From 2b3d66fe695d4bb9978626c861ea586706677a24 Mon Sep 17 00:00:00 2001 From: Fletcher Porter Date: Mon, 1 Nov 2021 23:51:11 -0700 Subject: [PATCH 001/291] Move the cmake submodule checkout command to a new line Presently, if you forget to initialize the git submodules before running cmake, there'll be a helpful message that reminds you to do so. However, on narrow terminals (e.g. 80 wide) there's a word wrap that includes a new line in the middle of the git command, precluding easy copy-paste. This moves the entire git command to its own line to avoid such tragedies. Before: ``` CMake Error at CMakeLists.txt:59 (message): Git submodule externals/inih/inih not found. Please run: git submodule update --init --recursive ``` After: ``` CMake Error at CMakeLists.txt:59 (message): Git submodule externals/inih/inih not found. Please run: git submodule update --init --recursive ``` --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb403205c..c9b40dd60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ function(check_submodules_present) string(REGEX REPLACE "path *= *" "" module ${module}) if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") message(FATAL_ERROR "Git submodule ${module} not found. " - "Please run: git submodule update --init --recursive") + "Please run: \ngit submodule update --init --recursive") endif() endforeach() endfunction() From 2e5866147eb24545e597d86f4e6621c2f2c63165 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Sat, 13 Nov 2021 22:14:30 -0500 Subject: [PATCH 002/291] Replace "Light" theme by "Default" This reflects the current behavior: Light = System default. If your system is set to dark theme, then Light = Dark, which is a bit confusing for the end user. In this PR, I propose to change "Light" with "Default". This way, the user has "Default" and "Default Colorful", which will apply the system theme. Now that the Flatpak respects the system theme, I think this makes much more sense. I also simplified the theme update. Before the code was branching between the default theme and the others, but I think we can have something simpler by forcing the default theme if no theme is defined in the settings, or if the selected theme doesn't exist. And if there's an error, tell the theme name in the error message. --- src/yuzu/main.cpp | 54 +++++++++++++++++++++-------------------- src/yuzu/uisettings.cpp | 4 +-- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4e5552d2a..cfda60997 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3381,36 +3381,38 @@ void GMainWindow::filterBarSetChecked(bool state) { } void GMainWindow::UpdateUITheme() { - const QString default_icons = QStringLiteral("default"); - const QString& current_theme = UISettings::values.theme; - const bool is_default_theme = current_theme == QString::fromUtf8(UISettings::themes[0].second); + const QString default_theme = QStringLiteral("default"); + QString current_theme = UISettings::values.theme; QStringList theme_paths(default_theme_paths); - if (is_default_theme || current_theme.isEmpty()) { - const QString theme_uri(QStringLiteral(":default/style.qss")); - QFile f(theme_uri); - if (f.open(QFile::ReadOnly | QFile::Text)) { - QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); - setStyleSheet(ts.readAll()); - } else { - qApp->setStyleSheet({}); - setStyleSheet({}); - } - QIcon::setThemeName(default_icons); - } else { - const QString theme_uri(QLatin1Char{':'} + current_theme + QStringLiteral("/style.qss")); - QFile f(theme_uri); - if (f.open(QFile::ReadOnly | QFile::Text)) { - QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); - setStyleSheet(ts.readAll()); - } else { - LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found"); - } - QIcon::setThemeName(current_theme); + if (current_theme.isEmpty()) { + current_theme = default_theme; } + if (current_theme != default_theme) { + QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)}; + QFile f(theme_uri); + if (!f.open(QFile::ReadOnly | QFile::Text)) { + LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", + UISettings::values.theme.toStdString()); + current_theme = default_theme; + } + } + + QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)}; + QFile f(theme_uri); + if (f.open(QFile::ReadOnly | QFile::Text)) { + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + setStyleSheet(ts.readAll()); + } else { + LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", + UISettings::values.theme.toStdString()); + qApp->setStyleSheet({}); + setStyleSheet({}); + } + + QIcon::setThemeName(current_theme); QIcon::setThemeSearchPaths(theme_paths); } diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 37499fc85..21683576c 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -7,8 +7,8 @@ namespace UISettings { const Themes themes{{ - {"Light", "default"}, - {"Light Colorful", "colorful"}, + {"Default", "default"}, + {"Default Colorful", "colorful"}, {"Dark", "qdarkstyle"}, {"Dark Colorful", "colorful_dark"}, {"Midnight Blue", "qdarkstyle_midnight_blue"}, From ffb79afd29afbb55b5d161286315f8bd9496776b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Tue, 16 Nov 2021 03:53:28 -0300 Subject: [PATCH 003/291] Replace keys error pop up Fight me. --- src/yuzu/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4e5552d2a..21981f749 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3194,9 +3194,9 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { if (!errors.isEmpty()) { QMessageBox::warning( this, tr("Derivation Components Missing"), - tr("Components are missing that may hinder key derivation from completing. " + tr("Encryption keys are missing. " "
Please follow the yuzu " - "quickstart guide to get all your keys and " + "quickstart guide to get all your keys, firmware and " "games.

(%1)") .arg(errors)); } From 894cc9d876a70947aecc7a1a3f9ef869e8088f42 Mon Sep 17 00:00:00 2001 From: Feng Chen Date: Wed, 17 Nov 2021 12:21:17 +0800 Subject: [PATCH 004/291] Fix image update/download error when width too small --- .../renderer_opengl/gl_texture_cache.cpp | 27 ++++++++++++------- .../renderer_opengl/gl_texture_cache.h | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 2f7d98d8b..5cfb6bb8a 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -317,13 +317,12 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) { } } -OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format) { +OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format, + GLsizei gl_num_levels) { const GLenum target = ImageTarget(info); const GLsizei width = info.size.width; const GLsizei height = info.size.height; const GLsizei depth = info.size.depth; - const int max_host_mip_levels = std::bit_width(info.size.width); - const GLsizei num_levels = std::min(info.resources.levels, max_host_mip_levels); const GLsizei num_layers = info.resources.layers; const GLsizei num_samples = info.num_samples; @@ -335,10 +334,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form } switch (target) { case GL_TEXTURE_1D_ARRAY: - glTextureStorage2D(handle, num_levels, gl_internal_format, width, num_layers); + glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, num_layers); break; case GL_TEXTURE_2D_ARRAY: - glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, num_layers); + glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, num_layers); break; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { // TODO: Where should 'fixedsamplelocations' come from? @@ -348,10 +347,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form break; } case GL_TEXTURE_RECTANGLE: - glTextureStorage2D(handle, num_levels, gl_internal_format, width, height); + glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, height); break; case GL_TEXTURE_3D: - glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, depth); + glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth); break; case GL_TEXTURE_BUFFER: UNREACHABLE(); @@ -686,7 +685,9 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, gl_format = tuple.format; gl_type = tuple.type; } - texture = MakeImage(info, gl_internal_format); + const int max_host_mip_levels = std::bit_width(info.size.width); + gl_num_levels = std::min(info.resources.levels, max_host_mip_levels); + texture = MakeImage(info, gl_internal_format, gl_num_levels); current_texture = texture.handle; if (runtime->device.HasDebuggingToolAttached()) { const std::string name = VideoCommon::Name(*this); @@ -714,6 +715,9 @@ void Image::UploadMemory(const ImageBufferMap& map, u32 current_image_height = std::numeric_limits::max(); for (const VideoCommon::BufferImageCopy& copy : copies) { + if (copy.image_subresource.base_level >= gl_num_levels) { + continue; + } if (current_row_length != copy.buffer_row_length) { current_row_length = copy.buffer_row_length; glPixelStorei(GL_UNPACK_ROW_LENGTH, current_row_length); @@ -743,6 +747,9 @@ void Image::DownloadMemory(ImageBufferMap& map, u32 current_image_height = std::numeric_limits::max(); for (const VideoCommon::BufferImageCopy& copy : copies) { + if (copy.image_subresource.base_level >= gl_num_levels) { + continue; + } if (current_row_length != copy.buffer_row_length) { current_row_length = copy.buffer_row_length; glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length); @@ -782,7 +789,7 @@ GLuint Image::StorageHandle() noexcept { } store_view.Create(); glTextureView(store_view.handle, ImageTarget(info), current_texture, GL_RGBA8, 0, - info.resources.levels, 0, info.resources.layers); + gl_num_levels, 0, info.resources.layers); return store_view.handle; default: return current_texture; @@ -946,7 +953,7 @@ void Image::Scale(bool up_scale) { auto dst_info = info; dst_info.size.width = scaled_width; dst_info.size.height = scaled_height; - upscaled_backup = MakeImage(dst_info, gl_internal_format); + upscaled_backup = MakeImage(dst_info, gl_internal_format, gl_num_levels); } const u32 src_width = up_scale ? original_width : scaled_width; const u32 src_height = up_scale ? original_height : scaled_height; diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 1bb762568..30037a6a2 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -219,6 +219,7 @@ private: GLenum gl_internal_format = GL_NONE; GLenum gl_format = GL_NONE; GLenum gl_type = GL_NONE; + GLsizei gl_num_levels{}; TextureCacheRuntime* runtime{}; GLuint current_texture{}; }; From 2348eb41f38a6e52e52d121adfc4c605763209a7 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 17 Nov 2021 15:04:38 -0500 Subject: [PATCH 005/291] video_core: Add S8_UINT stencil format --- src/video_core/gpu.h | 1 + src/video_core/surface.cpp | 7 +++++++ src/video_core/surface.h | 14 +++++++++++--- src/video_core/texture_cache/formatter.h | 2 ++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 05e5c94f3..c89a5d693 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -83,6 +83,7 @@ enum class DepthFormat : u32 { S8_UINT_Z24_UNORM = 0x14, D24X8_UNORM = 0x15, D24S8_UNORM = 0x16, + S8_UINT = 0x17, D24C8_UNORM = 0x18, D32_FLOAT_S8X24_UINT = 0x19, }; diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 58d262446..a36015c8c 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -82,6 +82,8 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) { return PixelFormat::D32_FLOAT; case Tegra::DepthFormat::D16_UNORM: return PixelFormat::D16_UNORM; + case Tegra::DepthFormat::S8_UINT: + return PixelFormat::S8_UINT; case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT: return PixelFormat::D32_FLOAT_S8_UINT; default: @@ -213,6 +215,11 @@ SurfaceType GetFormatType(PixelFormat pixel_format) { return SurfaceType::Depth; } + if (static_cast(pixel_format) < + static_cast(PixelFormat::MaxStencilFormat)) { + return SurfaceType::Stencil; + } + if (static_cast(pixel_format) < static_cast(PixelFormat::MaxDepthStencilFormat)) { return SurfaceType::DepthStencil; diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 2ce7c7d33..33e8d24ab 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -110,8 +110,12 @@ enum class PixelFormat { MaxDepthFormat, + // Stencil formats + S8_UINT = MaxDepthFormat, + MaxStencilFormat, + // DepthStencil formats - D24_UNORM_S8_UINT = MaxDepthFormat, + D24_UNORM_S8_UINT = MaxStencilFormat, S8_UINT_D24_UNORM, D32_FLOAT_S8_UINT, @@ -125,8 +129,9 @@ constexpr std::size_t MaxPixelFormat = static_cast(PixelFormat::Max enum class SurfaceType { ColorTexture = 0, Depth = 1, - DepthStencil = 2, - Invalid = 3, + Stencil = 2, + DepthStencil = 3, + Invalid = 4, }; enum class SurfaceTarget { @@ -229,6 +234,7 @@ constexpr std::array BLOCK_WIDTH_TABLE = {{ 1, // E5B9G9R9_FLOAT 1, // D32_FLOAT 1, // D16_UNORM + 1, // S8_UINT 1, // D24_UNORM_S8_UINT 1, // S8_UINT_D24_UNORM 1, // D32_FLOAT_S8_UINT @@ -328,6 +334,7 @@ constexpr std::array BLOCK_HEIGHT_TABLE = {{ 1, // E5B9G9R9_FLOAT 1, // D32_FLOAT 1, // D16_UNORM + 1, // S8_UINT 1, // D24_UNORM_S8_UINT 1, // S8_UINT_D24_UNORM 1, // D32_FLOAT_S8_UINT @@ -427,6 +434,7 @@ constexpr std::array BITS_PER_BLOCK_TABLE = {{ 32, // E5B9G9R9_FLOAT 32, // D32_FLOAT 16, // D16_UNORM + 8, // S8_UINT 32, // D24_UNORM_S8_UINT 32, // S8_UINT_D24_UNORM 64, // D32_FLOAT_S8_UINT diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h index c6cf0583f..b2c81057b 100644 --- a/src/video_core/texture_cache/formatter.h +++ b/src/video_core/texture_cache/formatter.h @@ -194,6 +194,8 @@ struct fmt::formatter : fmt::formatter Date: Wed, 17 Nov 2021 15:05:07 -0500 Subject: [PATCH 006/291] renderer_opengl: Implement S8_UINT stencil format --- .../renderer_opengl/gl_texture_cache.cpp | 28 +++++++++++++++---- .../renderer_opengl/gl_texture_cache.h | 4 +-- .../renderer_opengl/maxwell_to_gl.h | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 2f7d98d8b..d46ebd3ea 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -148,6 +148,8 @@ GLenum AttachmentType(PixelFormat format) { switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) { case SurfaceType::Depth: return GL_DEPTH_ATTACHMENT; + case SurfaceType::Stencil: + return GL_STENCIL_ATTACHMENT; case SurfaceType::DepthStencil: return GL_DEPTH_STENCIL_ATTACHMENT; default: @@ -897,6 +899,8 @@ void Image::Scale(bool up_scale) { return GL_COLOR_ATTACHMENT0; case SurfaceType::Depth: return GL_DEPTH_ATTACHMENT; + case SurfaceType::Stencil: + return GL_STENCIL_ATTACHMENT; case SurfaceType::DepthStencil: return GL_DEPTH_STENCIL_ATTACHMENT; default: @@ -910,8 +914,10 @@ void Image::Scale(bool up_scale) { return GL_COLOR_BUFFER_BIT; case SurfaceType::Depth: return GL_DEPTH_BUFFER_BIT; + case SurfaceType::Stencil: + return GL_STENCIL_BUFFER_BIT; case SurfaceType::DepthStencil: - return GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; + return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; default: UNREACHABLE(); return GL_COLOR_BUFFER_BIT; @@ -923,8 +929,10 @@ void Image::Scale(bool up_scale) { return 0; case SurfaceType::Depth: return 1; - case SurfaceType::DepthStencil: + case SurfaceType::Stencil: return 2; + case SurfaceType::DepthStencil: + return 3; default: UNREACHABLE(); return 0; @@ -1254,10 +1262,20 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::spanformat) == SurfaceType::DepthStencil) { - buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - } else { + switch (GetFormatType(image_view->format)) { + case SurfaceType::Depth: buffer_bits |= GL_DEPTH_BUFFER_BIT; + break; + case SurfaceType::Stencil: + buffer_bits |= GL_STENCIL_BUFFER_BIT; + break; + case SurfaceType::DepthStencil: + buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + break; + default: + UNREACHABLE(); + buffer_bits |= GL_DEPTH_BUFFER_BIT; + break; } const GLenum attachment = AttachmentType(image_view->format); AttachTexture(handle, attachment, image_view); diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 1bb762568..16224e6b3 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -162,8 +162,8 @@ private: std::array null_image_views{}; - std::array rescale_draw_fbos; - std::array rescale_read_fbos; + std::array rescale_draw_fbos; + std::array rescale_read_fbos; const Settings::ResolutionScalingInfo& resolution; }; diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 39158aa3e..daba42ed9 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -108,6 +108,7 @@ constexpr std::array FORMAT_TAB {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM + {GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, From d8a783a368cf2df4a2c7143cabd33cc134d6d79b Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Wed, 17 Nov 2021 15:00:55 -0800 Subject: [PATCH 007/291] Fix crash on exit due to static scoped dummy threads --- src/core/hle/kernel/kernel.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e42a6d36f..45e86a677 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -300,15 +300,16 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { auto make_thread = [this]() { - std::unique_ptr thread = std::make_unique(system.Kernel()); + std::lock_guard lk(dummy_thread_lock); + auto& thread = dummy_threads.emplace_back(std::make_unique(system.Kernel())); KAutoObject::Create(thread.get()); ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); - return thread; + return thread.get(); }; - thread_local auto thread = make_thread(); - return thread.get(); + thread_local KThread* saved_thread = make_thread(); + return saved_thread; } /// Registers a CPU core thread by allocating a host thread ID for it @@ -695,6 +696,12 @@ struct KernelCore::Impl { return port; } + std::mutex server_ports_lock; + std::mutex server_sessions_lock; + std::mutex registered_objects_lock; + std::mutex registered_in_use_objects_lock; + std::mutex dummy_thread_lock; + std::atomic next_object_id{0}; std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin}; std::atomic next_user_process_id{KProcess::ProcessIDMin}; @@ -725,10 +732,6 @@ struct KernelCore::Impl { std::unordered_set server_sessions; std::unordered_set registered_objects; std::unordered_set registered_in_use_objects; - std::mutex server_ports_lock; - std::mutex server_sessions_lock; - std::mutex registered_objects_lock; - std::mutex registered_in_use_objects_lock; std::unique_ptr exclusive_monitor; std::vector cores; @@ -753,6 +756,9 @@ struct KernelCore::Impl { std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; + // Specifically tracked to be automatically destroyed with kernel + std::vector> dummy_threads; + bool is_multicore{}; bool is_phantom_mode_for_singlecore{}; u32 single_core_thread_id{}; From dc61b7045b7ffc3cfe46f0b71f84d5fe709de6c9 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 17 Nov 2021 15:08:08 -0500 Subject: [PATCH 008/291] renderer_vulkan: Implement S8_UINT stencil format It should be noted that on Windows, only nvidia gpus support this format natively as of this commit. --- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 3 +++ src/video_core/renderer_vulkan/vk_texture_cache.cpp | 5 +++++ src/video_core/vulkan_common/vulkan_device.cpp | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 68a23b602..31adada56 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -208,6 +208,9 @@ struct FormatTuple { {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT {VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM + // Stencil formats + {VK_FORMAT_S8_UINT, Attachable}, // S8_UINT + // DepthStencil formats {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8_UINT_D24_UNORM (emulated) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 407fd2a15..9bc846b94 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -102,6 +102,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; break; case VideoCore::Surface::SurfaceType::Depth: + case VideoCore::Surface::SurfaceType::Stencil: case VideoCore::Surface::SurfaceType::DepthStencil: usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; break; @@ -173,6 +174,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { return VK_IMAGE_ASPECT_COLOR_BIT; case VideoCore::Surface::SurfaceType::Depth: return VK_IMAGE_ASPECT_DEPTH_BIT; + case VideoCore::Surface::SurfaceType::Stencil: + return VK_IMAGE_ASPECT_STENCIL_BIT; case VideoCore::Surface::SurfaceType::DepthStencil: return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; default: @@ -195,6 +198,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { case PixelFormat::D16_UNORM: case PixelFormat::D32_FLOAT: return VK_IMAGE_ASPECT_DEPTH_BIT; + case PixelFormat::S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; default: return VK_IMAGE_ASPECT_COLOR_BIT; } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 95106f88f..70c52aaac 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -21,6 +21,13 @@ namespace Vulkan { namespace { namespace Alternatives { +constexpr std::array STENCIL8_UINT{ + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_UNDEFINED, +}; + constexpr std::array DEPTH24_UNORM_STENCIL8_UINT{ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, @@ -74,6 +81,8 @@ void SetNext(void**& next, T& data) { constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { switch (format) { + case VK_FORMAT_S8_UINT: + return Alternatives::STENCIL8_UINT.data(); case VK_FORMAT_D24_UNORM_S8_UINT: return Alternatives::DEPTH24_UNORM_STENCIL8_UINT.data(); case VK_FORMAT_D16_UNORM_S8_UINT: @@ -145,6 +154,7 @@ std::unordered_map GetFormatProperties(vk::Physica VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM, + VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, From 2ec7fcecb7d1f0bc8f943a3f7cb4d2e215bc4e76 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 03:17:02 +0100 Subject: [PATCH 009/291] Vulkan: implement D24S8 <-> RGBA8 convertions. --- src/video_core/host_shaders/CMakeLists.txt | 2 + .../host_shaders/convert_abgr8_to_d24s8.frag | 17 ++++ .../host_shaders/convert_d24s8_to_abgr8.frag | 21 ++++ src/video_core/renderer_vulkan/blit_image.cpp | 98 +++++++++++++++++++ src/video_core/renderer_vulkan/blit_image.h | 16 +++ .../renderer_vulkan/vk_texture_cache.cpp | 12 +++ 6 files changed, 166 insertions(+) create mode 100644 src/video_core/host_shaders/convert_abgr8_to_d24s8.frag create mode 100644 src/video_core/host_shaders/convert_d24s8_to_abgr8.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index d779a967a..fd3e41434 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -10,6 +10,8 @@ set(SHADER_FILES astc_decoder.comp block_linear_unswizzle_2d.comp block_linear_unswizzle_3d.comp + convert_abgr8_to_d24s8.frag + convert_d24s8_to_abgr8.frag convert_depth_to_float.frag convert_float_to_depth.frag full_screen_triangle.vert diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag new file mode 100644 index 000000000..f7657e50a --- /dev/null +++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag @@ -0,0 +1,17 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 +// #extension GL_ARB_shader_stencil_export : require + +layout(binding = 0) uniform sampler2D color_texture; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f)); + uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b; + + gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f); + // gl_FragStencilRefARB = int(color.a); +} diff --git a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag new file mode 100644 index 000000000..ff3bf8209 --- /dev/null +++ b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag @@ -0,0 +1,21 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 + +layout(binding = 0) uniform sampler2D depth_tex; +layout(binding = 1) uniform isampler2D stencil_tex; + +layout(location = 0) out vec4 color; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); + uint stencil = uint(textureLod(stencil_tex, coord, 0).r); + + color.r = float(depth >> 16) / (exp2(8) - 1.0); + color.g = float((depth >> 8) & 0x00FF) / (exp2(8) - 1.0); + color.b = float(depth & 0x00FF) / (exp2(8) - 1.0); + color.a = float(stencil) / (exp2(8) - 1.0); +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index b3884a4f5..01535d0c0 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -4,6 +4,8 @@ #include +#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" +#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" @@ -354,6 +356,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), + convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), + convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)), nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) { if (device.IsExtShaderStencilExportSupported()) { @@ -448,6 +452,23 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); } +void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, + const ImageView& src_image_view, u32 up_scale, + u32 down_shift) { + ConvertPipelineEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), + convert_abgr8_to_d24s8_frag, true); + Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, + down_shift); +} + +void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, u32 down_shift) { + ConvertPipelineEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_abgr8_frag, false); + ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale, + down_shift); +} + void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift) { const VkPipelineLayout layout = *one_texture_pipeline_layout; @@ -495,6 +516,54 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb scheduler.InvalidateState(); } +void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, u32 down_shift) { + const VkPipelineLayout layout = *one_texture_pipeline_layout; + const VkImageView src_depth_view = src_image_view.DepthView(); + const VkImageView src_stencil_view = src_image_view.StencilView(); + const VkSampler sampler = *nearest_sampler; + const VkExtent2D extent{ + .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), + .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), + }; + scheduler.RequestRenderpass(dst_framebuffer); + scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale, + down_shift, this](vk::CommandBuffer cmdbuf) { + const VkOffset2D offset{ + .x = 0, + .y = 0, + }; + const VkViewport viewport{ + .x = 0.0f, + .y = 0.0f, + .width = static_cast(extent.width), + .height = static_cast(extent.height), + .minDepth = 0.0f, + .maxDepth = 0.0f, + }; + const VkRect2D scissor{ + .offset = offset, + .extent = extent, + }; + const PushConstants push_constants{ + .tex_scale = {viewport.width, viewport.height}, + .tex_offset = {0.0f, 0.0f}, + }; + const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); + UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, + src_stencil_view); + // TODO: Barriers + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, + nullptr); + cmdbuf.SetViewport(0, viewport); + cmdbuf.SetScissor(0, scissor); + cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); + cmdbuf.Draw(3, 1, 0, 0); + }); + scheduler.InvalidateState(); +} + VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) { const auto it = std::ranges::find(blit_color_keys, key); if (it != blit_color_keys.end()) { @@ -636,4 +705,33 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend }); } +void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture) { + if (pipeline) { + return; + } + const std::array stages = MakeStages(*full_screen_vert, *module); + pipeline = device.GetLogical().CreateGraphicsPipeline({ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast(stages.size()), + .pStages = stages.data(), + .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pTessellationState = nullptr, + .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, + .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, + .renderPass = renderpass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = 0, + }); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index d77f76678..f754a7294 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -56,10 +56,19 @@ public: void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, + u32 up_scale, u32 down_shift); + + void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, + u32 up_scale, u32 down_shift); + private: void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, u32 down_shift); + [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); @@ -68,6 +77,9 @@ private: void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); + void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture); + const Device& device; VKScheduler& scheduler; StateTracker& state_tracker; @@ -83,6 +95,8 @@ private: vk::ShaderModule blit_depth_stencil_frag; vk::ShaderModule convert_depth_to_float_frag; vk::ShaderModule convert_float_to_depth_frag; + vk::ShaderModule convert_abgr8_to_d24s8_frag; + vk::ShaderModule convert_d24s8_to_abgr8_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; @@ -94,6 +108,8 @@ private: vk::Pipeline convert_r32_to_d32_pipeline; vk::Pipeline convert_d16_to_r16_pipeline; vk::Pipeline convert_r16_to_d16_pipeline; + vk::Pipeline convert_abgr8_to_d24s8_pipeline; + vk::Pipeline convert_d24s8_to_abgr8_pipeline; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 407fd2a15..6dfd45f31 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -881,6 +881,12 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift); } break; + case PixelFormat::A8B8G8R8_UNORM: + case PixelFormat::B8G8R8A8_UNORM: + if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { + return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift); + } + break; case PixelFormat::R32_FLOAT: if (src_view.format == PixelFormat::D32_FLOAT) { return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); @@ -891,6 +897,12 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift); } break; + case PixelFormat::S8_UINT_D24_UNORM: + if (src_view.format == PixelFormat::A8B8G8R8_UNORM || + src_view.format == PixelFormat::B8G8R8A8_UNORM) { + return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); + } + break; case PixelFormat::D32_FLOAT: if (src_view.format == PixelFormat::R32_FLOAT) { return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift); From b130f648d7c629411c487722f864c6bafcd2562c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 03:17:54 +0100 Subject: [PATCH 010/291] TextureCache: Fix regression caused by ART and improve blit detection algorithm to be smarter. --- src/video_core/texture_cache/texture_cache.h | 9 +++---- src/video_core/texture_cache/util.cpp | 28 +++++++++++++++++--- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 241f71a91..5ade3ce55 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -475,6 +475,7 @@ void TextureCache

::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const BlitImages images = GetBlitImages(dst, src); const ImageId dst_id = images.dst_id; const ImageId src_id = images.src_id; + PrepareImage(src_id, false, false); PrepareImage(dst_id, true, false); @@ -1094,12 +1095,8 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { continue; } - if (!dst_id) { - dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); - } - if (!src_id) { - src_id = InsertImage(src_info, src_addr, RelaxedOptions{}); - } + src_id = FindOrInsertImage(src_info, src_addr); + dst_id = FindOrInsertImage(dst_info, dst_addr); } while (has_deleted_images); return BlitImages{ .dst_id = dst_id, diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index ddc9fb13a..8f9eb387c 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1151,17 +1151,37 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, const ImageBase* src) { - if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { + if (src) { src_info.format = src->info.format; + src_info.num_samples = src->info.num_samples; + src_info.size = src->info.size; } - if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { + if (dst) { dst_info.format = dst->info.format; + dst_info.num_samples = dst->info.num_samples; + dst_info.size = dst->info.size; } if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { - dst_info.format = src->info.format; + if (dst) { + src_info.format = dst_info.format; + } else { + dst_info.format = src->info.format; + } } if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { - src_info.format = dst->info.format; + if (src) { + if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) { + dst_info.format = src->info.format; + } + } else { + src_info.format = dst->info.format; + } + } + if (src_info.num_samples > 1) { + dst_info.format = src_info.format; + } + if (dst_info.num_samples > 1) { + src_info.format = dst_info.format; } } From c76163b611350e2261a6a64f1853626af6f57ada Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 18 Nov 2021 23:04:06 -0500 Subject: [PATCH 011/291] main: Shorten AMD FSR status bar text AMD'S FIDELITYFX SR -> FSR --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 6071a222f..689746028 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3106,7 +3106,7 @@ void GMainWindow::UpdateFilterText() { filter_status_button->setText(tr("SCALEFORCE")); break; case Settings::ScalingFilter::Fsr: - filter_status_button->setText(tr("AMD'S FIDELITYFX SR")); + filter_status_button->setText(tr("FSR")); break; default: filter_status_button->setText(tr("BILINEAR")); From a237fb5f759f15e1e1a8f920118e2189ad6d82e0 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 18 Nov 2021 23:09:28 -0500 Subject: [PATCH 012/291] configure_graphics_ui: AMD's -> AMD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AMD officially markets FSR as AMD FidelityFX™️ Super Resolution --- src/yuzu/configuration/configure_graphics.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 660b68c1c..9241678e4 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -429,7 +429,7 @@ - AMD's FidelityFX™️ Super Resolution [Vulkan Only] + AMD FidelityFX™️ Super Resolution [Vulkan Only] From bc5ed1aa1b41b9960657dddee658c3ce344cb501 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 18 Nov 2021 23:22:32 -0500 Subject: [PATCH 013/291] main: Fix default AA name By default, no AA is applied, not FXAA --- src/yuzu/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 689746028..44800e165 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3117,15 +3117,15 @@ void GMainWindow::UpdateFilterText() { void GMainWindow::UpdateAAText() { const auto aa_mode = Settings::values.anti_aliasing.GetValue(); switch (aa_mode) { - case Settings::AntiAliasing::Fxaa: - aa_status_button->setText(tr("FXAA")); - break; case Settings::AntiAliasing::None: aa_status_button->setText(tr("NO AA")); break; - default: + case Settings::AntiAliasing::Fxaa: aa_status_button->setText(tr("FXAA")); break; + default: + aa_status_button->setText(tr("NO AA")); + break; } } From 0ff228405faae92a39167b9aec072e14744eae35 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 05:46:57 +0100 Subject: [PATCH 014/291] TextureCache: force same image format when resolving an image. --- src/video_core/texture_cache/texture_cache.h | 10 ++++++++-- src/video_core/texture_cache/types.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 5ade3ce55..06257f064 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -759,7 +759,8 @@ ImageId TextureCache

::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, return ImageId{}; } } - const bool broken_views = runtime.HasBrokenTextureViewFormats(); + const bool broken_views = + runtime.HasBrokenTextureViewFormats() || True(options & RelaxedOptions::ForceBrokenViews); const bool native_bgr = runtime.HasNativeBgr(); ImageId image_id; const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { @@ -1096,7 +1097,12 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( continue; } src_id = FindOrInsertImage(src_info, src_addr); - dst_id = FindOrInsertImage(dst_info, dst_addr); + RelaxedOptions dst_options{}; + if (src_info.num_samples > 1) { + // it's a resolve, we must enforce the same format. + dst_options = RelaxedOptions::ForceBrokenViews; + } + dst_id = FindOrInsertImage(dst_info, dst_addr, dst_options); } while (has_deleted_images); return BlitImages{ .dst_id = dst_id, diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index 5c274abdf..5ac27b3a7 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h @@ -54,6 +54,7 @@ enum class RelaxedOptions : u32 { Size = 1 << 0, Format = 1 << 1, Samples = 1 << 2, + ForceBrokenViews = 1 << 3, }; DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions) From b805c7bf058c6da04620cf75880509bdf6d5986c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 06:27:44 +0100 Subject: [PATCH 015/291] TextureCache: Implement additional D24S8 convertions. --- src/video_core/host_shaders/CMakeLists.txt | 2 ++ .../convert_d24s8_to_b10g11r11.frag | 21 ++++++++++++++++++ .../host_shaders/convert_d24s8_to_r16g16.frag | 21 ++++++++++++++++++ src/video_core/renderer_vulkan/blit_image.cpp | 22 +++++++++++++++++++ src/video_core/renderer_vulkan/blit_image.h | 10 +++++++++ .../renderer_vulkan/vk_texture_cache.cpp | 10 +++++++++ 6 files changed, 86 insertions(+) create mode 100644 src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag create mode 100644 src/video_core/host_shaders/convert_d24s8_to_r16g16.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index fd3e41434..87042195a 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -12,6 +12,8 @@ set(SHADER_FILES block_linear_unswizzle_3d.comp convert_abgr8_to_d24s8.frag convert_d24s8_to_abgr8.frag + convert_d24s8_to_b10g11r11.frag + convert_d24s8_to_r16g16.frag convert_depth_to_float.frag convert_float_to_depth.frag full_screen_triangle.vert diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag new file mode 100644 index 000000000..c743d3a13 --- /dev/null +++ b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag @@ -0,0 +1,21 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 + +layout(binding = 0) uniform sampler2D depth_tex; +layout(binding = 1) uniform isampler2D stencil_tex; + +layout(location = 0) out vec4 color; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); + uint stencil = uint(textureLod(stencil_tex, coord, 0).r); + + color.b = float(depth >> 22) / (exp2(10) - 1.0); + color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0); + color.r = float(depth & 0x00FF) / (exp2(11) - 1.0); + color.a = 1.0f; +} diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag new file mode 100644 index 000000000..2a9443d3d --- /dev/null +++ b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag @@ -0,0 +1,21 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 + +layout(binding = 0) uniform sampler2D depth_tex; +layout(binding = 1) uniform isampler2D stencil_tex; + +layout(location = 0) out vec4 color; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); + uint stencil = uint(textureLod(stencil_tex, coord, 0).r); + + color.r = float(depth >> 16) / (exp2(16) - 1.0); + color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0); + color.b = 0.0f; + color.a = 1.0f; +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 01535d0c0..12b28aadd 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -6,6 +6,8 @@ #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" +#include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h" +#include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" @@ -358,6 +360,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), + convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)), + convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)), nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) { if (device.IsExtShaderStencilExportSupported()) { @@ -469,6 +473,24 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, down_shift); } +void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, + u32 down_shift) { + ConvertPipelineEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_b10g11r11_frag, false); + ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view, + up_scale, down_shift); +} + +void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, + u32 down_shift) { + ConvertPipelineEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_r16g16_frag, false); + ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view, + up_scale, down_shift); +} + void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift) { const VkPipelineLayout layout = *one_texture_pipeline_layout; diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index f754a7294..10d24c4b7 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -62,6 +62,12 @@ public: void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view, + u32 up_scale, u32 down_shift); + + void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view, + u32 up_scale, u32 down_shift); + private: void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); @@ -97,6 +103,8 @@ private: vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag; + vk::ShaderModule convert_d24s8_to_b10g11r11_frag; + vk::ShaderModule convert_d24s8_to_r16g16_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; @@ -110,6 +118,8 @@ private: vk::Pipeline convert_r16_to_d16_pipeline; vk::Pipeline convert_abgr8_to_d24s8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline; + vk::Pipeline convert_d24s8_to_b10g11r11_pipeline; + vk::Pipeline convert_d24s8_to_r16g16_pipeline; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 6dfd45f31..fd6064271 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -887,6 +887,16 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift); } break; + case PixelFormat::B10G11R11_FLOAT: + if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { + return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift); + } + break; + case PixelFormat::R16G16_UNORM: + if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { + return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift); + } + break; case PixelFormat::R32_FLOAT: if (src_view.format == PixelFormat::D32_FLOAT) { return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); From 6f896d1fae3d244f83450a485d15e7cebe79abaa Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 22:23:48 +0100 Subject: [PATCH 016/291] TextureCache: Further fixes on resolve algorithm. --- src/video_core/texture_cache/texture_cache.h | 8 +++---- src/video_core/texture_cache/util.cpp | 25 ++++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 06257f064..4188f93c5 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1096,13 +1096,13 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { continue; } - src_id = FindOrInsertImage(src_info, src_addr); - RelaxedOptions dst_options{}; + RelaxedOptions find_options{}; if (src_info.num_samples > 1) { // it's a resolve, we must enforce the same format. - dst_options = RelaxedOptions::ForceBrokenViews; + find_options = RelaxedOptions::ForceBrokenViews; } - dst_id = FindOrInsertImage(dst_info, dst_addr, dst_options); + src_id = FindOrInsertImage(src_info, src_addr, find_options); + dst_id = FindOrInsertImage(dst_info, dst_addr, find_options); } while (has_deleted_images); return BlitImages{ .dst_id = dst_id, diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 8f9eb387c..e4d82631e 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1151,19 +1151,25 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, const ImageBase* src) { + bool is_resolve = false; + const auto original_src_format = src_info.format; + const auto original_dst_format = dst_info.format; if (src) { - src_info.format = src->info.format; + if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) { + src_info.format = src->info.format; + } + is_resolve = src->info.num_samples > 1; src_info.num_samples = src->info.num_samples; src_info.size = src->info.size; } - if (dst) { + if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { dst_info.format = dst->info.format; - dst_info.num_samples = dst->info.num_samples; - dst_info.size = dst->info.size; } if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { if (dst) { - src_info.format = dst_info.format; + if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) { + src_info.format = original_src_format; + } } else { dst_info.format = src->info.format; } @@ -1171,18 +1177,13 @@ void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { if (src) { if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) { - dst_info.format = src->info.format; + dst_info.format = original_dst_format; } } else { src_info.format = dst->info.format; } } - if (src_info.num_samples > 1) { - dst_info.format = src_info.format; - } - if (dst_info.num_samples > 1) { - src_info.format = dst_info.format; - } + ASSERT(!is_resolve || dst_info.format == src_info.format); } u32 MapSizeBytes(const ImageBase& image) { From 1d5e6a51d7f66cf089d541a009c84c373fd5c6ab Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Nov 2021 23:22:44 +0100 Subject: [PATCH 017/291] TextureCache: Add B10G11R11 to D24S8 converter. --- src/video_core/host_shaders/CMakeLists.txt | 1 + .../convert_b10g11r11_to_d24s8.frag | 19 ++++++ src/video_core/renderer_vulkan/blit_image.cpp | 62 +++++++++++++++---- src/video_core/renderer_vulkan/blit_image.h | 12 +++- .../renderer_vulkan/vk_texture_cache.cpp | 3 + 5 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 87042195a..a2e046f12 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -11,6 +11,7 @@ set(SHADER_FILES block_linear_unswizzle_2d.comp block_linear_unswizzle_3d.comp convert_abgr8_to_d24s8.frag + convert_b10g11r11_to_d24s8.frag convert_d24s8_to_abgr8.frag convert_d24s8_to_b10g11r11.frag convert_d24s8_to_r16g16.frag diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag new file mode 100644 index 000000000..b7358c15c --- /dev/null +++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag @@ -0,0 +1,19 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 +// #extension GL_ARB_shader_stencil_export : require + +layout(binding = 0) uniform sampler2D color_texture; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + vec4 color = texelFetch(color_texture, coord, 0).rgba; + uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22) + | (uint(color.g * (exp2(11) - 1.0f)) << 11) + | (uint(color.r * (exp2(11) - 1.0f))); + + gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); + // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 12b28aadd..e70459de5 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -5,6 +5,7 @@ #include #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" +#include "video_core/host_shaders/convert_b10g11r11_to_d24s8_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h" @@ -359,6 +360,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), + convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)), convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)), @@ -459,16 +461,25 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift) { - ConvertPipelineEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), - convert_abgr8_to_d24s8_frag, true); + ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), + convert_abgr8_to_d24s8_frag, true); Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); } +void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, + const ImageView& src_image_view, u32 up_scale, + u32 down_shift) { + ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(), + convert_b10g11r11_to_d24s8_frag, true); + Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, + down_shift); +} + void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { - ConvertPipelineEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), - convert_d24s8_to_abgr8_frag, false); + ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_abgr8_frag, false); ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); } @@ -476,8 +487,8 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { - ConvertPipelineEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(), - convert_d24s8_to_b10g11r11_frag, false); + ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_b10g11r11_frag, false); ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); } @@ -485,8 +496,8 @@ void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { - ConvertPipelineEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(), - convert_d24s8_to_r16g16_frag, false); + ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(), + convert_d24s8_to_r16g16_frag, false); ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); } @@ -540,7 +551,7 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { - const VkPipelineLayout layout = *one_texture_pipeline_layout; + const VkPipelineLayout layout = *two_textures_pipeline_layout; const VkImageView src_depth_view = src_image_view.DepthView(); const VkImageView src_stencil_view = src_image_view.StencilView(); const VkSampler sampler = *nearest_sampler; @@ -727,8 +738,37 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend }); } -void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, - vk::ShaderModule& module, bool single_texture) { +void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture) { + if (pipeline) { + return; + } + const std::array stages = MakeStages(*full_screen_vert, *module); + pipeline = device.GetLogical().CreateGraphicsPipeline({ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast(stages.size()), + .pStages = stages.data(), + .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pTessellationState = nullptr, + .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pDepthStencilState = nullptr, + .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, + .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, + .renderPass = renderpass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = 0, + }); +} + +void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture) { if (pipeline) { return; } diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 10d24c4b7..607964b5e 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -59,6 +59,9 @@ public: void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, + const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); @@ -83,8 +86,11 @@ private: void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); - void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, - vk::ShaderModule& module, bool single_texture); + void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture); + + void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture); const Device& device; VKScheduler& scheduler; @@ -102,6 +108,7 @@ private: vk::ShaderModule convert_depth_to_float_frag; vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag; + vk::ShaderModule convert_b10g11r11_to_d24s8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag; vk::ShaderModule convert_d24s8_to_b10g11r11_frag; vk::ShaderModule convert_d24s8_to_r16g16_frag; @@ -117,6 +124,7 @@ private: vk::Pipeline convert_d16_to_r16_pipeline; vk::Pipeline convert_r16_to_d16_pipeline; vk::Pipeline convert_abgr8_to_d24s8_pipeline; + vk::Pipeline convert_b10g11r11_to_d24s8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline; vk::Pipeline convert_d24s8_to_b10g11r11_pipeline; vk::Pipeline convert_d24s8_to_r16g16_pipeline; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index fd6064271..28a659c0e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -912,6 +912,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im src_view.format == PixelFormat::B8G8R8A8_UNORM) { return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); } + if (src_view.format == PixelFormat::B10G11R11_FLOAT) { + return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift); + } break; case PixelFormat::D32_FLOAT: if (src_view.format == PixelFormat::R32_FLOAT) { From e02cff2f69f9a90777f87f85f290f83fc04c16ec Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 20 Nov 2021 00:02:12 +0100 Subject: [PATCH 018/291] TextureCache: Add R16G16 to D24S8 converter. --- src/video_core/host_shaders/CMakeLists.txt | 1 + .../host_shaders/convert_r16g16_to_d24s8.frag | 18 ++++++++++++++++++ src/video_core/renderer_vulkan/blit_image.cpp | 11 +++++++++++ src/video_core/renderer_vulkan/blit_image.h | 5 +++++ .../renderer_vulkan/vk_texture_cache.cpp | 3 +++ 5 files changed, 38 insertions(+) create mode 100644 src/video_core/host_shaders/convert_r16g16_to_d24s8.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index a2e046f12..1c91999d7 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -17,6 +17,7 @@ set(SHADER_FILES convert_d24s8_to_r16g16.frag convert_depth_to_float.frag convert_float_to_depth.frag + convert_r16g16_to_d24s8.frag full_screen_triangle.vert fxaa.frag fxaa.vert diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag new file mode 100644 index 000000000..7b1b914f6 --- /dev/null +++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag @@ -0,0 +1,18 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 +// #extension GL_ARB_shader_stencil_export : require + +layout(binding = 0) uniform sampler2D color_texture; + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + vec4 color = texelFetch(color_texture, coord, 0).rgba; + uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16) + | (uint(color.g * (exp2(16) - 1.0f)) << 16); + + gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); + // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); +} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index e70459de5..28b631f73 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -11,6 +11,7 @@ #include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" +#include "video_core/host_shaders/convert_r16g16_to_d24s8_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" @@ -361,6 +362,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)), + convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)), convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)), @@ -476,6 +478,15 @@ void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer down_shift); } +void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, + const ImageView& src_image_view, u32 up_scale, + u32 down_shift) { + ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(), + convert_r16g16_to_d24s8_frag, true); + Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, + down_shift); +} + void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 607964b5e..cec095341 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -62,6 +62,9 @@ public: void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, + u32 up_scale, u32 down_shift); + void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); @@ -109,6 +112,7 @@ private: vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag; vk::ShaderModule convert_b10g11r11_to_d24s8_frag; + vk::ShaderModule convert_r16g16_to_d24s8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag; vk::ShaderModule convert_d24s8_to_b10g11r11_frag; vk::ShaderModule convert_d24s8_to_r16g16_frag; @@ -125,6 +129,7 @@ private: vk::Pipeline convert_r16_to_d16_pipeline; vk::Pipeline convert_abgr8_to_d24s8_pipeline; vk::Pipeline convert_b10g11r11_to_d24s8_pipeline; + vk::Pipeline convert_r16g16_to_d24s8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline; vk::Pipeline convert_d24s8_to_b10g11r11_pipeline; vk::Pipeline convert_d24s8_to_r16g16_pipeline; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 28a659c0e..af1a11059 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -915,6 +915,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im if (src_view.format == PixelFormat::B10G11R11_FLOAT) { return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift); } + if (src_view.format == PixelFormat::R16G16_UNORM) { + return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift); + } break; case PixelFormat::D32_FLOAT: if (src_view.format == PixelFormat::R32_FLOAT) { From 0857f82913d0bcf2de4721233f74cd40ecddcdae Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 20 Nov 2021 06:15:29 +0100 Subject: [PATCH 019/291] TextureCache: Implement buffer copies on Vulkan. --- .../renderer_opengl/gl_texture_cache.cpp | 4 +- .../renderer_opengl/gl_texture_cache.h | 7 +- .../renderer_vulkan/vk_texture_cache.cpp | 174 ++++++++++++++++++ .../renderer_vulkan/vk_texture_cache.h | 11 +- src/video_core/texture_cache/texture_cache.h | 4 +- .../texture_cache/texture_cache_base.h | 2 - 6 files changed, 193 insertions(+), 9 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 6956535e5..e70bbec81 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -526,8 +526,8 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image, } } -void TextureCacheRuntime::ConvertImage(Image& dst, Image& src, - std::span copies) { +void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, + std::span copies) { LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format); format_conversion_pass.ConvertImage(dst, src, copies); } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 578f8d523..ad5157d66 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -84,9 +84,13 @@ public: u64 GetDeviceLocalMemory() const; + bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) { + return true; + } + void CopyImage(Image& dst, Image& src, std::span copies); - void ConvertImage(Image& dst, Image& src, std::span copies); + void ReinterpretImage(Image& dst, Image& src, std::span copies); void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) { UNIMPLEMENTED(); @@ -338,7 +342,6 @@ struct TextureCacheParams { static constexpr bool FRAMEBUFFER_BLITS = true; static constexpr bool HAS_EMULATED_COPIES = true; static constexpr bool HAS_DEVICE_MEMORY_INFO = true; - static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = true; using Runtime = OpenGL::TextureCacheRuntime; using Image = OpenGL::Image; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index af1a11059..02215cfc2 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -308,6 +308,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { }; } +[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src, + VkImageAspectFlags aspect_mask) noexcept { + return VkBufferImageCopy{ + .bufferOffset = 0, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = MakeImageSubresourceLayers( + is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask), + .imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset), + .imageExtent = MakeExtent3D(copy.extent), + }; +} + [[maybe_unused]] [[nodiscard]] std::vector TransformBufferCopies( std::span copies, size_t buffer_offset) { std::vector result(copies.size()); @@ -754,6 +767,167 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) { return staging_buffer_pool.Request(size, MemoryUsage::Download); } +bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { + if (VideoCore::Surface::GetFormatType(dst.info.format) == + VideoCore::Surface::SurfaceType::DepthStencil) { + return !device.IsExtShaderStencilExportSupported(); + } + return false; +} + +[[nodiscard]] size_t NextPow2(size_t value) { + return static_cast(1ULL << ((8U * sizeof(size_t)) - std::countl_zero(value - 1U))); +} + +VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { + const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); + if (buffer_commits[level]) { + return *buffers[level]; + } + const auto new_size = NextPow2(needed_size); + VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + buffers[level] = device.GetLogical().CreateBuffer({ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = new_size, + .usage = flags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }); + buffer_commits[level] = std::make_unique( + memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); + return *buffers[level]; +} + +void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, + std::span copies) { + std::vector vk_in_copies(copies.size()); + std::vector vk_out_copies(copies.size()); + const VkImageAspectFlags src_aspect_mask = src.AspectMask(); + const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); + + std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) { + return MakeBufferImageCopy(copy, true, src_aspect_mask); + }); + std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) { + return MakeBufferImageCopy(copy, false, dst_aspect_mask); + }); + const u32 img_bpp = BytesPerBlock(src.info.format); + size_t total_size = 0; + for (const auto& copy : copies) { + total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp; + } + const VkBuffer copy_buffer = GetTemporaryBuffer(total_size); + const VkImage dst_image = dst.Handle(); + const VkImage src_image = src.Handle(); + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask, + vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) { + RangedBarrierRange dst_range; + RangedBarrierRange src_range; + for (const VkBufferImageCopy& copy : vk_in_copies) { + src_range.AddLayers(copy.imageSubresource); + } + for (const VkBufferImageCopy& copy : vk_out_copies) { + dst_range.AddLayers(copy.imageSubresource); + } + static constexpr VkMemoryBarrier READ_BARRIER{ + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + }; + static constexpr VkMemoryBarrier WRITE_BARRIER{ + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + }; + const std::array pre_barriers{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = src_image, + .subresourceRange = src_range.SubresourceRange(src_aspect_mask), + }, + }; + const std::array middle_in_barrier{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = 0, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = src_image, + .subresourceRange = src_range.SubresourceRange(src_aspect_mask), + }, + }; + const std::array middle_out_barrier{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask), + }, + }; + const std::array post_barriers{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask), + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, {}, {}, pre_barriers); + + cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer, + vk_in_copies); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + 0, WRITE_BARRIER, nullptr, middle_in_barrier); + + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, READ_BARRIER, {}, middle_out_barrier); + cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + 0, {}, {}, post_barriers); + }); +} + void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f5f8f9a74..44e9dcee4 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -61,6 +61,10 @@ public: void CopyImage(Image& dst, Image& src, std::span copies); + bool ShouldReinterpret(Image& dst, Image& src); + + void ReinterpretImage(Image& dst, Image& src, std::span copies); + void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled); bool CanAccelerateImageUpload(Image&) const noexcept { @@ -82,6 +86,8 @@ public: return true; } + [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size); + const Device& device; VKScheduler& scheduler; MemoryAllocator& memory_allocator; @@ -90,6 +96,10 @@ public: ASTCDecoderPass& astc_decoder_pass; RenderPassCache& render_pass_cache; const Settings::ResolutionScalingInfo& resolution; + + constexpr static size_t indexing_slots = 8 * sizeof(size_t); + std::array buffers{}; + std::array, indexing_slots> buffer_commits{}; }; class Image : public VideoCommon::ImageBase { @@ -316,7 +326,6 @@ struct TextureCacheParams { static constexpr bool FRAMEBUFFER_BLITS = false; static constexpr bool HAS_EMULATED_COPIES = false; static constexpr bool HAS_DEVICE_MEMORY_INFO = true; - static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = false; using Runtime = Vulkan::TextureCacheRuntime; using Image = Vulkan::Image; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 4188f93c5..44a0d42ba 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1762,8 +1762,8 @@ void TextureCache

::CopyImage(ImageId dst_id, ImageId src_id, std::vector Date: Sat, 20 Nov 2021 06:17:01 +0100 Subject: [PATCH 020/291] TextureCache: Assure full conversions on depth/stencil write shaders. --- src/video_core/host_shaders/convert_abgr8_to_d24s8.frag | 4 ++-- src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag | 4 ++-- src/video_core/host_shaders/convert_r16g16_to_d24s8.frag | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag index f7657e50a..4e4ab6a26 100644 --- a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #version 450 -// #extension GL_ARB_shader_stencil_export : require +#extension GL_ARB_shader_stencil_export : require layout(binding = 0) uniform sampler2D color_texture; @@ -13,5 +13,5 @@ void main() { uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b; gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f); - // gl_FragStencilRefARB = int(color.a); + gl_FragStencilRefARB = int(color.a); } diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag index b7358c15c..2999a84cf 100644 --- a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #version 450 -// #extension GL_ARB_shader_stencil_export : require +#extension GL_ARB_shader_stencil_export : require layout(binding = 0) uniform sampler2D color_texture; @@ -15,5 +15,5 @@ void main() { | (uint(color.r * (exp2(11) - 1.0f))); gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); - // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); + gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); } diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag index 7b1b914f6..3df70575e 100644 --- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #version 450 -// #extension GL_ARB_shader_stencil_export : require +#extension GL_ARB_shader_stencil_export : require layout(binding = 0) uniform sampler2D color_texture; @@ -14,5 +14,5 @@ void main() { | (uint(color.g * (exp2(16) - 1.0f)) << 16); gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); - // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); + gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); } From da2fe8190518d3266df7f4a48f9b651eaea84d4b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 20 Nov 2021 14:46:19 +0100 Subject: [PATCH 021/291] TextureCache: Refactor and fix linux compiling. --- src/common/bit_util.h | 7 +++++++ src/video_core/renderer_opengl/gl_texture_cache.cpp | 6 ++---- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 7 ++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 64520ca4e..eef8c1c5a 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/common_types.h" @@ -44,4 +45,10 @@ template return static_cast(log2_f + static_cast((value ^ (1ULL << log2_f)) != 0ULL)); } +template +requires std::is_integral_v +[[nodiscard]] T NextPow2(T value) { + return static_cast(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U))); +} + } // namespace Common diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index e70bbec81..ecb215a7d 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -9,6 +9,7 @@ #include +#include "common/bit_util.h" #include "common/literals.h" #include "common/settings.h" #include "video_core/renderer_opengl/gl_device.h" @@ -397,9 +398,6 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form return GL_R32UI; } -[[nodiscard]] u32 NextPow2(u32 value) { - return 1U << (32U - std::countl_zero(value - 1U)); -} } // Anonymous namespace ImageBufferMap::~ImageBufferMap() { @@ -1308,7 +1306,7 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image, const u32 copy_size = region.width * region.height * region.depth * img_bpp; if (pbo_size < copy_size) { intermediate_pbo.Create(); - pbo_size = NextPow2(copy_size); + pbo_size = Common::NextPow2(copy_size); glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY); } // Copy from source to PBO diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 02215cfc2..f194110e5 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -8,6 +8,7 @@ #include #include "common/bit_cast.h" +#include "common/bit_util.h" #include "common/settings.h" #include "video_core/engines/fermi_2d.h" @@ -775,16 +776,12 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { return false; } -[[nodiscard]] size_t NextPow2(size_t value) { - return static_cast(1ULL << ((8U * sizeof(size_t)) - std::countl_zero(value - 1U))); -} - VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); if (buffer_commits[level]) { return *buffers[level]; } - const auto new_size = NextPow2(needed_size); + const auto new_size = Common::NextPow2(needed_size); VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; From fe1f06c856b768e9afcc9ba9ab8ef09b7152678c Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sat, 20 Nov 2021 17:48:22 -0500 Subject: [PATCH 022/291] Fix screenshot dimensions when at 1x scale This was regressed by ART. Prior to ART, the screenshots were saved at the title's framebuffer resolution. A misunderstanding of the existing logic led to screenshot dimensions becoming dependent on the host render window size. This changes the behavior to match how it was prior to ART at 1x, with screenshots now always being the title's framebuffer dimensions scaled by the resolution scaling factor. --- src/core/frontend/framebuffer_layout.cpp | 7 ++++++- src/core/frontend/framebuffer_layout.h | 11 +---------- src/video_core/video_core.cpp | 6 ------ src/video_core/video_core.h | 2 -- src/yuzu/bootmanager.cpp | 2 +- 5 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 4b58b672a..26a5b12aa 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -25,7 +25,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { ASSERT(height > 0); // The drawing code needs at least somewhat valid values for both screens // so just calculate them both even if the other isn't showing. - FramebufferLayout res{width, height, false, {}}; + FramebufferLayout res{ + .width = width, + .height = height, + .screen = {}, + .is_srgb = false, + }; const float window_aspect_ratio = static_cast(height) / static_cast(width); const float emulation_aspect_ratio = EmulationAspectRatio( diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 2e36c0163..8e341e4e2 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -35,17 +35,8 @@ enum class AspectRatio { struct FramebufferLayout { u32 width{ScreenUndocked::Width}; u32 height{ScreenUndocked::Height}; - bool is_srgb{}; - Common::Rectangle screen; - - /** - * Returns the ration of pixel size of the screen, compared to the native size of the undocked - * Switch screen. - */ - float GetScalingRatio() const { - return static_cast(screen.GetWidth()) / ScreenUndocked::Width; - } + bool is_srgb{}; }; /** diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index e852c817e..329bf4def 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -55,10 +55,4 @@ std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor } } -float GetResolutionScaleFactor(const RendererBase& renderer) { - return Settings::values.resolution_info.active - ? Settings::values.resolution_info.up_factor - : renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio(); -} - } // namespace VideoCore diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index f86877e86..084df641f 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -25,6 +25,4 @@ class RendererBase; /// Creates an emulated GPU instance using the given system context. std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); -float GetResolutionScaleFactor(const RendererBase& renderer); - } // namespace VideoCore diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 976acd176..822ba1a34 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -630,7 +630,7 @@ void GRenderWindow::ReleaseRenderTarget() { void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { auto& renderer = system.Renderer(); - const f32 res_scale = VideoCore::GetResolutionScaleFactor(renderer); + const f32 res_scale = Settings::values.resolution_info.up_factor; const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); From 40cd0bb97b3d6db6eba0e18fae6560c8e1b69794 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 19:39:26 -0500 Subject: [PATCH 023/291] service: pm: Rename title id to program id --- src/core/hle/service/pm/pm.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 88fc5b5cc..969300795 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -95,13 +95,13 @@ public: private: void GetProcessId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto title_id = rp.PopRaw(); + const auto program_id = rp.PopRaw(); - LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); + LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); const auto process = - SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) { - return proc->GetProgramID() == title_id; + SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { + return proc->GetProgramID() == program_id; }); if (!process.has_value()) { @@ -128,13 +128,13 @@ public: explicit Info(Core::System& system_, const std::vector& process_list_) : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { static const FunctionInfo functions[] = { - {0, &Info::GetTitleId, "GetTitleId"}, + {0, &Info::GetProgramId, "GetProgramId"}, }; RegisterHandlers(functions); } private: - void GetTitleId(Kernel::HLERequestContext& ctx) { + void GetProgramId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto process_id = rp.PopRaw(); From 3dc38d185b595ef2cf1d539f7bc68554999cd1db Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 19:42:30 -0500 Subject: [PATCH 024/291] service: pm: Add all relevant result codes --- src/core/hle/service/pm/pm.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 969300795..b2e97a218 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -13,7 +13,12 @@ namespace Service::PM { namespace { -constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; +constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1}; +[[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2}; +[[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3}; +[[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4}; +[[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5}; +[[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6}; constexpr u64 NO_PROCESS_FOUND_PID{0}; @@ -106,7 +111,7 @@ private: if (!process.has_value()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_PROCESS_NOT_FOUND); + rb.Push(ResultProcessNotFound); return; } @@ -146,7 +151,7 @@ private: if (!process.has_value()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_PROCESS_NOT_FOUND); + rb.Push(ResultProcessNotFound); return; } From 9173f07a51ee355d79c60fed21e7731868db5e6d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 19:52:25 -0500 Subject: [PATCH 025/291] service: pm: Implement AtmosphereGetProcessId - Used by Skyline modding framework --- src/core/hle/service/pm/pm.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index b2e97a218..277abc17a 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -134,6 +134,9 @@ public: : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { static const FunctionInfo functions[] = { {0, &Info::GetProgramId, "GetProgramId"}, + {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, + {65001, nullptr, "AtmosphereHasLaunchedProgram"}, + {65002, nullptr, "AtmosphereGetProcessInfo"}, }; RegisterHandlers(functions); } @@ -160,6 +163,27 @@ private: rb.Push((*process)->GetProgramID()); } + void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto program_id = rp.PopRaw(); + + LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); + + const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { + return proc->GetProgramID() == program_id; + }); + + if (!process.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultProcessNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push((*process)->GetProcessID()); + } + const std::vector& process_list; }; From 095bc88428a0c744136969441e4763ddb5c697a6 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 21:18:37 -0500 Subject: [PATCH 026/291] vk_blit_image: Consolidate CreatePipelineTargetEx functions --- src/video_core/renderer_vulkan/blit_image.cpp | 38 +++++-------------- src/video_core/renderer_vulkan/blit_image.h | 3 ++ 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 28b631f73..a63d4d222 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -749,8 +749,9 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend }); } -void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, - vk::ShaderModule& module, bool single_texture) { +void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool is_target_depth, + bool single_texture) { if (pipeline) { return; } @@ -767,7 +768,7 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pDepthStencilState = nullptr, + .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, @@ -778,33 +779,14 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen }); } +void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool single_texture) { + ConvertPipelineEx(pipeline, renderpass, module, false, single_texture); +} + void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, vk::ShaderModule& module, bool single_texture) { - if (pipeline) { - return; - } - const std::array stages = MakeStages(*full_screen_vert, *module); - pipeline = device.GetLogical().CreateGraphicsPipeline({ - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .stageCount = static_cast(stages.size()), - .pStages = stages.data(), - .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pTessellationState = nullptr, - .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, - .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, - .renderPass = renderpass, - .subpass = 0, - .basePipelineHandle = VK_NULL_HANDLE, - .basePipelineIndex = 0, - }); + ConvertPipelineEx(pipeline, renderpass, module, true, single_texture); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index cec095341..3455c75f4 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -89,6 +89,9 @@ private: void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); + void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, + vk::ShaderModule& module, bool is_target_depth, bool single_texture); + void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, vk::ShaderModule& module, bool single_texture); From a41c6dafea6e00d674cfcf3e1b6576fa208acf81 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 21:49:37 -0500 Subject: [PATCH 027/291] vk_texture_cache: Mark VkBufferUsageFlags as static constexpr --- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 3964424af..c72f0c897 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -787,9 +787,9 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { return *buffers[level]; } const auto new_size = Common::NextPow2(needed_size); - VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + static constexpr VkBufferUsageFlags flags = + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; buffers[level] = device.GetLogical().CreateBuffer({ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, From 281437c811847adbc38b69ef3638996c666f65c3 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 20:05:02 -0500 Subject: [PATCH 028/291] kernel: KPageTable: Rename SetCodeMemoryPermission to SetProcessMemoryPermission --- src/core/hle/kernel/k_page_table.cpp | 4 ++-- src/core/hle/kernel/k_page_table.h | 2 +- src/core/hle/kernel/k_process.cpp | 2 +- src/core/hle/service/ldr/ldr.cpp | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 526b87241..9bda5c5b2 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -685,8 +685,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, return ResultSuccess; } -ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, - KMemoryPermission perm) { +ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, + KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 770c4841c..b7ec38f06 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -41,7 +41,7 @@ public: ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, KMemoryPermission perm); ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); - ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); + ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); KMemoryInfo QueryInfo(VAddr addr); ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); ResultCode ResetTransferMemory(VAddr addr, std::size_t size); diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 76fd8c285..1aad061e1 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -528,7 +528,7 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { std::lock_guard lock{HLE::g_hle_lock}; const auto ReprotectSegment = [&](const CodeSet::Segment& segment, KMemoryPermission permission) { - page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); + page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); }; kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 32eff3b2a..3782703d2 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -396,12 +396,12 @@ public: CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, nro_header.segment_headers[DATA_INDEX].memory_size); - CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( + CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); - CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start, - Kernel::KMemoryPermission::Read)); + CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( + ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); - return process->PageTable().SetCodeMemoryPermission( + return process->PageTable().SetProcessMemoryPermission( data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); } From 2726d705f8dde6d8fcbcfcd55e065a0598e10969 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 20:23:59 -0500 Subject: [PATCH 029/291] kernel: svc: Implement SetProcessMemoryPermission - Used by Skyline modding framework --- src/core/hle/kernel/svc.cpp | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f9d99bc51..23dc44780 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1183,6 +1183,18 @@ constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; } +constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { + switch (perm) { + case Svc::MemoryPermission::None: + case Svc::MemoryPermission::Read: + case Svc::MemoryPermission::ReadWrite: + case Svc::MemoryPermission::ReadExecute: + return true; + default: + return false; + } +} + static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, @@ -1262,6 +1274,34 @@ static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, return UnmapSharedMemory(system, shmem_handle, address, size); } +static ResultCode SetProcessMemoryPermission(Core::System& system, Handle process_handle, + VAddr address, u64 size, Svc::MemoryPermission perm) { + LOG_TRACE(Kernel_SVC, + "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + process_handle, address, size, perm); + + // Validate the address/size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + + // Validate the memory permission. + R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Get the process from its handle. + KScopedAutoObject process = + system.CurrentProcess()->GetHandleTable().GetObject(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Validate that the address is in range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Set the memory permission. + return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -2588,7 +2628,7 @@ static const FunctionDef SVC_Table_64[] = { {0x70, nullptr, "CreatePort"}, {0x71, nullptr, "ManageNamedPort"}, {0x72, nullptr, "ConnectToPort"}, - {0x73, nullptr, "SetProcessMemoryPermission"}, + {0x73, SvcWrap64, "SetProcessMemoryPermission"}, {0x74, nullptr, "MapProcessMemory"}, {0x75, nullptr, "UnmapProcessMemory"}, {0x76, SvcWrap64, "QueryProcessMemory"}, From 5cf93c134684f7548572ff27131901f5909725fa Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 20 Nov 2021 21:54:46 -0500 Subject: [PATCH 030/291] kernel: svc: Move all IsValid functions to an anonymous namespace --- src/core/hle/kernel/svc.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 23dc44780..f0cd8471e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1169,6 +1169,8 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { return GetCurrentProcessorNumber(system); } +namespace { + constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { switch (perm) { case Svc::MemoryPermission::Read: @@ -1179,7 +1181,7 @@ constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { } } -constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { +[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; } @@ -1195,6 +1197,8 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { } } +} // Anonymous namespace + static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, @@ -1499,10 +1503,14 @@ static void ExitProcess32(Core::System& system) { ExitProcess(system); } -static constexpr bool IsValidVirtualCoreId(int32_t core_id) { +namespace { + +constexpr bool IsValidVirtualCoreId(int32_t core_id) { return (0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); } +} // Anonymous namespace + /// Creates a new thread static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_bottom, u32 priority, s32 core_id) { @@ -1886,7 +1894,9 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) { return ResetSignal(system, handle); } -static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { +namespace { + +constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { switch (perm) { case MemoryPermission::None: case MemoryPermission::Read: @@ -1897,6 +1907,8 @@ static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { } } +} // Anonymous namespace + /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, MemoryPermission map_perm) { From 779f4ac72d2ea2788c2106c8d2d1ec0e01b77b81 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 21 Nov 2021 05:32:34 +0100 Subject: [PATCH 031/291] TextureCache: Eliminate format deduction as full depth conversion has been supported. --- src/video_core/texture_cache/texture_cache.h | 6 ++--- src/video_core/texture_cache/util.cpp | 28 +++----------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 44a0d42ba..0e4907c53 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1079,7 +1079,7 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA template typename TextureCache

::BlitImages TextureCache

::GetBlitImages( const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src) { - static constexpr auto FIND_OPTIONS = RelaxedOptions::Format | RelaxedOptions::Samples; + static constexpr auto FIND_OPTIONS = RelaxedOptions::Samples; const GPUVAddr dst_addr = dst.Address(); const GPUVAddr src_addr = src.Address(); ImageInfo dst_info(dst); @@ -1093,9 +1093,7 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( const ImageBase* const dst_image = dst_id ? &slot_images[dst_id] : nullptr; const ImageBase* const src_image = src_id ? &slot_images[src_id] : nullptr; DeduceBlitImages(dst_info, src_info, dst_image, src_image); - if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { - continue; - } + ASSERT(GetFormatType(dst_info.format) == GetFormatType(src_info.format)); RelaxedOptions find_options{}; if (src_info.num_samples > 1) { // it's a resolve, we must enforce the same format. diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index e4d82631e..777503488 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1152,36 +1152,14 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, const ImageBase* src) { bool is_resolve = false; - const auto original_src_format = src_info.format; - const auto original_dst_format = dst_info.format; if (src) { - if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) { - src_info.format = src->info.format; - } is_resolve = src->info.num_samples > 1; src_info.num_samples = src->info.num_samples; src_info.size = src->info.size; } - if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { - dst_info.format = dst->info.format; - } - if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { - if (dst) { - if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) { - src_info.format = original_src_format; - } - } else { - dst_info.format = src->info.format; - } - } - if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { - if (src) { - if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) { - dst_info.format = original_dst_format; - } - } else { - src_info.format = dst->info.format; - } + if (dst) { + dst_info.num_samples = dst->info.num_samples; + dst_info.size = dst->info.size; } ASSERT(!is_resolve || dst_info.format == src_info.format); } From 8e3371a5c5aa26e1f3d0c1f944b65ee6b65c3f34 Mon Sep 17 00:00:00 2001 From: Kewlan Date: Sun, 21 Nov 2021 16:57:00 +0100 Subject: [PATCH 032/291] configure_general: Allow framerate cap to be used in custom game configs --- src/common/settings.cpp | 1 + src/common/settings.h | 2 +- src/yuzu/configuration/config.cpp | 4 +- src/yuzu/configuration/configure_general.cpp | 20 ++++ src/yuzu/configuration/configure_general.ui | 99 +++++++++++++++----- 5 files changed, 99 insertions(+), 27 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 3bcaa072f..6964a8273 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -183,6 +183,7 @@ void RestoreGlobalState(bool is_powered_on) { values.max_anisotropy.SetGlobal(true); values.use_speed_limit.SetGlobal(true); values.speed_limit.SetGlobal(true); + values.fps_cap.SetGlobal(true); values.use_disk_shader_cache.SetGlobal(true); values.gpu_accuracy.SetGlobal(true); values.use_asynchronous_gpu_emulation.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 42f8b4a7d..fa4aa8747 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -525,7 +525,7 @@ struct Values { Setting nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; Setting accelerate_astc{true, "accelerate_astc"}; Setting use_vsync{true, "use_vsync"}; - BasicRangedSetting fps_cap{1000, 1, 1000, "fps_cap"}; + RangedSetting fps_cap{1000, 1, 1000, "fps_cap"}; BasicSetting disable_fps_limit{false, "disable_fps_limit"}; RangedSetting shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL, ShaderBackend::SPIRV, "shader_backend"}; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8227d06bc..2b670ddfd 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -830,6 +830,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.max_anisotropy); ReadGlobalSetting(Settings::values.use_speed_limit); ReadGlobalSetting(Settings::values.speed_limit); + ReadGlobalSetting(Settings::values.fps_cap); ReadGlobalSetting(Settings::values.use_disk_shader_cache); ReadGlobalSetting(Settings::values.gpu_accuracy); ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); @@ -844,7 +845,6 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.bg_blue); if (global) { - ReadBasicSetting(Settings::values.fps_cap); ReadBasicSetting(Settings::values.renderer_debug); ReadBasicSetting(Settings::values.renderer_shader_feedback); ReadBasicSetting(Settings::values.enable_nsight_aftermath); @@ -1382,6 +1382,7 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.max_anisotropy); WriteGlobalSetting(Settings::values.use_speed_limit); WriteGlobalSetting(Settings::values.speed_limit); + WriteGlobalSetting(Settings::values.fps_cap); WriteGlobalSetting(Settings::values.use_disk_shader_cache); WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), static_cast(Settings::values.gpu_accuracy.GetValue(global)), @@ -1405,7 +1406,6 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.bg_blue); if (global) { - WriteBasicSetting(Settings::values.fps_cap); WriteBasicSetting(Settings::values.renderer_debug); WriteBasicSetting(Settings::values.renderer_shader_feedback); WriteBasicSetting(Settings::values.enable_nsight_aftermath); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 7af3ea97e..566879317 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -30,6 +30,9 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent) connect(ui->button_reset_defaults, &QPushButton::clicked, this, &ConfigureGeneral::ResetDefaults); + + ui->fps_cap_label->setVisible(Settings::IsConfiguringGlobal()); + ui->fps_cap_combobox->setVisible(!Settings::IsConfiguringGlobal()); } ConfigureGeneral::~ConfigureGeneral() = default; @@ -57,6 +60,11 @@ void ConfigureGeneral::SetConfiguration() { } else { ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && use_speed_limit != ConfigurationShared::CheckState::Global); + + ui->fps_cap_combobox->setCurrentIndex(Settings::values.fps_cap.UsingGlobal() ? 0 : 1); + ui->fps_cap->setEnabled(!Settings::values.fps_cap.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->fps_cap_layout, + !Settings::values.fps_cap.UsingGlobal()); } } @@ -106,6 +114,13 @@ void ConfigureGeneral::ApplyConfiguration() { Qt::Checked); Settings::values.speed_limit.SetValue(ui->speed_limit->value()); } + + if (ui->fps_cap_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { + Settings::values.fps_cap.SetGlobal(true); + } else { + Settings::values.fps_cap.SetGlobal(false); + Settings::values.fps_cap.SetValue(ui->fps_cap->value()); + } } } @@ -148,4 +163,9 @@ void ConfigureGeneral::SetupPerGameUI() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && (use_speed_limit != ConfigurationShared::CheckState::Global)); }); + + connect(ui->fps_cap_combobox, qOverload(&QComboBox::activated), this, [this](int index) { + ui->fps_cap->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->fps_cap_layout, index == 1); + }); } diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index f9f0e3ebf..112dc72b3 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -6,8 +6,8 @@ 0 0 - 329 - 407 + 744 + 568 @@ -28,34 +28,85 @@ - - - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Use global framerate cap + + + 0 + + - Framerate Cap + Use global framerate cap - - Requires the use of the FPS Limiter Toggle hotkey to take effect. + + + + Set framerate cap: + - - - - - x - - - 1 - - - 1000 - - - 500 - + + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. + + + Framerate Cap + - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + x + + + 1 + + + 1000 + + + 500 + + + + From b96caf200d047b81554c3839c7a6a7c35b251944 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 21 Nov 2021 20:52:39 +0100 Subject: [PATCH 033/291] HostShaders: Fix D24S8 convertion shaders. --- .../host_shaders/convert_abgr8_to_d24s8.frag | 7 ++++--- .../convert_b10g11r11_to_d24s8.frag | 18 +++++++++++++----- .../host_shaders/convert_d24s8_to_abgr8.frag | 10 ++++++---- .../convert_d24s8_to_b10g11r11.frag | 19 +++++++++++++++---- .../host_shaders/convert_d24s8_to_r16g16.frag | 7 ++++--- .../host_shaders/convert_r16g16_to_d24s8.frag | 9 +++++---- 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag index 4e4ab6a26..d51397a0c 100644 --- a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag @@ -10,8 +10,9 @@ layout(binding = 0) uniform sampler2D color_texture; void main() { ivec2 coord = ivec2(gl_FragCoord.xy); uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f)); - uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b; + uvec4 bytes = color << uvec4(24, 16, 8, 0); + uint depth_stencil_unorm = bytes.x | bytes.y | bytes.z | bytes.w; - gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f); - gl_FragStencilRefARB = int(color.a); + gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f); + gl_FragStencilRefARB = int(depth_stencil_unorm >> 24); } diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag index 2999a84cf..11bdd861d 100644 --- a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag @@ -7,13 +7,21 @@ layout(binding = 0) uniform sampler2D color_texture; +uint conv_from_float(float value_f, uint mantissa_bits) { + uint value = floatBitsToInt(value_f); + uint exp = (value >> 23) & 0x1Fu; + uint mantissa_shift = 32u - mantissa_bits; + uint mantissa = (value << 9u) >> mantissa_shift; + return (exp << mantissa_bits) | mantissa; +} + void main() { ivec2 coord = ivec2(gl_FragCoord.xy); vec4 color = texelFetch(color_texture, coord, 0).rgba; - uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22) - | (uint(color.g * (exp2(11) - 1.0f)) << 11) - | (uint(color.r * (exp2(11) - 1.0f))); + uint depth_stencil_unorm = (conv_from_float(color.r, 6u) << 21) + | (conv_from_float(color.g, 6u) << 10) + | conv_from_float(color.b, 5u); - gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); - gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); + gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f); + gl_FragStencilRefARB = int(depth_stencil_unorm >> 24); } diff --git a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag index ff3bf8209..47f9c1abc 100644 --- a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag +++ b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag @@ -14,8 +14,10 @@ void main() { uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); uint stencil = uint(textureLod(stencil_tex, coord, 0).r); - color.r = float(depth >> 16) / (exp2(8) - 1.0); - color.g = float((depth >> 8) & 0x00FF) / (exp2(8) - 1.0); - color.b = float(depth & 0x00FF) / (exp2(8) - 1.0); - color.a = float(stencil) / (exp2(8) - 1.0); + highp uint depth_val = + uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0)); + lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r; + highp uvec4 components = + uvec4(stencil_val, (uvec3(depth_val) >> uvec3(24u, 16u, 8u)) & 0x000000FFu); + color = vec4(components) / (exp2(8.0) - 1.0); } diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag index c743d3a13..c2d935fcd 100644 --- a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag +++ b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag @@ -9,13 +9,24 @@ layout(binding = 1) uniform isampler2D stencil_tex; layout(location = 0) out vec4 color; +float conv_to_float(uint value, uint mantissa_bits) { + uint exp = (value >> mantissa_bits) & 0x1Fu; + uint mantissa_shift = 32u - mantissa_bits; + uint mantissa = (value << mantissa_shift) >> mantissa_shift; + return uintBitsToFloat((exp << 23) | (mantissa << (23 - mantissa_bits))); +} + void main() { ivec2 coord = ivec2(gl_FragCoord.xy); - uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); + uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f)); uint stencil = uint(textureLod(stencil_tex, coord, 0).r); + uint depth_stencil = (stencil << 24) | (depth >> 8); + uint red_int = (depth_stencil >> 21) & 0x07FF; + uint green_int = (depth_stencil >> 10) & 0x07FF; + uint blue_int = depth_stencil & 0x03FF; - color.b = float(depth >> 22) / (exp2(10) - 1.0); - color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0); - color.r = float(depth & 0x00FF) / (exp2(11) - 1.0); + color.r = conv_to_float(red_int, 6u); + color.g = conv_to_float(green_int, 6u); + color.b = conv_to_float(blue_int, 5u); color.a = 1.0f; } diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag index 2a9443d3d..c48a7ac66 100644 --- a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag +++ b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag @@ -11,11 +11,12 @@ layout(location = 0) out vec4 color; void main() { ivec2 coord = ivec2(gl_FragCoord.xy); - uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f)); + uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f)); uint stencil = uint(textureLod(stencil_tex, coord, 0).r); + uint depth_stencil = (stencil << 24) | (depth >> 8); - color.r = float(depth >> 16) / (exp2(16) - 1.0); - color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0); + color.r = float(depth_stencil & 0x0000FFFFu) / (exp2(16) - 1.0); + color.g = float(depth_stencil >> 16) / (exp2(16) - 1.0); color.b = 0.0f; color.a = 1.0f; } diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag index 3df70575e..beb2d1284 100644 --- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag @@ -10,9 +10,10 @@ layout(binding = 0) uniform sampler2D color_texture; void main() { ivec2 coord = ivec2(gl_FragCoord.xy); vec4 color = texelFetch(color_texture, coord, 0).rgba; - uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16) - | (uint(color.g * (exp2(16) - 1.0f)) << 16); + uvec2 bytes = uvec2(color.rg * (exp2(16) - 1.0f)) << uvec2(0, 16); + uint depth_stencil_unorm = + uint(color.r * (exp2(16) - 1.0f)) | (uint(color.g * (exp2(16) - 1.0f)) << 16); - gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f); - gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF); + gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f); + gl_FragStencilRefARB = int(depth_stencil_unorm >> 24); } From d7f4434bd534d53e8aea293e39629bf8ca8ee123 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 21 Nov 2021 21:09:49 +0100 Subject: [PATCH 034/291] VulkanTexturECache: Use reinterpret on D32_S8 formats. --- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 3964424af..e1ba1bdaf 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -775,8 +775,13 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) { bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { if (VideoCore::Surface::GetFormatType(dst.info.format) == - VideoCore::Surface::SurfaceType::DepthStencil) { - return !device.IsExtShaderStencilExportSupported(); + VideoCore::Surface::SurfaceType::DepthStencil && + !device.IsExtShaderStencilExportSupported()) { + return true; + } + if (dst.info.format == PixelFormat::D32_FLOAT_S8_UINT || + src.info.format == PixelFormat::D32_FLOAT_S8_UINT) { + return true; } return false; } From 853284943901560081f6ff992b6c04b7c33f0d21 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 22 Nov 2021 00:00:01 +0100 Subject: [PATCH 035/291] TextureCache: Simplify blitting of D24S8 formats and fix bugs. --- src/video_core/host_shaders/CMakeLists.txt | 4 - .../convert_b10g11r11_to_d24s8.frag | 27 ----- .../convert_d24s8_to_b10g11r11.frag | 32 ------ .../host_shaders/convert_d24s8_to_r16g16.frag | 22 ----- .../host_shaders/convert_r16g16_to_d24s8.frag | 19 ---- src/video_core/renderer_vulkan/blit_image.cpp | 98 ++++++++++--------- src/video_core/renderer_vulkan/blit_image.h | 25 +---- .../renderer_vulkan/vk_texture_cache.cpp | 30 ++---- .../renderer_vulkan/vk_texture_cache.h | 3 + src/video_core/texture_cache/texture_cache.h | 8 +- 10 files changed, 73 insertions(+), 195 deletions(-) delete mode 100644 src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag delete mode 100644 src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag delete mode 100644 src/video_core/host_shaders/convert_d24s8_to_r16g16.frag delete mode 100644 src/video_core/host_shaders/convert_r16g16_to_d24s8.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 1c91999d7..fd3e41434 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -11,13 +11,9 @@ set(SHADER_FILES block_linear_unswizzle_2d.comp block_linear_unswizzle_3d.comp convert_abgr8_to_d24s8.frag - convert_b10g11r11_to_d24s8.frag convert_d24s8_to_abgr8.frag - convert_d24s8_to_b10g11r11.frag - convert_d24s8_to_r16g16.frag convert_depth_to_float.frag convert_float_to_depth.frag - convert_r16g16_to_d24s8.frag full_screen_triangle.vert fxaa.frag fxaa.vert diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag deleted file mode 100644 index 11bdd861d..000000000 --- a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#version 450 -#extension GL_ARB_shader_stencil_export : require - -layout(binding = 0) uniform sampler2D color_texture; - -uint conv_from_float(float value_f, uint mantissa_bits) { - uint value = floatBitsToInt(value_f); - uint exp = (value >> 23) & 0x1Fu; - uint mantissa_shift = 32u - mantissa_bits; - uint mantissa = (value << 9u) >> mantissa_shift; - return (exp << mantissa_bits) | mantissa; -} - -void main() { - ivec2 coord = ivec2(gl_FragCoord.xy); - vec4 color = texelFetch(color_texture, coord, 0).rgba; - uint depth_stencil_unorm = (conv_from_float(color.r, 6u) << 21) - | (conv_from_float(color.g, 6u) << 10) - | conv_from_float(color.b, 5u); - - gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f); - gl_FragStencilRefARB = int(depth_stencil_unorm >> 24); -} diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag deleted file mode 100644 index c2d935fcd..000000000 --- a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#version 450 - -layout(binding = 0) uniform sampler2D depth_tex; -layout(binding = 1) uniform isampler2D stencil_tex; - -layout(location = 0) out vec4 color; - -float conv_to_float(uint value, uint mantissa_bits) { - uint exp = (value >> mantissa_bits) & 0x1Fu; - uint mantissa_shift = 32u - mantissa_bits; - uint mantissa = (value << mantissa_shift) >> mantissa_shift; - return uintBitsToFloat((exp << 23) | (mantissa << (23 - mantissa_bits))); -} - -void main() { - ivec2 coord = ivec2(gl_FragCoord.xy); - uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f)); - uint stencil = uint(textureLod(stencil_tex, coord, 0).r); - uint depth_stencil = (stencil << 24) | (depth >> 8); - uint red_int = (depth_stencil >> 21) & 0x07FF; - uint green_int = (depth_stencil >> 10) & 0x07FF; - uint blue_int = depth_stencil & 0x03FF; - - color.r = conv_to_float(red_int, 6u); - color.g = conv_to_float(green_int, 6u); - color.b = conv_to_float(blue_int, 5u); - color.a = 1.0f; -} diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag deleted file mode 100644 index c48a7ac66..000000000 --- a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#version 450 - -layout(binding = 0) uniform sampler2D depth_tex; -layout(binding = 1) uniform isampler2D stencil_tex; - -layout(location = 0) out vec4 color; - -void main() { - ivec2 coord = ivec2(gl_FragCoord.xy); - uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f)); - uint stencil = uint(textureLod(stencil_tex, coord, 0).r); - uint depth_stencil = (stencil << 24) | (depth >> 8); - - color.r = float(depth_stencil & 0x0000FFFFu) / (exp2(16) - 1.0); - color.g = float(depth_stencil >> 16) / (exp2(16) - 1.0); - color.b = 0.0f; - color.a = 1.0f; -} diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag deleted file mode 100644 index beb2d1284..000000000 --- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#version 450 -#extension GL_ARB_shader_stencil_export : require - -layout(binding = 0) uniform sampler2D color_texture; - -void main() { - ivec2 coord = ivec2(gl_FragCoord.xy); - vec4 color = texelFetch(color_texture, coord, 0).rgba; - uvec2 bytes = uvec2(color.rg * (exp2(16) - 1.0f)) << uvec2(0, 16); - uint depth_stencil_unorm = - uint(color.r * (exp2(16) - 1.0f)) | (uint(color.g * (exp2(16) - 1.0f)) << 16); - - gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f); - gl_FragStencilRefARB = int(depth_stencil_unorm >> 24); -} diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 28b631f73..2e69e270f 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -5,13 +5,9 @@ #include #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" -#include "video_core/host_shaders/convert_b10g11r11_to_d24s8_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" -#include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h" -#include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" -#include "video_core/host_shaders/convert_r16g16_to_d24s8_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" @@ -361,11 +357,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), - convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)), - convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), - convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)), - convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)), nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) { if (device.IsExtShaderStencilExportSupported()) { @@ -461,30 +453,11 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, } void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, - const ImageView& src_image_view, u32 up_scale, - u32 down_shift) { + ImageView& src_image_view, u32 up_scale, u32 down_shift) { ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), convert_abgr8_to_d24s8_frag, true); - Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, - down_shift); -} - -void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, - const ImageView& src_image_view, u32 up_scale, - u32 down_shift) { - ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(), - convert_b10g11r11_to_d24s8_frag, true); - Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, - down_shift); -} - -void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, - const ImageView& src_image_view, u32 up_scale, - u32 down_shift) { - ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(), - convert_r16g16_to_d24s8_frag, true); - Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, - down_shift); + ConvertColor(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, + down_shift); } void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, @@ -495,24 +468,6 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, down_shift); } -void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, - ImageView& src_image_view, u32 up_scale, - u32 down_shift) { - ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(), - convert_d24s8_to_b10g11r11_frag, false); - ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view, - up_scale, down_shift); -} - -void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, - ImageView& src_image_view, u32 up_scale, - u32 down_shift) { - ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(), - convert_d24s8_to_r16g16_frag, false); - ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view, - up_scale, down_shift); -} - void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift) { const VkPipelineLayout layout = *one_texture_pipeline_layout; @@ -560,6 +515,53 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb scheduler.InvalidateState(); } +void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, u32 down_shift) { + const VkPipelineLayout layout = *one_texture_pipeline_layout; + const VkImageView src_view = src_image_view.ColorView(); + const VkSampler sampler = *nearest_sampler; + const VkExtent2D extent{ + .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), + .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), + }; + scheduler.RequestRenderpass(dst_framebuffer); + scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift, + this](vk::CommandBuffer cmdbuf) { + const VkOffset2D offset{ + .x = 0, + .y = 0, + }; + const VkViewport viewport{ + .x = 0.0f, + .y = 0.0f, + .width = static_cast(extent.width), + .height = static_cast(extent.height), + .minDepth = 0.0f, + .maxDepth = 0.0f, + }; + const VkRect2D scissor{ + .offset = offset, + .extent = extent, + }; + const PushConstants push_constants{ + .tex_scale = {viewport.width, viewport.height}, + .tex_offset = {0.0f, 0.0f}, + }; + const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); + UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); + + // TODO: Barriers + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, + nullptr); + cmdbuf.SetViewport(0, viewport); + cmdbuf.SetScissor(0, scissor); + cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); + cmdbuf.Draw(3, 1, 0, 0); + }); + scheduler.InvalidateState(); +} + void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift) { const VkPipelineLayout layout = *two_textures_pipeline_layout; diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index cec095341..0b73cf444 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -56,28 +56,19 @@ public: void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); - void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, + void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); - void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, - const ImageView& src_image_view, u32 up_scale, u32 down_shift); - - void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, - u32 up_scale, u32 down_shift); - void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); - void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view, - u32 up_scale, u32 down_shift); - - void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view, - u32 up_scale, u32 down_shift); - private: void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer, + ImageView& src_image_view, u32 up_scale, u32 down_shift); + void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, ImageView& src_image_view, u32 up_scale, u32 down_shift); @@ -111,11 +102,7 @@ private: vk::ShaderModule convert_depth_to_float_frag; vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag; - vk::ShaderModule convert_b10g11r11_to_d24s8_frag; - vk::ShaderModule convert_r16g16_to_d24s8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag; - vk::ShaderModule convert_d24s8_to_b10g11r11_frag; - vk::ShaderModule convert_d24s8_to_r16g16_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; @@ -128,11 +115,7 @@ private: vk::Pipeline convert_d16_to_r16_pipeline; vk::Pipeline convert_r16_to_d16_pipeline; vk::Pipeline convert_abgr8_to_d24s8_pipeline; - vk::Pipeline convert_b10g11r11_to_d24s8_pipeline; - vk::Pipeline convert_r16g16_to_d24s8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline; - vk::Pipeline convert_d24s8_to_b10g11r11_pipeline; - vk::Pipeline convert_d24s8_to_r16g16_pipeline; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index e1ba1bdaf..ef8ae6cb6 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1063,21 +1063,10 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im } break; case PixelFormat::A8B8G8R8_UNORM: - case PixelFormat::B8G8R8A8_UNORM: if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift); } break; - case PixelFormat::B10G11R11_FLOAT: - if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { - return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift); - } - break; - case PixelFormat::R16G16_UNORM: - if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { - return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift); - } - break; case PixelFormat::R32_FLOAT: if (src_view.format == PixelFormat::D32_FLOAT) { return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); @@ -1089,16 +1078,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im } break; case PixelFormat::S8_UINT_D24_UNORM: - if (src_view.format == PixelFormat::A8B8G8R8_UNORM || - src_view.format == PixelFormat::B8G8R8A8_UNORM) { - return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); - } - if (src_view.format == PixelFormat::B10G11R11_FLOAT) { - return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift); - } - if (src_view.format == PixelFormat::R16G16_UNORM) { - return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift); - } + return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); break; case PixelFormat::D32_FLOAT: if (src_view.format == PixelFormat::R32_FLOAT) { @@ -1595,6 +1575,14 @@ VkImageView ImageView::StencilView() { return *stencil_view; } +VkImageView ImageView::ColorView() { + if (color_view) { + return *color_view; + } + color_view = MakeView(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + return *color_view; +} + VkImageView ImageView::StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format) { if (image_format == Shader::ImageFormat::Typeless) { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 44e9dcee4..753e3e8a1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -184,6 +184,8 @@ public: [[nodiscard]] VkImageView StencilView(); + [[nodiscard]] VkImageView ColorView(); + [[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format); @@ -224,6 +226,7 @@ private: std::unique_ptr storage_views; vk::ImageView depth_view; vk::ImageView stencil_view; + vk::ImageView color_view; VkImage image_handle = VK_NULL_HANDLE; VkImageView render_target = VK_NULL_HANDLE; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 0e4907c53..9548abec8 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1781,7 +1781,13 @@ void TextureCache

::CopyImage(ImageId dst_id, ImageId src_id, std::vector Date: Mon, 22 Nov 2021 00:06:56 +0100 Subject: [PATCH 036/291] Texture Cache: Always copy on NVIDIA. --- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ef8ae6cb6..51246d46f 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -779,6 +779,11 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { !device.IsExtShaderStencilExportSupported()) { return true; } + if (VideoCore::Surface::GetFormatType(src.info.format) == + VideoCore::Surface::SurfaceType::DepthStencil && + !device.IsExtShaderStencilExportSupported()) { + return true; + } if (dst.info.format == PixelFormat::D32_FLOAT_S8_UINT || src.info.format == PixelFormat::D32_FLOAT_S8_UINT) { return true; From 1e474fb9d1c5e35c2bb8822d58556ef3358e66e9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 22 Nov 2021 00:21:42 +0100 Subject: [PATCH 037/291] Texture Cache: Correct conversion shaders. --- src/video_core/host_shaders/convert_abgr8_to_d24s8.frag | 2 +- src/video_core/host_shaders/convert_d24s8_to_abgr8.frag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag index d51397a0c..ea055ddad 100644 --- a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag +++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag @@ -9,7 +9,7 @@ layout(binding = 0) uniform sampler2D color_texture; void main() { ivec2 coord = ivec2(gl_FragCoord.xy); - uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f)); + uvec4 color = uvec4(texelFetch(color_texture, coord, 0).abgr * (exp2(8) - 1.0f)); uvec4 bytes = color << uvec4(24, 16, 8, 0); uint depth_stencil_unorm = bytes.x | bytes.y | bytes.z | bytes.w; diff --git a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag index 47f9c1abc..94368fb59 100644 --- a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag +++ b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag @@ -19,5 +19,5 @@ void main() { lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r; highp uvec4 components = uvec4(stencil_val, (uvec3(depth_val) >> uvec3(24u, 16u, 8u)) & 0x000000FFu); - color = vec4(components) / (exp2(8.0) - 1.0); + color.abgr = vec4(components) / (exp2(8.0) - 1.0); } From f90d9808378092e208b431f467c54feb6952e91d Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Sun, 21 Nov 2021 17:28:47 -0800 Subject: [PATCH 038/291] Added TAS controls to the menu under Tools --- src/yuzu/bootmanager.cpp | 9 ++++ src/yuzu/bootmanager.h | 6 +++ src/yuzu/main.cpp | 100 +++++++++++++++++++++++++++------------ src/yuzu/main.h | 5 ++ src/yuzu/main.ui | 92 +++++++++++++++++++++++------------ 5 files changed, 154 insertions(+), 58 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 822ba1a34..105f36d33 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -303,6 +303,7 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, Qt::QueuedConnection); connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); + connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged); } void GRenderWindow::ExecuteProgram(std::size_t program_index) { @@ -319,10 +320,18 @@ GRenderWindow::~GRenderWindow() { void GRenderWindow::OnFrameDisplayed() { input_subsystem->GetTas()->UpdateThread(); + TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus()); + if (!first_frame) { + last_tas_state = new_tas_state; first_frame = true; emit FirstFrameDisplayed(); } + + if (new_tas_state != last_tas_state) { + last_tas_state = new_tas_state; + emit TasPlaybackStateChanged(); + } } bool GRenderWindow::IsShown() const { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 40fd4a9d6..061e3605f 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -41,6 +41,10 @@ enum class LoadCallbackStage; class RendererBase; } // namespace VideoCore +namespace TasInput { +enum class TasState; +} + class EmuThread final : public QThread { Q_OBJECT @@ -203,6 +207,7 @@ signals: void ExecuteProgramSignal(std::size_t program_index); void ExitSignal(); void MouseActivity(); + void TasPlaybackStateChanged(); private: void TouchBeginEvent(const QTouchEvent* event); @@ -236,6 +241,7 @@ private: QWidget* child_widget = nullptr; bool first_frame = false; + TasInput::TasState last_tas_state; std::array touch_ids{}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c4c76b094..73278f29f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -965,6 +965,9 @@ void GMainWindow::InitializeHotkeys() { const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); const QString fullscreen = QStringLiteral("Fullscreen"); const QString capture_screenshot = QStringLiteral("Capture Screenshot"); + const QString tas_start_stop = QStringLiteral("TAS Start/Stop"); + const QString tas_record = QStringLiteral("TAS Record"); + const QString tas_reset = QStringLiteral("TAS Reset"); ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); ui->action_Load_File->setShortcutContext( @@ -1005,6 +1008,18 @@ void GMainWindow::InitializeHotkeys() { ui->action_Fullscreen->setShortcutContext( hotkey_registry.GetShortcutContext(main_window, fullscreen)); + ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop)); + ui->action_TAS_Start->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, tas_start_stop)); + + ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record)); + ui->action_TAS_Record->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, tas_record)); + + ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset)); + ui->action_TAS_Reset->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, tas_reset)); + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); connect( @@ -1095,28 +1110,6 @@ void GMainWindow::InitializeHotkeys() { render_window->setAttribute(Qt::WA_Hover, true); } }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this), - &QShortcut::activated, this, [&] { - if (!emulation_running) { - return; - } - input_subsystem->GetTas()->StartStop(); - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this), - &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this), - &QShortcut::activated, this, [&] { - if (!emulation_running) { - return; - } - bool is_recording = input_subsystem->GetTas()->Record(); - if (!is_recording) { - const auto res = QMessageBox::question(this, tr("TAS Recording"), - tr("Overwrite file of player 1?"), - QMessageBox::Yes | QMessageBox::No); - input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); - } - }); } void GMainWindow::SetDefaultUIGeometry() { @@ -1236,11 +1229,11 @@ void GMainWindow::ConnectMenuEvents() { connect(ui->action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); - connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); connect(ui->action_Configure_Current_Game, &QAction::triggered, this, &GMainWindow::OnConfigurePerGame); // View + connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); connect(ui->action_Single_Window_Mode, &QAction::triggered, this, &GMainWindow::ToggleWindowMode); connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this, @@ -1258,17 +1251,20 @@ void GMainWindow::ConnectMenuEvents() { ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900); ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080); - // Fullscreen - connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); - - // Movie + // Tools + connect(ui->action_Rederive, &QAction::triggered, this, + std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); connect(ui->action_Capture_Screenshot, &QAction::triggered, this, &GMainWindow::OnCaptureScreenshot); + // TAS + connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop); + connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord); + connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset); + connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); + // Help connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); - connect(ui->action_Rederive, &QAction::triggered, this, - std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout); } @@ -1582,6 +1578,7 @@ void GMainWindow::ShutdownGame() { game_list->SetFilterFocus(); tas_label->clear(); input_subsystem->GetTas()->Stop(); + OnTasStateChanged(); render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); @@ -2509,6 +2506,7 @@ void GMainWindow::OnStartGame() { ui->action_Restart->setEnabled(true); ui->action_Configure_Current_Game->setEnabled(true); ui->action_Report_Compatibility->setEnabled(true); + OnTasStateChanged(); discord_rpc->Update(); ui->action_Load_Amiibo->setEnabled(true); @@ -2821,6 +2819,33 @@ void GMainWindow::OnConfigureTas() { } } +void GMainWindow::OnTasStartStop() { + if (!emulation_running) { + return; + } + input_subsystem->GetTas()->StartStop(); + OnTasStateChanged(); +} + +void GMainWindow::OnTasRecord() { + if (!emulation_running) { + return; + } + bool is_recording = input_subsystem->GetTas()->Record(); + if (!is_recording) { + const auto res = + QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"), + QMessageBox::Yes | QMessageBox::No); + input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); + } + OnTasStateChanged(); +} + +void GMainWindow::OnTasReset() { + input_subsystem->GetTas()->Reset(); +} + + void GMainWindow::OnConfigurePerGame() { const u64 title_id = system->GetCurrentProcessProgramID(); OpenPerGameConfiguration(title_id, game_path.toStdString()); @@ -3014,6 +3039,23 @@ QString GMainWindow::GetTasStateDescription() const { } } +void GMainWindow::OnTasStateChanged() { + bool is_running = false; + bool is_recording = false; + if (emulation_running) { + TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus()); + is_running = tas_status == TasInput::TasState::Running; + is_recording = tas_status == TasInput::TasState::Recording; + } + + ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start")); + ui->action_TAS_Record->setText(is_recording ? tr("Stop R&ecording") : tr("R&ecord")); + + ui->action_TAS_Start->setEnabled(emulation_running); + ui->action_TAS_Record->setEnabled(emulation_running); + ui->action_TAS_Reset->setEnabled(emulation_running); +} + void GMainWindow::UpdateStatusBar() { if (emu_thread == nullptr) { status_bar_update_timer.stop(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 24633ff2d..556cbbaf7 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -177,6 +177,7 @@ public slots: void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, bool is_local); void OnAppFocusStateChanged(Qt::ApplicationState state); + void OnTasStateChanged(); private: void RegisterMetaTypes(); @@ -268,6 +269,9 @@ private slots: void OnMenuRecentFile(); void OnConfigure(); void OnConfigureTas(); + void OnTasStartStop(); + void OnTasRecord(); + void OnTasReset(); void OnConfigurePerGame(); void OnLoadAmiibo(); void OnOpenYuzuFolder(); @@ -313,6 +317,7 @@ private: void OpenURL(const QUrl& url); void LoadTranslation(); void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); + QString GetTasStateDescription() const; std::unique_ptr ui; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index a62e39a06..c58aa2866 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -79,39 +79,39 @@ &View - - &Reset Window Size - + + &Reset Window Size + - - - Reset Window Size to &720p - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - Reset Window Size to 1080p - - &Debugging + + + Reset Window Size to &720p + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + Reset Window Size to 1080p + + @@ -125,10 +125,20 @@ &Tools + + + &TAS + + + + + + + - + @@ -309,7 +319,7 @@ - Configure &TAS... + &Configure TAS... @@ -320,6 +330,30 @@ Configure C&urrent Game... + + + false + + + &Start + + + + + false + + + &Reset + + + + + false + + + R&ecord + + From b7a938e817be3801f2c2c9f1b693ea7d008373b1 Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Sun, 21 Nov 2021 18:02:08 -0800 Subject: [PATCH 039/291] Apply clang format --- src/yuzu/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 73278f29f..42ee310cc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2845,7 +2845,6 @@ void GMainWindow::OnTasReset() { input_subsystem->GetTas()->Reset(); } - void GMainWindow::OnConfigurePerGame() { const u64 title_id = system->GetCurrentProcessProgramID(); OpenPerGameConfiguration(title_id, game_path.toStdString()); From 097de2febcf97da38c55235073eff834c529acac Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Sun, 21 Nov 2021 18:07:37 -0800 Subject: [PATCH 040/291] const fixes --- src/yuzu/bootmanager.cpp | 2 +- src/yuzu/main.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 105f36d33..fd0a130a3 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -320,7 +320,7 @@ GRenderWindow::~GRenderWindow() { void GRenderWindow::OnFrameDisplayed() { input_subsystem->GetTas()->UpdateThread(); - TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus()); + const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus()); if (!first_frame) { last_tas_state = new_tas_state; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 42ee310cc..5058c3e4e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2831,7 +2831,7 @@ void GMainWindow::OnTasRecord() { if (!emulation_running) { return; } - bool is_recording = input_subsystem->GetTas()->Record(); + const bool is_recording = input_subsystem->GetTas()->Record(); if (!is_recording) { const auto res = QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"), @@ -3042,7 +3042,7 @@ void GMainWindow::OnTasStateChanged() { bool is_running = false; bool is_recording = false; if (emulation_running) { - TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus()); + const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus()); is_running = tas_status == TasInput::TasState::Running; is_recording = tas_status == TasInput::TasState::Recording; } From 84eb3e7d02d386bc90eb4a6c6b6e33eea33a42e2 Mon Sep 17 00:00:00 2001 From: jam1garner <8260240+jam1garner@users.noreply.github.com> Date: Sun, 21 Nov 2021 21:10:14 -0500 Subject: [PATCH 041/291] arm: dynarmic: Implement icache op handling for 'ic ivau' instruction --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4e73cc03a..587fffb34 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -86,6 +86,24 @@ public: num_instructions, MemoryReadCode(pc)); } + void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, + VAddr value) override { + constexpr u64 ICACHE_LINE_SIZE = 64; + u64 cache_line_start; + + switch (op) { + case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: + cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); + parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); + return; + + case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: + case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: + default: + LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation"); + } + } + void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { switch (exception) { case Dynarmic::A64::Exception::WaitForInterrupt: From c8a67a725de6481c891d5bfe1b83fcb6340c88a3 Mon Sep 17 00:00:00 2001 From: jam1garner <8260240+jam1garner@users.noreply.github.com> Date: Sun, 21 Nov 2021 21:18:56 -0500 Subject: [PATCH 042/291] arm: dynarmic: Implement icache op handling for 'ic iallu' instruction --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 587fffb34..8fe83413c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -98,6 +98,9 @@ public: return; case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: + parent.ClearInstructionCache(); + return; + case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: default: LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation"); From 4d9c9e567ef6c44967b639471613a0328dcbf833 Mon Sep 17 00:00:00 2001 From: jam1garner <8260240+jam1garner@users.noreply.github.com> Date: Sun, 21 Nov 2021 21:24:07 -0500 Subject: [PATCH 043/291] arm: dynarmic: Cleanup icache op handling --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8fe83413c..56836bd05 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -88,22 +88,21 @@ public: void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, VAddr value) override { - constexpr u64 ICACHE_LINE_SIZE = 64; - u64 cache_line_start; - switch (op) { - case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: - cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); - parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); - return; + case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: { + static constexpr u64 ICACHE_LINE_SIZE = 64; + const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); + parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); + break; + } case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: parent.ClearInstructionCache(); - return; - + break; case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: default: - LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation"); + LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op); + break; } } From 08674aee87e385e5f2a3b8e1b9aa85a61e23a490 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 22 Nov 2021 06:07:21 +0100 Subject: [PATCH 044/291] Texture Cache: Fix issue with blitting 3D textures. --- src/video_core/texture_cache/util.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 777503488..9b1613008 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1155,11 +1155,13 @@ void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* if (src) { is_resolve = src->info.num_samples > 1; src_info.num_samples = src->info.num_samples; - src_info.size = src->info.size; + src_info.size.width = src->info.size.width; + src_info.size.height = src->info.size.height; } if (dst) { dst_info.num_samples = dst->info.num_samples; - dst_info.size = dst->info.size; + dst_info.size.width = dst->info.size.width; + dst_info.size.height = dst->info.size.height; } ASSERT(!is_resolve || dst_info.format == src_info.format); } From 72aa418b0b412855683633d2799da1eb190ab6d5 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Wed, 24 Nov 2021 17:23:57 -0700 Subject: [PATCH 045/291] video_core/codecs: fix multiple decoding issues on Linux ... * when someone installed Intel video drivers on an AMD system, the decoder will select the Intel VA-API decoding driver and yuzu will crash due to incorrect driver selection; the fix will check if the currently about-to-use driver is loaded in the kernel * when using NVIDIA driver on Linux with a ffmpeg that does not have CUDA capability enabled, the decoder will crash; the fix simply making the decoder prefers the VDPAU driver over CUDA on Linux --- .../command_classes/codecs/codec.cpp | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 916277811..403ce30fe 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include "common/assert.h" @@ -59,6 +60,36 @@ Codec::~Codec() { av_buffer_unref(&av_gpu_decoder); } +#ifdef LIBVA_FOUND +// List all the currently loaded Linux modules +static std::vector ListLinuxKernelModules() { + std::vector modules{}; + auto module_listing = fopen("/proc/modules", "rt"); + char* buffer = nullptr; + size_t buf_len = 0; + if (!module_listing) { + LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules"); + return modules; + } + while (getline(&buffer, &buf_len, module_listing) != -1) { + // format for the module listing file (sysfs) + // + auto line = std::string(buffer); + // we are only interested in module names + auto name_pos = line.find_first_of(" "); + if (name_pos == std::string::npos) { + continue; + } + modules.push_back(line.erase(name_pos + 1)); + } + if (buffer) { + free(buffer); + } + fclose(module_listing); + return modules; +} +#endif + bool Codec::CreateGpuAvDevice() { #if defined(LIBVA_FOUND) static constexpr std::array VAAPI_DRIVERS = { @@ -67,8 +98,21 @@ bool Codec::CreateGpuAvDevice() { "amdgpu", }; AVDictionary* hwdevice_options = nullptr; + auto loaded_modules = ListLinuxKernelModules(); av_dict_set(&hwdevice_options, "connection_type", "drm", 0); for (const auto& driver : VAAPI_DRIVERS) { + bool found = false; + // first check if the target driver is loaded in the kernel + for (const auto& module : loaded_modules) { + if (module == driver) { + found = true; + break; + } + } + if (!found) { + LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver); + continue; + } av_dict_set(&hwdevice_options, "kernel_driver", driver, 0); const int hwdevice_error = av_hwdevice_ctx_create(&av_gpu_decoder, AV_HWDEVICE_TYPE_VAAPI, nullptr, hwdevice_options, 0); @@ -85,11 +129,12 @@ bool Codec::CreateGpuAvDevice() { #endif static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; static constexpr std::array GPU_DECODER_TYPES{ +#ifdef linux + AV_HWDEVICE_TYPE_VDPAU, +#endif AV_HWDEVICE_TYPE_CUDA, #ifdef _WIN32 AV_HWDEVICE_TYPE_D3D11VA, -#else - AV_HWDEVICE_TYPE_VDPAU, #endif }; for (const auto& type : GPU_DECODER_TYPES) { From 60928cf8cd0d6f46826d588926969913d7fc6740 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Wed, 24 Nov 2021 18:00:55 -0700 Subject: [PATCH 046/291] video_core/codec: address comments --- .../command_classes/codecs/codec.cpp | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 403ce30fe..02d309170 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -63,15 +64,16 @@ Codec::~Codec() { #ifdef LIBVA_FOUND // List all the currently loaded Linux modules static std::vector ListLinuxKernelModules() { + using FILEPtr = std::unique_ptr; + auto module_listing = FILEPtr{fopen("/proc/modules", "rt"), std::fclose}; std::vector modules{}; - auto module_listing = fopen("/proc/modules", "rt"); - char* buffer = nullptr; - size_t buf_len = 0; if (!module_listing) { LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules"); return modules; } - while (getline(&buffer, &buf_len, module_listing) != -1) { + char* buffer = nullptr; + size_t buf_len = 0; + while (getline(&buffer, &buf_len, module_listing.get()) != -1) { // format for the module listing file (sysfs) // auto line = std::string(buffer); @@ -80,12 +82,9 @@ static std::vector ListLinuxKernelModules() { if (name_pos == std::string::npos) { continue; } - modules.push_back(line.erase(name_pos + 1)); + modules.push_back(line.erase(name_pos)); } - if (buffer) { - free(buffer); - } - fclose(module_listing); + free(buffer); return modules; } #endif @@ -98,17 +97,12 @@ bool Codec::CreateGpuAvDevice() { "amdgpu", }; AVDictionary* hwdevice_options = nullptr; - auto loaded_modules = ListLinuxKernelModules(); + const auto loaded_modules = ListLinuxKernelModules(); av_dict_set(&hwdevice_options, "connection_type", "drm", 0); for (const auto& driver : VAAPI_DRIVERS) { - bool found = false; // first check if the target driver is loaded in the kernel - for (const auto& module : loaded_modules) { - if (module == driver) { - found = true; - break; - } - } + bool found = std::any_of(loaded_modules.begin(), loaded_modules.end(), + [&driver](const auto& module) { return module == driver; }); if (!found) { LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver); continue; From f078d3d212a4b272012695762f3ce62eaa0db2ab Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Wed, 24 Nov 2021 18:27:25 -0800 Subject: [PATCH 047/291] Refactor menu states and shortcuts in GMainWindow. (#7419) Refactor menu states and shortcuts in GMainWindow. - Removed "Start", since it was always disabled unless it was "Continue" which has now been moved to "Pause". - Allow hotkeys to be used while in fullscreen. - Removed the load amiibo hotkey. --- src/yuzu/main.cpp | 393 ++++++++++++++++++++-------------------------- src/yuzu/main.h | 6 + src/yuzu/main.ui | 9 -- 3 files changed, 173 insertions(+), 235 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 5058c3e4e..88e84e8f7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -952,164 +952,80 @@ void GMainWindow::InitializeRecentFileMenuActions() { UpdateRecentFiles(); } +void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) { + static const QString main_window = QStringLiteral("Main Window"); + action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); + action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); + + this->addAction(action); +} + void GMainWindow::InitializeHotkeys() { hotkey_registry.LoadHotkeys(); - const QString main_window = QStringLiteral("Main Window"); - const QString load_file = QStringLiteral("Load File"); - const QString load_amiibo = QStringLiteral("Load Amiibo"); - const QString exit_yuzu = QStringLiteral("Exit yuzu"); - const QString restart_emulation = QStringLiteral("Restart Emulation"); - const QString stop_emulation = QStringLiteral("Stop Emulation"); - const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); - const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); - const QString fullscreen = QStringLiteral("Fullscreen"); - const QString capture_screenshot = QStringLiteral("Capture Screenshot"); - const QString tas_start_stop = QStringLiteral("TAS Start/Stop"); - const QString tas_record = QStringLiteral("TAS Record"); - const QString tas_reset = QStringLiteral("TAS Reset"); + LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File")); + LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load Amiibo")); + LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu")); + LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation")); + LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation")); + LinkActionShortcut(ui->action_Stop, QStringLiteral("Stop Emulation")); + LinkActionShortcut(ui->action_Show_Filter_Bar, QStringLiteral("Toggle Filter Bar")); + LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar")); + LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen")); + LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot")); + LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop")); + LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record")); + LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset")); - ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); - ui->action_Load_File->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, load_file)); + static const QString main_window = QStringLiteral("Main Window"); + const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { + const QShortcut* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this); + connect(hotkey, &QShortcut::activated, this, function); + }; - ui->action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo)); - ui->action_Load_Amiibo->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, load_amiibo)); - - ui->action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); - ui->action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); - - ui->action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation)); - ui->action_Restart->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, restart_emulation)); - - ui->action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); - ui->action_Stop->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, stop_emulation)); - - ui->action_Show_Filter_Bar->setShortcut( - hotkey_registry.GetKeySequence(main_window, toggle_filter_bar)); - ui->action_Show_Filter_Bar->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar)); - - ui->action_Show_Status_Bar->setShortcut( - hotkey_registry.GetKeySequence(main_window, toggle_status_bar)); - ui->action_Show_Status_Bar->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); - - ui->action_Capture_Screenshot->setShortcut( - hotkey_registry.GetKeySequence(main_window, capture_screenshot)); - ui->action_Capture_Screenshot->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); - - ui->action_Fullscreen->setShortcut( - hotkey_registry.GetHotkey(main_window, fullscreen, this)->key()); - ui->action_Fullscreen->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, fullscreen)); - - ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop)); - ui->action_TAS_Start->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, tas_start_stop)); - - ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record)); - ui->action_TAS_Record->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, tas_record)); - - ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset)); - ui->action_TAS_Reset->setShortcutContext( - hotkey_registry.GetShortcutContext(main_window, tas_reset)); - - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), - &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); - connect( - hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this), - &QShortcut::activated, this, [&] { - if (emulation_running) { - if (emu_thread->IsRunning()) { - OnPauseGame(); - } else { - OnStartGame(); - } - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this), - &QShortcut::activated, this, [this] { - if (!system->IsPoweredOn()) { - return; - } - BootGame(game_path); - }); - connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), - &QShortcut::activated, ui->action_Fullscreen, &QAction::trigger); - connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), - &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this), - &QShortcut::activated, this, [&] { - if (emulation_running && ui->action_Fullscreen->isChecked()) { - ui->action_Fullscreen->setChecked(false); - ToggleFullscreen(); - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), - &QShortcut::activated, this, [&] { - Settings::values.use_speed_limit.SetValue( - !Settings::values.use_speed_limit.GetValue()); - UpdateStatusBar(); - }); + connect_shortcut(QStringLiteral("Exit Fullscreen"), [&] { + if (emulation_running && ui->action_Fullscreen->isChecked()) { + ui->action_Fullscreen->setChecked(false); + ToggleFullscreen(); + } + }); + connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] { + Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); + UpdateStatusBar(); + }); constexpr u16 SPEED_LIMIT_STEP = 5; - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), - &QShortcut::activated, this, [&] { - if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { - Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP + - Settings::values.speed_limit.GetValue()); - UpdateStatusBar(); - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), - &QShortcut::activated, this, [&] { - if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) { - Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() - - SPEED_LIMIT_STEP); - UpdateStatusBar(); - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this), - &QShortcut::activated, this, [&] { - if (ui->action_Load_Amiibo->isEnabled()) { - OnLoadAmiibo(); - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this), - &QShortcut::activated, this, [&] { - if (emu_thread != nullptr && emu_thread->IsRunning()) { - OnCaptureScreenshot(); - } - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this), - &QShortcut::activated, this, [&] { - Settings::values.use_docked_mode.SetValue( - !Settings::values.use_docked_mode.GetValue()); - OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(), - Settings::values.use_docked_mode.GetValue(), *system); - dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this), - &QShortcut::activated, this, - [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Framerate Limit"), this), - &QShortcut::activated, this, [] { - Settings::values.disable_fps_limit.SetValue( - !Settings::values.disable_fps_limit.GetValue()); - }); - connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), - &QShortcut::activated, this, [&] { - Settings::values.mouse_panning = !Settings::values.mouse_panning; - if (Settings::values.mouse_panning) { - render_window->installEventFilter(render_window); - render_window->setAttribute(Qt::WA_Hover, true); - } - }); + connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] { + if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { + Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP + + Settings::values.speed_limit.GetValue()); + UpdateStatusBar(); + } + }); + connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] { + if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) { + Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() - + SPEED_LIMIT_STEP); + UpdateStatusBar(); + } + }); + connect_shortcut(QStringLiteral("Change Docked Mode"), [&] { + Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue()); + OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(), + Settings::values.use_docked_mode.GetValue(), *system); + dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); + }); + connect_shortcut(QStringLiteral("Mute Audio"), + [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); + connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { + Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue()); + }); + connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { + Settings::values.mouse_panning = !Settings::values.mouse_panning; + if (Settings::values.mouse_panning) { + render_window->installEventFilter(render_window); + render_window->setAttribute(Qt::WA_Hover, true); + } + }); } void GMainWindow::SetDefaultUIGeometry() { @@ -1164,7 +1080,8 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { auto_paused = true; OnPauseGame(); - } else if (ui->action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) { + } else if (emulation_running && !emu_thread->IsRunning() && auto_paused && + state == Qt::ApplicationActive) { auto_paused = false; OnStartGame(); } @@ -1208,64 +1125,86 @@ void GMainWindow::ConnectWidgetEvents() { } void GMainWindow::ConnectMenuEvents() { + const auto connect_menu = [&](QAction* action, const Fn& event_fn) { + connect(action, &QAction::triggered, this, event_fn); + // Add actions to this window so that hiding menus in fullscreen won't disable them + addAction(action); + // Add actions to the render window so that they work outside of single window mode + render_window->addAction(action); + }; + // File - connect(ui->action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); - connect(ui->action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); - connect(ui->action_Install_File_NAND, &QAction::triggered, this, - &GMainWindow::OnMenuInstallToNAND); - connect(ui->action_Exit, &QAction::triggered, this, &QMainWindow::close); - connect(ui->action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo); + connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile); + connect_menu(ui->action_Load_Folder, &GMainWindow::OnMenuLoadFolder); + connect_menu(ui->action_Install_File_NAND, &GMainWindow::OnMenuInstallToNAND); + connect_menu(ui->action_Exit, &QMainWindow::close); + connect_menu(ui->action_Load_Amiibo, &GMainWindow::OnLoadAmiibo); // Emulation - connect(ui->action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); - connect(ui->action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame); - connect(ui->action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); - connect(ui->action_Report_Compatibility, &QAction::triggered, this, - &GMainWindow::OnMenuReportCompatibility); - connect(ui->action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); - connect(ui->action_Open_Quickstart_Guide, &QAction::triggered, this, - &GMainWindow::OnOpenQuickstartGuide); - connect(ui->action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); - connect(ui->action_Restart, &QAction::triggered, this, - [this] { BootGame(QString(game_path)); }); - connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); - connect(ui->action_Configure_Current_Game, &QAction::triggered, this, - &GMainWindow::OnConfigurePerGame); + connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame); + connect_menu(ui->action_Stop, &GMainWindow::OnStopGame); + connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility); + connect_menu(ui->action_Open_Mods_Page, &GMainWindow::OnOpenModsPage); + connect_menu(ui->action_Open_Quickstart_Guide, &GMainWindow::OnOpenQuickstartGuide); + connect_menu(ui->action_Open_FAQ, &GMainWindow::OnOpenFAQ); + connect_menu(ui->action_Restart, &GMainWindow::OnRestartGame); + connect_menu(ui->action_Configure, &GMainWindow::OnConfigure); + connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame); // View - connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); - connect(ui->action_Single_Window_Mode, &QAction::triggered, this, - &GMainWindow::ToggleWindowMode); - connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this, - &GMainWindow::OnDisplayTitleBars); - connect(ui->action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); + connect_menu(ui->action_Fullscreen, &GMainWindow::ToggleFullscreen); + connect_menu(ui->action_Single_Window_Mode, &GMainWindow::ToggleWindowMode); + connect_menu(ui->action_Display_Dock_Widget_Headers, &GMainWindow::OnDisplayTitleBars); + connect_menu(ui->action_Show_Filter_Bar, &GMainWindow::OnToggleFilterBar); + connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); - connect(ui->action_Reset_Window_Size_720, &QAction::triggered, this, - &GMainWindow::ResetWindowSize720); - connect(ui->action_Reset_Window_Size_900, &QAction::triggered, this, - &GMainWindow::ResetWindowSize900); - connect(ui->action_Reset_Window_Size_1080, &QAction::triggered, this, - &GMainWindow::ResetWindowSize1080); - ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_720); - ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900); - ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080); + connect_menu(ui->action_Reset_Window_Size_720, &GMainWindow::ResetWindowSize720); + connect_menu(ui->action_Reset_Window_Size_900, &GMainWindow::ResetWindowSize900); + connect_menu(ui->action_Reset_Window_Size_1080, &GMainWindow::ResetWindowSize1080); + ui->menu_Reset_Window_Size->addActions({ui->action_Reset_Window_Size_720, + ui->action_Reset_Window_Size_900, + ui->action_Reset_Window_Size_1080}); // Tools - connect(ui->action_Rederive, &QAction::triggered, this, - std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); - connect(ui->action_Capture_Screenshot, &QAction::triggered, this, - &GMainWindow::OnCaptureScreenshot); + connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, + ReinitializeKeyBehavior::Warning)); + connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot); // TAS - connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop); - connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord); - connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset); - connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); + connect_menu(ui->action_TAS_Start, &GMainWindow::OnTasStartStop); + connect_menu(ui->action_TAS_Record, &GMainWindow::OnTasRecord); + connect_menu(ui->action_TAS_Reset, &GMainWindow::OnTasReset); + connect_menu(ui->action_Configure_Tas, &GMainWindow::OnConfigureTas); // Help - connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); - connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout); + connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); + connect_menu(ui->action_About, &GMainWindow::OnAbout); +} + +void GMainWindow::UpdateMenuState() { + const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning(); + + const std::array running_actions{ + ui->action_Stop, + ui->action_Restart, + ui->action_Configure_Current_Game, + ui->action_Report_Compatibility, + ui->action_Load_Amiibo, + ui->action_Pause, + }; + + for (QAction* action : running_actions) { + action->setEnabled(emulation_running); + } + + ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused); + + if (emulation_running && is_paused) { + ui->action_Pause->setText(tr("&Continue")); + } else { + ui->action_Pause->setText(tr("&Pause")); + } } void GMainWindow::OnDisplayTitleBars(bool show) { @@ -1558,15 +1497,8 @@ void GMainWindow::ShutdownGame() { disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); // Update the GUI - ui->action_Start->setEnabled(false); - ui->action_Start->setText(tr("Start")); - ui->action_Pause->setEnabled(false); - ui->action_Stop->setEnabled(false); - ui->action_Restart->setEnabled(false); - ui->action_Configure_Current_Game->setEnabled(false); - ui->action_Report_Compatibility->setEnabled(false); - ui->action_Load_Amiibo->setEnabled(false); - ui->action_Capture_Screenshot->setEnabled(false); + UpdateMenuState(); + render_window->hide(); loading_screen->hide(); loading_screen->Clear(); @@ -2498,32 +2430,36 @@ void GMainWindow::OnStartGame() { connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); - ui->action_Start->setEnabled(false); - ui->action_Start->setText(tr("&Continue")); - - ui->action_Pause->setEnabled(true); - ui->action_Stop->setEnabled(true); - ui->action_Restart->setEnabled(true); - ui->action_Configure_Current_Game->setEnabled(true); - ui->action_Report_Compatibility->setEnabled(true); + UpdateMenuState(); OnTasStateChanged(); discord_rpc->Update(); - ui->action_Load_Amiibo->setEnabled(true); - ui->action_Capture_Screenshot->setEnabled(true); +} + +void GMainWindow::OnRestartGame() { + if (!system->IsPoweredOn()) { + return; + } + // Make a copy since BootGame edits game_path + BootGame(QString(game_path)); } void GMainWindow::OnPauseGame() { emu_thread->SetRunning(false); - - ui->action_Start->setEnabled(true); - ui->action_Pause->setEnabled(false); - ui->action_Stop->setEnabled(true); - ui->action_Capture_Screenshot->setEnabled(false); - + UpdateMenuState(); AllowOSSleep(); } +void GMainWindow::OnPauseContinueGame() { + if (emulation_running) { + if (emu_thread->IsRunning()) { + OnPauseGame(); + } else { + OnStartGame(); + } + } +} + void GMainWindow::OnStopGame() { if (system->GetExitLock() && !ConfirmForceLockedExit()) { return; @@ -2882,6 +2818,10 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } void GMainWindow::OnLoadAmiibo() { + if (emu_thread == nullptr || !emu_thread->IsRunning()) { + return; + } + const QString extensions{QStringLiteral("*.bin")}; const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter); @@ -2945,6 +2885,10 @@ void GMainWindow::OnToggleFilterBar() { } void GMainWindow::OnCaptureScreenshot() { + if (emu_thread == nullptr || !emu_thread->IsRunning()) { + return; + } + const u64 title_id = system->GetCurrentProcessProgramID(); const auto screenshot_path = QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)); @@ -3593,9 +3537,6 @@ void GMainWindow::OnLanguageChanged(const QString& locale) { LoadTranslation(); ui->retranslateUi(this); UpdateWindowTitle(); - - if (emulation_running) - ui->action_Start->setText(tr("&Continue")); } void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 556cbbaf7..0fd41ed4f 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -191,6 +191,7 @@ private: void ConnectWidgetEvents(); void ConnectMenuEvents(); + void UpdateMenuState(); void PreventOSSleep(); void AllowOSSleep(); @@ -240,7 +241,9 @@ private: private slots: void OnStartGame(); + void OnRestartGame(); void OnPauseGame(); + void OnPauseContinueGame(); void OnStopGame(); void OnMenuReportCompatibility(); void OnOpenModsPage(); @@ -294,6 +297,9 @@ private slots: void OnMouseActivity(); private: + /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry. + void LinkActionShortcut(QAction* action, const QString& action_name); + void RemoveBaseContent(u64 program_id, const QString& entry_type); void RemoveUpdateContent(u64 program_id, const QString& entry_type); void RemoveAddOnContent(u64 program_id, const QString& entry_type); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index c58aa2866..5719b2ee4 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -66,7 +66,6 @@ &Emulation - @@ -180,14 +179,6 @@ E&xit - - - false - - - &Start - - false From ad5142ac2c56aded4090ad031a9351cd188caacf Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 14:56:55 -0500 Subject: [PATCH 048/291] common: Rewrite and move core/frontend/input.h to common --- src/common/CMakeLists.txt | 1 + src/common/input.h | 242 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 src/common/input.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 23d43a394..919da4a53 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -73,6 +73,7 @@ add_library(common STATIC hex_util.h host_memory.cpp host_memory.h + input.h intrusive_red_black_tree.h literals.h logging/backend.cpp diff --git a/src/common/input.h b/src/common/input.h new file mode 100644 index 000000000..6eefc55f9 --- /dev/null +++ b/src/common/input.h @@ -0,0 +1,242 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include "common/logging/log.h" +#include "common/param_package.h" + +namespace Input { + +enum class InputType { + None, + Battery, + Button, + Stick, + Analog, + Trigger, + Motion, + Touch, + Color, + Vibration, + Nfc, + Ir, +}; + +enum class BatteryLevel { + Empty, + Critical, + Low, + Medium, + Full, + Charging, +}; + +struct AnalogProperties { + float deadzone{}; + float range{1.0f}; + float threshold{0.5f}; + float offset{}; + bool inverted{}; +}; + +struct AnalogStatus { + float value{}; + float raw_value{}; + AnalogProperties properties{}; +}; + +struct ButtonStatus { + bool value{}; + bool inverted{}; + bool toggle{}; + bool locked{}; +}; + +using BatteryStatus = BatteryLevel; + +struct StickStatus { + AnalogStatus x{}; + AnalogStatus y{}; + bool left{}; + bool right{}; + bool up{}; + bool down{}; +}; + +struct TriggerStatus { + AnalogStatus analog{}; + bool pressed{}; +}; + +struct MotionSensor { + AnalogStatus x{}; + AnalogStatus y{}; + AnalogStatus z{}; +}; + +struct MotionStatus { + MotionSensor gyro{}; + MotionSensor accel{}; + u64 delta_timestamp{}; +}; + +struct TouchStatus { + ButtonStatus pressed{}; + AnalogStatus x{}; + AnalogStatus y{}; + u32 id{}; +}; + +struct BodyColorStatus { + u32 body{}; + u32 buttons{}; +}; + +struct VibrationStatus { + f32 low_amplitude{}; + f32 low_frequency{}; + f32 high_amplitude{}; + f32 high_frequency{}; +}; + +struct LedStatus { + bool led_1{}; + bool led_2{}; + bool led_3{}; + bool led_4{}; +}; + +struct CallbackStatus { + InputType type{InputType::None}; + ButtonStatus button_status{}; + StickStatus stick_status{}; + AnalogStatus analog_status{}; + TriggerStatus trigger_status{}; + MotionStatus motion_status{}; + TouchStatus touch_status{}; + BodyColorStatus color_status{}; + BatteryStatus battery_status{}; + VibrationStatus vibration_status{}; +}; + +struct InputCallback { + std::function on_change; +}; + +/// An abstract class template for an input device (a button, an analog input, etc.). +class InputDevice { +public: + virtual ~InputDevice() = default; + + void SetCallback(InputCallback callback_) { + callback = std::move(callback_); + } + + void TriggerOnChange(CallbackStatus status) { + if (callback.on_change) { + callback.on_change(status); + } + } + +private: + InputCallback callback; +}; + +/// An abstract class template for a factory that can create input devices. +template +class Factory { +public: + virtual ~Factory() = default; + virtual std::unique_ptr Create(const Common::ParamPackage&) = 0; +}; + +namespace Impl { + +template +using FactoryListType = std::unordered_map>>; + +template +struct FactoryList { + static FactoryListType list; +}; + +template +FactoryListType FactoryList::list; + +} // namespace Impl + +/** + * Registers an input device factory. + * @tparam InputDeviceType the type of input devices the factory can create + * @param name the name of the factory. Will be used to match the "engine" parameter when creating + * a device + * @param factory the factory object to register + */ +template +void RegisterFactory(const std::string& name, std::shared_ptr> factory) { + auto pair = std::make_pair(name, std::move(factory)); + if (!Impl::FactoryList::list.insert(std::move(pair)).second) { + LOG_ERROR(Input, "Factory '{}' already registered", name); + } +} + +/** + * Unregisters an input device factory. + * @tparam InputDeviceType the type of input devices the factory can create + * @param name the name of the factory to unregister + */ +template +void UnregisterFactory(const std::string& name) { + if (Impl::FactoryList::list.erase(name) == 0) { + LOG_ERROR(Input, "Factory '{}' not registered", name); + } +} + +/** + * Create an input device from given paramters. + * @tparam InputDeviceType the type of input devices to create + * @param params a serialized ParamPackage string that contains all parameters for creating the + * device + */ +template +std::unique_ptr CreateDeviceFromString(const std::string& params) { + const Common::ParamPackage package(params); + const std::string engine = package.Get("engine", "null"); + const auto& factory_list = Impl::FactoryList::list; + const auto pair = factory_list.find(engine); + if (pair == factory_list.end()) { + if (engine != "null") { + LOG_ERROR(Input, "Unknown engine name: {}", engine); + } + return std::make_unique(); + } + return pair->second->Create(package); +} + +/** + * Create an input device from given paramters. + * @tparam InputDeviceType the type of input devices to create + * @param A ParamPackage that contains all parameters for creating the device + */ +template +std::unique_ptr CreateDevice(const Common::ParamPackage package) { + const std::string engine = package.Get("engine", "null"); + const auto& factory_list = Impl::FactoryList::list; + const auto pair = factory_list.find(engine); + if (pair == factory_list.end()) { + if (engine != "null") { + LOG_ERROR(Input, "Unknown engine name: {}", engine); + } + return std::make_unique(); + } + return pair->second->Create(package); +} + +} // namespace Input From bf71d18af99368d7658c9519086c40e73c6abfdd Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 15:02:01 -0500 Subject: [PATCH 049/291] core/hid: Move input_interpreter to hid --- src/core/CMakeLists.txt | 4 ++-- src/core/{frontend => hid}/input_interpreter.cpp | 2 +- src/core/{frontend => hid}/input_interpreter.h | 0 src/yuzu/applets/qt_web_browser.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/core/{frontend => hid}/input_interpreter.cpp (97%) rename src/core/{frontend => hid}/input_interpreter.h (100%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9f0fbba2d..14ba986d3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -132,11 +132,11 @@ add_library(core STATIC frontend/emu_window.h frontend/framebuffer_layout.cpp frontend/framebuffer_layout.h - frontend/input_interpreter.cpp - frontend/input_interpreter.h frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h + hid/input_interpreter.cpp + hid/input_interpreter.h hle/api_version.h hle/ipc.h hle/ipc_helpers.h diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp similarity index 97% rename from src/core/frontend/input_interpreter.cpp rename to src/core/hid/input_interpreter.cpp index 9f6a90e8f..c33d8a11a 100644 --- a/src/core/frontend/input_interpreter.cpp +++ b/src/core/hid/input_interpreter.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include "core/core.h" -#include "core/frontend/input_interpreter.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/sm/sm.h" diff --git a/src/core/frontend/input_interpreter.h b/src/core/hid/input_interpreter.h similarity index 100% rename from src/core/frontend/input_interpreter.h rename to src/core/hid/input_interpreter.h diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index da8c6882a..24d72a496 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -15,7 +15,7 @@ #include "common/fs/path_util.h" #include "core/core.h" -#include "core/frontend/input_interpreter.h" +#include "core/hid/input_interpreter.h" #include "input_common/keyboard.h" #include "input_common/main.h" #include "yuzu/applets/qt_web_browser.h" From 449576df93f6beb70cff0e009ccb2dd8bce1e085 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 16:29:43 -0500 Subject: [PATCH 050/291] core/hid: Move motion_input, create input converter and hid_types --- src/core/CMakeLists.txt | 5 + src/core/hid/hid_types.h | 388 +++++++++++++++++++++++++++++++ src/core/hid/input_converter.cpp | 345 +++++++++++++++++++++++++++ src/core/hid/input_converter.h | 77 ++++++ src/core/hid/motion_input.cpp | 278 ++++++++++++++++++++++ src/core/hid/motion_input.h | 71 ++++++ 6 files changed, 1164 insertions(+) create mode 100644 src/core/hid/hid_types.h create mode 100644 src/core/hid/input_converter.cpp create mode 100644 src/core/hid/input_converter.h create mode 100644 src/core/hid/motion_input.cpp create mode 100644 src/core/hid/motion_input.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 14ba986d3..eddf455c0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -135,8 +135,13 @@ add_library(core STATIC frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h + hid/hid_types.h + hid/input_converter.cpp + hid/input_converter.h hid/input_interpreter.cpp hid/input_interpreter.h + hid/motion_input.cpp + hid/motion_input.h hle/api_version.h hle/ipc.h hle/ipc_helpers.h diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h new file mode 100644 index 000000000..d3f7930c9 --- /dev/null +++ b/src/core/hid/hid_types.h @@ -0,0 +1,388 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/point.h" +#include "common/uuid.h" + +namespace Core::HID { + +// This is nn::hid::NpadIdType +enum class NpadIdType : u8 { + Player1 = 0x0, + Player2 = 0x1, + Player3 = 0x2, + Player4 = 0x3, + Player5 = 0x4, + Player6 = 0x5, + Player7 = 0x6, + Player8 = 0x7, + Other = 0x10, + Handheld = 0x20, + + Invalid = 0xFF, +}; + +/// Converts a NpadIdType to an array index. +constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { + switch (npad_id_type) { + case NpadIdType::Player1: + return 0; + case NpadIdType::Player2: + return 1; + case NpadIdType::Player3: + return 2; + case NpadIdType::Player4: + return 3; + case NpadIdType::Player5: + return 4; + case NpadIdType::Player6: + return 5; + case NpadIdType::Player7: + return 6; + case NpadIdType::Player8: + return 7; + case NpadIdType::Other: + return 8; + case NpadIdType::Handheld: + return 9; + default: + return 0; + } +} + +/// Converts an array index to a NpadIdType +constexpr NpadIdType IndexToNpadIdType(size_t index) { + switch (index) { + case 0: + return NpadIdType::Player1; + case 1: + return NpadIdType::Player2; + case 2: + return NpadIdType::Player3; + case 3: + return NpadIdType::Player4; + case 4: + return NpadIdType::Player5; + case 5: + return NpadIdType::Player6; + case 6: + return NpadIdType::Player7; + case 7: + return NpadIdType::Player8; + case 8: + return NpadIdType::Other; + case 9: + return NpadIdType::Handheld; + default: + return NpadIdType::Invalid; + } +} + +// This is nn::hid::NpadType +enum class NpadType : u8 { + None = 0, + ProController = 3, + Handheld = 4, + JoyconDual = 5, + JoyconLeft = 6, + JoyconRight = 7, + GameCube = 8, + Pokeball = 9, + MaxNpadType = 10, +}; + +// This is nn::hid::NpadStyleTag +struct NpadStyleTag { + union { + u32_le raw{}; + + BitField<0, 1, u32> fullkey; + BitField<1, 1, u32> handheld; + BitField<2, 1, u32> joycon_dual; + BitField<3, 1, u32> joycon_left; + BitField<4, 1, u32> joycon_right; + BitField<5, 1, u32> gamecube; + BitField<6, 1, u32> palma; + BitField<7, 1, u32> lark; + BitField<8, 1, u32> handheld_lark; + BitField<9, 1, u32> lucia; + BitField<29, 1, u32> system_ext; + BitField<30, 1, u32> system; + }; +}; +static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size"); + +// This is nn::hid::TouchAttribute +struct TouchAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> start_touch; + BitField<1, 1, u32> end_touch; + }; +}; +static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size"); + +// This is nn::hid::TouchState +struct TouchState { + u64_le delta_time; + TouchAttribute attribute; + u32_le finger; + Common::Point position; + u32_le diameter_x; + u32_le diameter_y; + u32_le rotation_angle; +}; +static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); + +// This is nn::hid::NpadControllerColor +struct NpadControllerColor { + u32_le body; + u32_le button; +}; +static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); + +// This is nn::hid::AnalogStickState +struct AnalogStickState { + s32_le x; + s32_le y; +}; +static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size"); + +// This is nn::hid::server::NpadGcTriggerState +struct NpadGcTriggerState { + s64_le sampling_number{}; + s32_le left{}; + s32_le right{}; +}; +static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); + +// This is nn::hid::system::NpadBatteryLevel +using BatteryLevel = u32; +static_assert(sizeof(BatteryLevel) == 0x4, "BatteryLevel is an invalid size"); + +// This is nn::hid::system::NpadPowerInfo +struct NpadPowerInfo { + bool is_powered; + bool is_charging; + INSERT_PADDING_BYTES(0x6); + BatteryLevel battery_level; +}; +static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); + +// This is nn::hid::NpadButton +enum class NpadButton : u64 { + None = 0, + A = 1U << 0, + B = 1U << 1, + X = 1U << 2, + Y = 1U << 3, + StickL = 1U << 4, + StickR = 1U << 5, + L = 1U << 6, + R = 1U << 7, + ZL = 1U << 8, + ZR = 1U << 9, + Plus = 1U << 10, + Minus = 1U << 11, + + Left = 1U << 12, + Up = 1U << 13, + Right = 1U << 14, + Down = 1U << 15, + + StickLLeft = 1U << 16, + StickLUp = 1U << 17, + StickLRight = 1U << 18, + StickLDown = 1U << 19, + + StickRLeft = 1U << 20, + StickRUp = 1U << 21, + StickRRight = 1U << 22, + StickRDown = 1U << 23, + + LeftSL = 1U << 24, + LeftSR = 1U << 25, + + RightSL = 1U << 26, + RightSR = 1U << 27, + + Palma = 1U << 28, + HandheldLeftB = 1U << 30, +}; +DECLARE_ENUM_FLAG_OPERATORS(NpadButton); + +struct NpadButtonState { + union { + NpadButton raw{}; + + // Buttons + BitField<0, 1, u64> a; + BitField<1, 1, u64> b; + BitField<2, 1, u64> x; + BitField<3, 1, u64> y; + BitField<4, 1, u64> stick_l; + BitField<5, 1, u64> stick_r; + BitField<6, 1, u64> l; + BitField<7, 1, u64> r; + BitField<8, 1, u64> zl; + BitField<9, 1, u64> zr; + BitField<10, 1, u64> plus; + BitField<11, 1, u64> minus; + + // D-Pad + BitField<12, 1, u64> left; + BitField<13, 1, u64> up; + BitField<14, 1, u64> right; + BitField<15, 1, u64> down; + + // Left JoyStick + BitField<16, 1, u64> stick_l_left; + BitField<17, 1, u64> stick_l_up; + BitField<18, 1, u64> stick_l_right; + BitField<19, 1, u64> stick_l_down; + + // Right JoyStick + BitField<20, 1, u64> stick_r_left; + BitField<21, 1, u64> stick_r_up; + BitField<22, 1, u64> stick_r_right; + BitField<23, 1, u64> stick_r_down; + + BitField<24, 1, u64> left_sl; + BitField<25, 1, u64> left_sr; + + BitField<26, 1, u64> right_sl; + BitField<27, 1, u64> right_sr; + + BitField<28, 1, u64> palma; + BitField<30, 1, u64> handheld_left_b; + }; +}; +static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect size."); + +// This is nn::hid::DebugPadButton +struct DebugPadButton { + union { + u32_le raw{}; + BitField<0, 1, u32> a; + BitField<1, 1, u32> b; + BitField<2, 1, u32> x; + BitField<3, 1, u32> y; + BitField<4, 1, u32> l; + BitField<5, 1, u32> r; + BitField<6, 1, u32> zl; + BitField<7, 1, u32> zr; + BitField<8, 1, u32> plus; + BitField<9, 1, u32> minus; + BitField<10, 1, u32> d_left; + BitField<11, 1, u32> d_up; + BitField<12, 1, u32> d_right; + BitField<13, 1, u32> d_down; + }; +}; +static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"); + +// This is nn::hid::VibrationDeviceType +enum class VibrationDeviceType : u32 { + Unknown = 0, + LinearResonantActuator = 1, + GcErm = 2, +}; + +// This is nn::hid::VibrationDevicePosition +enum class VibrationDevicePosition : u32 { + None = 0, + Left = 1, + Right = 2, +}; + +// This is nn::hid::VibrationValue +struct VibrationValue { + f32 low_amplitude; + f32 low_frequency; + f32 high_amplitude; + f32 high_frequency; +}; +static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); + +// This is nn::hid::VibrationGcErmCommand +enum class VibrationGcErmCommand : u64 { + Stop = 0, + Start = 1, + StopHard = 2, +}; + +// This is nn::hid::VibrationDeviceInfo +struct VibrationDeviceInfo { + VibrationDeviceType type{}; + VibrationDevicePosition position{}; +}; +static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); + +// This is nn::hid::KeyboardModifier +struct KeyboardModifier { + union { + u32_le raw{}; + BitField<0, 1, u32> control; + BitField<1, 1, u32> shift; + BitField<2, 1, u32> left_alt; + BitField<3, 1, u32> right_alt; + BitField<4, 1, u32> gui; + BitField<8, 1, u32> caps_lock; + BitField<9, 1, u32> scroll_lock; + BitField<10, 1, u32> num_lock; + BitField<11, 1, u32> katakana; + BitField<12, 1, u32> hiragana; + }; +}; +static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size"); + +// This is nn::hid::KeyboardKey +struct KeyboardKey { + // This should be a 256 bit flag + std::array key; +}; +static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size"); + +// This is nn::hid::MouseButton +struct MouseButton { + union { + u32_le raw{}; + BitField<0, 1, u32> left; + BitField<1, 1, u32> right; + BitField<2, 1, u32> middle; + BitField<3, 1, u32> forward; + BitField<4, 1, u32> back; + }; +}; +static_assert(sizeof(MouseButton) == 0x4, "MouseButton is an invalid size"); + +// This is nn::hid::MouseAttribute +struct MouseAttribute { + union { + u32_le raw{}; + BitField<0, 1, u32> transferable; + BitField<1, 1, u32> is_connected; + }; +}; +static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size"); + +// This is nn::hid::detail::MouseState +struct MouseState { + s64_le sampling_number; + s32_le x; + s32_le y; + s32_le delta_x; + s32_le delta_y; + s32_le delta_wheel_x; + s32_le delta_wheel_y; + MouseButton button; + MouseAttribute attribute; +}; +static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); +} // namespace Core::HID diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp new file mode 100644 index 000000000..5834622e9 --- /dev/null +++ b/src/core/hid/input_converter.cpp @@ -0,0 +1,345 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include + +#include "common/input.h" +#include "core/hid/input_converter.h" + +namespace Core::HID { + +Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { + Input::BatteryStatus battery{}; + switch (callback.type) { + case Input::InputType::Analog: + case Input::InputType::Trigger: { + const auto value = TransformToTrigger(callback).analog.value; + battery = Input::BatteryLevel::Empty; + if (value > 0.2f) { + battery = Input::BatteryLevel::Critical; + } + if (value > 0.4f) { + battery = Input::BatteryLevel::Low; + } + if (value > 0.6f) { + battery = Input::BatteryLevel::Medium; + } + if (value > 0.8f) { + battery = Input::BatteryLevel::Full; + } + if (value >= 1.0f) { + battery = Input::BatteryLevel::Charging; + } + break; + } + case Input::InputType::Battery: + battery = callback.battery_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type); + break; + } + + return battery; +} + +Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) { + Input::ButtonStatus status{}; + switch (callback.type) { + case Input::InputType::Analog: + case Input::InputType::Trigger: + status.value = TransformToTrigger(callback).pressed; + break; + case Input::InputType::Button: + status = callback.button_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type); + break; + } + + if (status.inverted) { + status.value = !status.value; + } + + return status; +} + +Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { + Input::MotionStatus status{}; + switch (callback.type) { + case Input::InputType::Button: { + if (TransformToButton(callback).value) { + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution distribution(-1000, 1000); + Input::AnalogProperties properties{ + .deadzone = 0.0, + .range = 1.0f, + .offset = 0.0, + }; + status.accel.x = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + status.accel.y = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + status.accel.z = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + status.gyro.x = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + status.gyro.y = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + status.gyro.z = { + .value = 0, + .raw_value = static_cast(distribution(gen)) * 0.001f, + .properties = properties, + }; + } + break; + } + case Input::InputType::Motion: + status = callback.motion_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type); + break; + } + SanitizeAnalog(status.accel.x, false); + SanitizeAnalog(status.accel.y, false); + SanitizeAnalog(status.accel.z, false); + SanitizeAnalog(status.gyro.x, false); + SanitizeAnalog(status.gyro.y, false); + SanitizeAnalog(status.gyro.z, false); + + return status; +} + +Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { + Input::StickStatus status{}; + + switch (callback.type) { + case Input::InputType::Stick: + status = callback.stick_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type); + break; + } + + SanitizeStick(status.x, status.y, true); + const Input::AnalogProperties& properties_x = status.x.properties; + const Input::AnalogProperties& properties_y = status.y.properties; + const float x = status.x.value; + const float y = status.y.value; + + // Set directional buttons + status.right = x > properties_x.threshold; + status.left = x < -properties_x.threshold; + status.up = y > properties_y.threshold; + status.down = y < -properties_y.threshold; + + return status; +} + +Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) { + Input::TouchStatus status{}; + + switch (callback.type) { + case Input::InputType::Touch: + status = callback.touch_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type); + break; + } + + SanitizeAnalog(status.x, true); + SanitizeAnalog(status.y, true); + float& x = status.x.value; + float& y = status.y.value; + + // Adjust if value is inverted + x = status.x.properties.inverted ? 1.0f + x : x; + y = status.y.properties.inverted ? 1.0f + y : y; + + // clamp value + x = std::clamp(x, 0.0f, 1.0f); + y = std::clamp(y, 0.0f, 1.0f); + + if (status.pressed.inverted) { + status.pressed.value = !status.pressed.value; + } + + return status; +} + +Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { + Input::TriggerStatus status{}; + float& raw_value = status.analog.raw_value; + bool calculate_button_value = true; + + switch (callback.type) { + case Input::InputType::Analog: + status.analog.properties = callback.analog_status.properties; + raw_value = callback.analog_status.raw_value; + break; + case Input::InputType::Button: + status.analog.properties.range = 1.0f; + status.analog.properties.inverted = callback.button_status.inverted; + raw_value = callback.button_status.value ? 1.0f : 0.0f; + break; + case Input::InputType::Trigger: + status = callback.trigger_status; + calculate_button_value = false; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type); + break; + } + + SanitizeAnalog(status.analog, true); + const Input::AnalogProperties& properties = status.analog.properties; + float& value = status.analog.value; + + // Set button status + if (calculate_button_value) { + status.pressed = value > properties.threshold; + } + + // Adjust if value is inverted + value = properties.inverted ? 1.0f + value : value; + + // clamp value + value = std::clamp(value, 0.0f, 1.0f); + + return status; +} + +void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { + const Input::AnalogProperties& properties = analog.properties; + float& raw_value = analog.raw_value; + float& value = analog.value; + + if (!std::isnormal(raw_value)) { + raw_value = 0; + } + + // Apply center offset + raw_value -= properties.offset; + + // Set initial values to be formated + value = raw_value; + + // Calculate vector size + const float r = std::abs(value); + + // Return zero if value is smaller than the deadzone + if (r <= properties.deadzone || properties.deadzone == 1.0f) { + analog.value = 0; + return; + } + + // Adjust range of value + const float deadzone_factor = + 1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone); + value = value * deadzone_factor / properties.range; + + // Invert direction if needed + if (properties.inverted) { + value = -value; + } + + // Clamp value + if (clamp_value) { + value = std::clamp(value, -1.0f, 1.0f); + } +} + +void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value) { + const Input::AnalogProperties& properties_x = analog_x.properties; + const Input::AnalogProperties& properties_y = analog_y.properties; + float& raw_x = analog_x.raw_value; + float& raw_y = analog_y.raw_value; + float& x = analog_x.value; + float& y = analog_y.value; + + if (!std::isnormal(raw_x)) { + raw_x = 0; + } + if (!std::isnormal(raw_y)) { + raw_y = 0; + } + + // Apply center offset + raw_x += properties_x.offset; + raw_y += properties_y.offset; + + // Apply X scale correction from offset + if (std::abs(properties_x.offset) < 0.5f) { + if (raw_x > 0) { + raw_x /= 1 + properties_x.offset; + } else { + raw_x /= 1 - properties_x.offset; + } + } + + // Apply Y scale correction from offset + if (std::abs(properties_y.offset) < 0.5f) { + if (raw_y > 0) { + raw_y /= 1 + properties_y.offset; + } else { + raw_y /= 1 - properties_y.offset; + } + } + + // Invert direction if needed + raw_x = properties_x.inverted ? -raw_x : raw_x; + raw_y = properties_y.inverted ? -raw_y : raw_y; + + // Set initial values to be formated + x = raw_x; + y = raw_y; + + // Calculate vector size + float r = x * x + y * y; + r = std::sqrt(r); + + // TODO(German77): Use deadzone and range of both axis + + // Return zero if values are smaller than the deadzone + if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) { + x = 0; + y = 0; + return; + } + + // Adjust range of joystick + const float deadzone_factor = + 1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone); + x = x * deadzone_factor / properties_x.range; + y = y * deadzone_factor / properties_x.range; + r = r * deadzone_factor / properties_x.range; + + // Normalize joystick + if (clamp_value && r > 1.0f) { + x /= r; + y /= r; + } +} + +} // namespace Core::HID diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h new file mode 100644 index 000000000..3cc32e26a --- /dev/null +++ b/src/core/hid/input_converter.h @@ -0,0 +1,77 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +namespace Input { +struct CallbackStatus; +}; + +namespace Core::HID { + +/** + * Converts raw input data into a valid battery status. + * + * @param Supported callbacks: Analog, Battery, Trigger. + * @return A valid BatteryStatus object. + */ +Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback); + +/** + * Converts raw input data into a valid button status. Applies invert properties to the output. + * + * @param Supported callbacks: Analog, Button, Trigger. + * @return A valid TouchStatus object. + */ +Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback); + +/** + * Converts raw input data into a valid motion status. + * + * @param Supported callbacks: Motion. + * @return A valid TouchStatus object. + */ +Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback); + +/** + * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert + * properties to the output. + * + * @param Supported callbacks: Stick. + * @return A valid StickStatus object. + */ +Input::StickStatus TransformToStick(const Input::CallbackStatus& callback); + +/** + * Converts raw input data into a valid touch status. + * + * @param Supported callbacks: Touch. + * @return A valid TouchStatus object. + */ +Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback); + +/** + * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and + * invert properties to the output. Button status uses the threshold property if necessary. + * + * @param Supported callbacks: Analog, Button, Trigger. + * @return A valid TriggerStatus object. + */ +Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback); + +/** + * Converts raw analog data into a valid analog value + * @param An analog object containing raw data and properties, bool that determines if the value + * needs to be clamped between -1.0f and 1.0f. + */ +void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value); + +/** + * Converts raw stick data into a valid stick value + * @param Two analog objects containing raw data and properties, bool that determines if the value + * needs to be clamped into the unit circle. + */ +void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value); + +} // namespace Core::HID diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp new file mode 100644 index 000000000..93f37b77b --- /dev/null +++ b/src/core/hid/motion_input.cpp @@ -0,0 +1,278 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/math_util.h" +#include "core/hid/motion_input.h" + +namespace Core::HID { + +MotionInput::MotionInput() { + // Initialize PID constants with default values + SetPID(0.3f, 0.005f, 0.0f); +} + +void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { + kp = new_kp; + ki = new_ki; + kd = new_kd; +} + +void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { + accel = acceleration; +} + +void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { + gyro = gyroscope - gyro_drift; + + // Auto adjust drift to minimize drift + if (!IsMoving(0.1f)) { + gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f); + } + + if (gyro.Length2() < gyro_threshold) { + gyro = {}; + } else { + only_accelerometer = false; + } +} + +void MotionInput::SetQuaternion(const Common::Quaternion& quaternion) { + quat = quaternion; +} + +void MotionInput::SetGyroDrift(const Common::Vec3f& drift) { + gyro_drift = drift; +} + +void MotionInput::SetGyroThreshold(f32 threshold) { + gyro_threshold = threshold; +} + +void MotionInput::EnableReset(bool reset) { + reset_enabled = reset; +} + +void MotionInput::ResetRotations() { + rotations = {}; +} + +bool MotionInput::IsMoving(f32 sensitivity) const { + return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f; +} + +bool MotionInput::IsCalibrated(f32 sensitivity) const { + return real_error.Length() < sensitivity; +} + +void MotionInput::UpdateRotation(u64 elapsed_time) { + const auto sample_period = static_cast(elapsed_time) / 1000000.0f; + if (sample_period > 0.1f) { + return; + } + rotations += gyro * sample_period; +} + +void MotionInput::UpdateOrientation(u64 elapsed_time) { + if (!IsCalibrated(0.1f)) { + ResetOrientation(); + } + // Short name local variable for readability + f32 q1 = quat.w; + f32 q2 = quat.xyz[0]; + f32 q3 = quat.xyz[1]; + f32 q4 = quat.xyz[2]; + const auto sample_period = static_cast(elapsed_time) / 1000000.0f; + + // Ignore invalid elapsed time + if (sample_period > 0.1f) { + return; + } + + const auto normal_accel = accel.Normalized(); + auto rad_gyro = gyro * Common::PI * 2; + const f32 swap = rad_gyro.x; + rad_gyro.x = rad_gyro.y; + rad_gyro.y = -swap; + rad_gyro.z = -rad_gyro.z; + + // Clear gyro values if there is no gyro present + if (only_accelerometer) { + rad_gyro.x = 0; + rad_gyro.y = 0; + rad_gyro.z = 0; + } + + // Ignore drift correction if acceleration is not reliable + if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) { + const f32 ax = -normal_accel.x; + const f32 ay = normal_accel.y; + const f32 az = -normal_accel.z; + + // Estimated direction of gravity + const f32 vx = 2.0f * (q2 * q4 - q1 * q3); + const f32 vy = 2.0f * (q1 * q2 + q3 * q4); + const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; + + // Error is cross product between estimated direction and measured direction of gravity + const Common::Vec3f new_real_error = { + az * vx - ax * vz, + ay * vz - az * vy, + ax * vy - ay * vx, + }; + + derivative_error = new_real_error - real_error; + real_error = new_real_error; + + // Prevent integral windup + if (ki != 0.0f && !IsCalibrated(0.05f)) { + integral_error += real_error; + } else { + integral_error = {}; + } + + // Apply feedback terms + if (!only_accelerometer) { + rad_gyro += kp * real_error; + rad_gyro += ki * integral_error; + rad_gyro += kd * derivative_error; + } else { + // Give more weight to accelerometer values to compensate for the lack of gyro + rad_gyro += 35.0f * kp * real_error; + rad_gyro += 10.0f * ki * integral_error; + rad_gyro += 10.0f * kd * derivative_error; + + // Emulate gyro values for games that need them + gyro.x = -rad_gyro.y; + gyro.y = rad_gyro.x; + gyro.z = -rad_gyro.z; + UpdateRotation(elapsed_time); + } + } + + const f32 gx = rad_gyro.y; + const f32 gy = rad_gyro.x; + const f32 gz = rad_gyro.z; + + // Integrate rate of change of quaternion + const f32 pa = q2; + const f32 pb = q3; + const f32 pc = q4; + q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period); + q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period); + q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period); + q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period); + + quat.w = q1; + quat.xyz[0] = q2; + quat.xyz[1] = q3; + quat.xyz[2] = q4; + quat = quat.Normalized(); +} + +std::array MotionInput::GetOrientation() const { + const Common::Quaternion quad{ + .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w}, + .w = -quat.xyz[2], + }; + const std::array matrix4x4 = quad.ToMatrix(); + + return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]), + Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]), + Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])}; +} + +Common::Vec3f MotionInput::GetAcceleration() const { + return accel; +} + +Common::Vec3f MotionInput::GetGyroscope() const { + return gyro; +} + +Common::Quaternion MotionInput::GetQuaternion() const { + return quat; +} + +Common::Vec3f MotionInput::GetRotations() const { + return rotations; +} + +void MotionInput::ResetOrientation() { + if (!reset_enabled || only_accelerometer) { + return; + } + if (!IsMoving(0.5f) && accel.z <= -0.9f) { + ++reset_counter; + if (reset_counter > 900) { + quat.w = 0; + quat.xyz[0] = 0; + quat.xyz[1] = 0; + quat.xyz[2] = -1; + SetOrientationFromAccelerometer(); + integral_error = {}; + reset_counter = 0; + } + } else { + reset_counter = 0; + } +} + +void MotionInput::SetOrientationFromAccelerometer() { + int iterations = 0; + const f32 sample_period = 0.015f; + + const auto normal_accel = accel.Normalized(); + + while (!IsCalibrated(0.01f) && ++iterations < 100) { + // Short name local variable for readability + f32 q1 = quat.w; + f32 q2 = quat.xyz[0]; + f32 q3 = quat.xyz[1]; + f32 q4 = quat.xyz[2]; + + Common::Vec3f rad_gyro; + const f32 ax = -normal_accel.x; + const f32 ay = normal_accel.y; + const f32 az = -normal_accel.z; + + // Estimated direction of gravity + const f32 vx = 2.0f * (q2 * q4 - q1 * q3); + const f32 vy = 2.0f * (q1 * q2 + q3 * q4); + const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; + + // Error is cross product between estimated direction and measured direction of gravity + const Common::Vec3f new_real_error = { + az * vx - ax * vz, + ay * vz - az * vy, + ax * vy - ay * vx, + }; + + derivative_error = new_real_error - real_error; + real_error = new_real_error; + + rad_gyro += 10.0f * kp * real_error; + rad_gyro += 5.0f * ki * integral_error; + rad_gyro += 10.0f * kd * derivative_error; + + const f32 gx = rad_gyro.y; + const f32 gy = rad_gyro.x; + const f32 gz = rad_gyro.z; + + // Integrate rate of change of quaternion + const f32 pa = q2; + const f32 pb = q3; + const f32 pc = q4; + q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period); + q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period); + q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period); + q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period); + + quat.w = q1; + quat.xyz[0] = q2; + quat.xyz[1] = q3; + quat.xyz[2] = q4; + quat = quat.Normalized(); + } +} +} // namespace Core::HID diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h new file mode 100644 index 000000000..3deef5ac3 --- /dev/null +++ b/src/core/hid/motion_input.h @@ -0,0 +1,71 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "common/common_types.h" +#include "common/quaternion.h" +#include "common/vector_math.h" + +namespace Core::HID { + +class MotionInput { +public: + explicit MotionInput(); + + MotionInput(const MotionInput&) = default; + MotionInput& operator=(const MotionInput&) = default; + + MotionInput(MotionInput&&) = default; + MotionInput& operator=(MotionInput&&) = default; + + void SetPID(f32 new_kp, f32 new_ki, f32 new_kd); + void SetAcceleration(const Common::Vec3f& acceleration); + void SetGyroscope(const Common::Vec3f& gyroscope); + void SetQuaternion(const Common::Quaternion& quaternion); + void SetGyroDrift(const Common::Vec3f& drift); + void SetGyroThreshold(f32 threshold); + + void EnableReset(bool reset); + void ResetRotations(); + + void UpdateRotation(u64 elapsed_time); + void UpdateOrientation(u64 elapsed_time); + + [[nodiscard]] std::array GetOrientation() const; + [[nodiscard]] Common::Vec3f GetAcceleration() const; + [[nodiscard]] Common::Vec3f GetGyroscope() const; + [[nodiscard]] Common::Vec3f GetRotations() const; + [[nodiscard]] Common::Quaternion GetQuaternion() const; + + [[nodiscard]] bool IsMoving(f32 sensitivity) const; + [[nodiscard]] bool IsCalibrated(f32 sensitivity) const; + +private: + void ResetOrientation(); + void SetOrientationFromAccelerometer(); + + // PID constants + f32 kp; + f32 ki; + f32 kd; + + // PID errors + Common::Vec3f real_error; + Common::Vec3f integral_error; + Common::Vec3f derivative_error; + + Common::Quaternion quat{{0.0f, 0.0f, -1.0f}, 0.0f}; + Common::Vec3f rotations; + Common::Vec3f accel; + Common::Vec3f gyro; + Common::Vec3f gyro_drift; + + f32 gyro_threshold = 0.0f; + u32 reset_counter = 0; + bool reset_enabled = true; + bool only_accelerometer = true; +}; + +} // namespace Core::HID From ea7b1fbc673e40d5e51f2d185ebe8542741164fa Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 16:34:05 -0500 Subject: [PATCH 051/291] input_common: Create input_engine --- src/input_common/input_engine.cpp | 361 ++++++++++++++++++++++++++++++ src/input_common/input_engine.h | 224 ++++++++++++++++++ 2 files changed, 585 insertions(+) create mode 100644 src/input_common/input_engine.cpp create mode 100644 src/input_common/input_engine.h diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp new file mode 100644 index 000000000..1534f24b0 --- /dev/null +++ b/src/input_common/input_engine.cpp @@ -0,0 +1,361 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/logging/log.h" +#include "common/param_package.h" +#include "input_common/input_engine.h" + +namespace InputCommon { + +void InputEngine::PreSetController(const PadIdentifier& identifier) { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + controller_list.insert_or_assign(identifier, ControllerData{}); + } +} + +void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!controller.buttons.contains(button)) { + controller.buttons.insert_or_assign(button, false); + } +} + +void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!controller.hat_buttons.contains(button)) { + controller.hat_buttons.insert_or_assign(button, u8{0}); + } +} + +void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!controller.axes.contains(axis)) { + controller.axes.insert_or_assign(axis, 0.0f); + } +} + +void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!controller.motions.contains(motion)) { + controller.motions.insert_or_assign(motion, BasicMotion{}); + } +} + +void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { + { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.buttons.insert_or_assign(button, value); + } + } + TriggerOnButtonChange(identifier, button, value); +} + +void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 value) { + { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.hat_buttons.insert_or_assign(button, value); + } + } + TriggerOnHatButtonChange(identifier, button, value); +} + +void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) { + { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.axes.insert_or_assign(axis, value); + } + } + TriggerOnAxisChange(identifier, axis, value); +} + +void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value) { + { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.battery = value; + } + } + TriggerOnBatteryChange(identifier, value); +} + +void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { + { + std::lock_guard lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.motions.insert_or_assign(motion, value); + } + } + TriggerOnMotionChange(identifier, motion, value); +} + +bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), + identifier.pad, identifier.port); + return false; + } + ControllerData controller = controller_list.at(identifier); + if (!controller.buttons.contains(button)) { + LOG_ERROR(Input, "Invalid button {}", button); + return false; + } + return controller.buttons.at(button); +} + +bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), + identifier.pad, identifier.port); + return false; + } + ControllerData controller = controller_list.at(identifier); + if (!controller.hat_buttons.contains(button)) { + LOG_ERROR(Input, "Invalid hat button {}", button); + return false; + } + return (controller.hat_buttons.at(button) & direction) != 0; +} + +f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), + identifier.pad, identifier.port); + return 0.0f; + } + ControllerData controller = controller_list.at(identifier); + if (!controller.axes.contains(axis)) { + LOG_ERROR(Input, "Invalid axis {}", axis); + return 0.0f; + } + return controller.axes.at(axis); +} + +BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), + identifier.pad, identifier.port); + return BatteryLevel::Charging; + } + ControllerData controller = controller_list.at(identifier); + return controller.battery; +} + +BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { + std::lock_guard lock{mutex}; + if (!controller_list.contains(identifier)) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), + identifier.pad, identifier.port); + return {}; + } + ControllerData controller = controller_list.at(identifier); + return controller.motions.at(motion); +} + +void InputEngine::ResetButtonState() { + for (std::pair controller : controller_list) { + for (std::pair button : controller.second.buttons) { + SetButton(controller.first, button.first, false); + } + for (std::pair button : controller.second.hat_buttons) { + SetHatButton(controller.first, button.first, false); + } + } +} + +void InputEngine::ResetAnalogState() { + for (std::pair controller : controller_list) { + for (std::pair axis : controller.second.axes) { + SetAxis(controller.first, axis.first, 0.0); + } + } +} + +void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { + std::lock_guard lock{mutex_callback}; + for (const std::pair poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } + if (!configuring || !mapping_callback.on_data) { + return; + } + if (value == GetButton(identifier, button)) { + return; + } + mapping_callback.on_data(MappingData{ + .engine = GetEngineName(), + .pad = identifier, + .type = EngineInputType::Button, + .index = button, + .button_value = value, + }); +} + +void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) { + std::lock_guard lock{mutex_callback}; + for (const std::pair poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } + if (!configuring || !mapping_callback.on_data) { + return; + } + for (std::size_t index = 1; index < 0xff; index <<= 1) { + bool button_value = (value & index) != 0; + if (button_value == GetHatButton(identifier, button, static_cast(index))) { + continue; + } + mapping_callback.on_data(MappingData{ + .engine = GetEngineName(), + .pad = identifier, + .type = EngineInputType::HatButton, + .index = button, + .hat_name = GetHatButtonName(static_cast(index)), + }); + } +} + +void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { + std::lock_guard lock{mutex_callback}; + for (const std::pair poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } + if (!configuring || !mapping_callback.on_data) { + return; + } + if (std::abs(value - GetAxis(identifier, axis)) < 0.5f) { + return; + } + mapping_callback.on_data(MappingData{ + .engine = GetEngineName(), + .pad = identifier, + .type = EngineInputType::Analog, + .index = axis, + .axis_value = value, + }); +} + +void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, + [[maybe_unused]] BatteryLevel value) { + std::lock_guard lock{mutex_callback}; + for (const std::pair poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } +} + +void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, + BasicMotion value) { + std::lock_guard lock{mutex_callback}; + for (const std::pair poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } + if (!configuring || !mapping_callback.on_data) { + return; + } + if (std::abs(value.gyro_x) < 1.0f && std::abs(value.gyro_y) < 1.0f && + std::abs(value.gyro_z) < 1.0f) { + return; + } + mapping_callback.on_data(MappingData{ + .engine = GetEngineName(), + .pad = identifier, + .type = EngineInputType::Motion, + .index = motion, + .motion_value = value, + }); +} + +bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, + const PadIdentifier& identifier, EngineInputType type, + std::size_t index) const { + if (input_identifier.type != type) { + return false; + } + if (input_identifier.index != index) { + return false; + } + if (input_identifier.identifier != identifier) { + return false; + } + return true; +} + +void InputEngine::BeginConfiguration() { + configuring = true; +} + +void InputEngine::EndConfiguration() { + configuring = false; +} + +const std::string& InputEngine::GetEngineName() const { + return input_engine; +} + +int InputEngine::SetCallback(InputIdentifier input_identifier) { + std::lock_guard lock{mutex_callback}; + callback_list.insert_or_assign(last_callback_key, input_identifier); + return last_callback_key++; +} + +void InputEngine::SetMappingCallback(MappingCallback callback) { + std::lock_guard lock{mutex_callback}; + mapping_callback = std::move(callback); +} + +void InputEngine::DeleteCallback(int key) { + std::lock_guard lock{mutex_callback}; + if (!callback_list.contains(key)) { + LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); + return; + } + callback_list.erase(key); +} + +} // namespace InputCommon diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h new file mode 100644 index 000000000..86a8e00d8 --- /dev/null +++ b/src/input_common/input_engine.h @@ -0,0 +1,224 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include +#include +#include + +#include "common/common_types.h" +#include "common/input.h" +#include "common/param_package.h" +#include "common/uuid.h" +#include "input_common/main.h" + +// Pad Identifier of data source +struct PadIdentifier { + Common::UUID guid{}; + std::size_t port{}; + std::size_t pad{}; + + friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default; +}; + +// Basic motion data containing data from the sensors and a timestamp in microsecons +struct BasicMotion { + float gyro_x; + float gyro_y; + float gyro_z; + float accel_x; + float accel_y; + float accel_z; + u64 delta_timestamp; +}; + +// Stages of a battery charge +enum class BatteryLevel { + Empty, + Critical, + Low, + Medium, + Full, + Charging, +}; + +// Types of input that are stored in the engine +enum class EngineInputType { + None, + Button, + HatButton, + Analog, + Motion, + Battery, +}; + +namespace std { +// Hash used to create lists from PadIdentifier data +template <> +struct hash { + size_t operator()(const PadIdentifier& pad_id) const noexcept { + u64 hash_value = pad_id.guid.uuid[1] ^ pad_id.guid.uuid[0]; + hash_value ^= (static_cast(pad_id.port) << 32); + hash_value ^= static_cast(pad_id.pad); + return static_cast(hash_value); + } +}; + +} // namespace std + +namespace InputCommon { + +// Data from the engine and device needed for creating a ParamPackage +struct MappingData { + std::string engine{}; + PadIdentifier pad{}; + EngineInputType type{}; + int index{}; + bool button_value{}; + std::string hat_name{}; + f32 axis_value{}; + BasicMotion motion_value{}; +}; + +// Triggered if data changed on the controller +struct UpdateCallback { + std::function on_change; +}; + +// Triggered if data changed on the controller and the engine is on configuring mode +struct MappingCallback { + std::function on_data; +}; + +// Input Identifier of data source +struct InputIdentifier { + PadIdentifier identifier; + EngineInputType type; + std::size_t index; + UpdateCallback callback; +}; + +class InputEngine { +public: + explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) { + callback_list.clear(); + } + + virtual ~InputEngine() = default; + + // Enable configuring mode for mapping + void BeginConfiguration(); + + // Disable configuring mode for mapping + void EndConfiguration(); + + // Sets rumble to a controller + virtual bool SetRumble([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::VibrationStatus vibration) { + return false; + } + + // Sets a led pattern for a controller + virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::LedStatus led_status) { + return; + } + + // Returns the engine name + [[nodiscard]] const std::string& GetEngineName() const; + + /// Used for automapping features + virtual std::vector GetInputDevices() const { + return {}; + }; + + /// Retrieves the button mappings for the given device + virtual InputCommon::ButtonMapping GetButtonMappingForDevice( + [[maybe_unused]] const Common::ParamPackage& params) { + return {}; + }; + + /// Retrieves the analog mappings for the given device + virtual InputCommon::AnalogMapping GetAnalogMappingForDevice( + [[maybe_unused]] const Common::ParamPackage& params) { + return {}; + }; + + /// Retrieves the motion mappings for the given device + virtual InputCommon::MotionMapping GetMotionMappingForDevice( + [[maybe_unused]] const Common::ParamPackage& params) { + return {}; + }; + + /// Retrieves the name of the given input. + virtual std::string GetUIName([[maybe_unused]] const Common::ParamPackage& params) const { + return GetEngineName(); + }; + + /// Retrieves the index number of the given hat button direction + virtual u8 GetHatButtonId([[maybe_unused]] const std::string direction_name) const { + return 0; + }; + + void PreSetController(const PadIdentifier& identifier); + void PreSetButton(const PadIdentifier& identifier, int button); + void PreSetHatButton(const PadIdentifier& identifier, int button); + void PreSetAxis(const PadIdentifier& identifier, int axis); + void PreSetMotion(const PadIdentifier& identifier, int motion); + void ResetButtonState(); + void ResetAnalogState(); + + bool GetButton(const PadIdentifier& identifier, int button) const; + bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const; + f32 GetAxis(const PadIdentifier& identifier, int axis) const; + BatteryLevel GetBattery(const PadIdentifier& identifier) const; + BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const; + + int SetCallback(InputIdentifier input_identifier); + void SetMappingCallback(MappingCallback callback); + void DeleteCallback(int key); + +protected: + void SetButton(const PadIdentifier& identifier, int button, bool value); + void SetHatButton(const PadIdentifier& identifier, int button, u8 value); + void SetAxis(const PadIdentifier& identifier, int axis, f32 value); + void SetBattery(const PadIdentifier& identifier, BatteryLevel value); + void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value); + + virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { + return "Unknown"; + } + +private: + struct ControllerData { + std::unordered_map buttons; + std::unordered_map hat_buttons; + std::unordered_map axes; + std::unordered_map motions; + BatteryLevel battery; + }; + + void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); + void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); + void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); + void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); + void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value); + + bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, + const PadIdentifier& identifier, EngineInputType type, + std::size_t index) const; + + mutable std::mutex mutex; + mutable std::mutex mutex_callback; + bool configuring{false}; + bool is_callback_enabled{true}; + const std::string input_engine; + int last_callback_key = 0; + std::unordered_map controller_list; + std::unordered_map callback_list; + MappingCallback mapping_callback; +}; + +} // namespace InputCommon From 854c933716f0f5e1dbf62157c5a76e65213b30b2 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 16:41:15 -0500 Subject: [PATCH 052/291] input_common: Create input poller and mapping --- src/input_common/CMakeLists.txt | 6 + src/input_common/input_mapping.cpp | 171 ++++++ src/input_common/input_mapping.h | 76 +++ src/input_common/input_poller.cpp | 860 +++++++++++++++++++++++++++++ src/input_common/input_poller.h | 189 +++++++ src/input_common/main.h | 3 + 6 files changed, 1305 insertions(+) create mode 100644 src/input_common/input_mapping.cpp create mode 100644 src/input_common/input_mapping.h create mode 100644 src/input_common/input_poller.cpp create mode 100644 src/input_common/input_poller.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index dd13d948f..72f1e0f4a 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -3,6 +3,12 @@ add_library(input_common STATIC analog_from_button.h keyboard.cpp keyboard.h + input_engine.cpp + input_engine.h + input_mapping.cpp + input_mapping.h + input_poller.cpp + input_poller.h main.cpp main.h motion_from_button.cpp diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp new file mode 100644 index 000000000..0ffc71028 --- /dev/null +++ b/src/input_common/input_mapping.cpp @@ -0,0 +1,171 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/common_types.h" +#include "input_common/input_engine.h" +#include "input_common/input_mapping.h" + +namespace InputCommon { + +MappingFactory::MappingFactory() {} + +void MappingFactory::BeginMapping(Polling::InputType type) { + is_enabled = true; + input_type = type; + input_queue.Clear(); + first_axis = -1; + second_axis = -1; +} + +[[nodiscard]] const Common::ParamPackage MappingFactory::GetNextInput() { + Common::ParamPackage input; + input_queue.Pop(input); + return input; +} + +void MappingFactory::RegisterInput(const MappingData& data) { + if (!is_enabled) { + return; + } + switch (input_type) { + case Polling::InputType::Button: + RegisterButton(data); + return; + case Polling::InputType::Stick: + RegisterStick(data); + return; + case Polling::InputType::Motion: + RegisterMotion(data); + return; + default: + return; + } +} + +void MappingFactory::StopMapping() { + is_enabled = false; + input_type = Polling::InputType::None; + input_queue.Clear(); +} + +void MappingFactory::RegisterButton(const MappingData& data) { + Common::ParamPackage new_input; + new_input.Set("engine", data.engine); + if (data.pad.guid != Common::UUID{}) { + new_input.Set("guid", data.pad.guid.Format()); + } + new_input.Set("port", static_cast(data.pad.port)); + new_input.Set("pad", static_cast(data.pad.pad)); + switch (data.type) { + case EngineInputType::Button: + // Workaround for old compatibility + if (data.engine == "keyboard") { + new_input.Set("code", data.index); + break; + } + new_input.Set("button", data.index); + break; + case EngineInputType::HatButton: + new_input.Set("hat", data.index); + new_input.Set("direction", data.hat_name); + break; + case EngineInputType::Analog: + new_input.Set("axis", data.index); + new_input.Set("threshold", 0.5f); + break; + default: + return; + } + input_queue.Push(new_input); +} + +void MappingFactory::RegisterStick(const MappingData& data) { + Common::ParamPackage new_input; + new_input.Set("engine", data.engine); + if (data.pad.guid != Common::UUID{}) { + new_input.Set("guid", data.pad.guid.Format()); + } + new_input.Set("port", static_cast(data.pad.port)); + new_input.Set("pad", static_cast(data.pad.pad)); + + // If engine is mouse map the mouse position as a joystick + if (data.engine == "mouse") { + new_input.Set("axis_x", 0); + new_input.Set("axis_y", 1); + new_input.Set("threshold", 0.5f); + new_input.Set("range", 1.0f); + new_input.Set("deadzone", 0.0f); + input_queue.Push(new_input); + return; + } + + switch (data.type) { + case EngineInputType::Button: + case EngineInputType::HatButton: + RegisterButton(data); + return; + case EngineInputType::Analog: + if (first_axis == data.index) { + return; + } + if (first_axis == -1) { + first_axis = data.index; + return; + } + new_input.Set("axis_x", first_axis); + new_input.Set("axis_y", data.index); + new_input.Set("threshold", 0.5f); + new_input.Set("range", 0.95f); + new_input.Set("deadzone", 0.15f); + break; + default: + return; + } + input_queue.Push(new_input); +} + +void MappingFactory::RegisterMotion(const MappingData& data) { + Common::ParamPackage new_input; + new_input.Set("engine", data.engine); + if (data.pad.guid != Common::UUID{}) { + new_input.Set("guid", data.pad.guid.Format()); + } + new_input.Set("port", static_cast(data.pad.port)); + new_input.Set("pad", static_cast(data.pad.pad)); + switch (data.type) { + case EngineInputType::Button: + case EngineInputType::HatButton: + RegisterButton(data); + return; + case EngineInputType::Analog: + if (first_axis == data.index) { + return; + } + if (second_axis == data.index) { + return; + } + if (first_axis == -1) { + first_axis = data.index; + return; + } + if (second_axis == -1) { + second_axis = data.index; + return; + } + new_input.Set("axis_x", first_axis); + new_input.Set("axis_y", second_axis); + new_input.Set("axis_z", data.index); + new_input.Set("range", 1.0f); + new_input.Set("deadzone", 0.20f); + break; + case EngineInputType::Motion: + new_input.Set("motion", data.index); + break; + default: + return; + } + input_queue.Push(new_input); +} + +} // namespace InputCommon diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h new file mode 100644 index 000000000..2622dba70 --- /dev/null +++ b/src/input_common/input_mapping.h @@ -0,0 +1,76 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once +#include "common/threadsafe_queue.h" + +namespace InputCommon { +class InputEngine; +struct MappingData; + +class MappingFactory { +public: + MappingFactory(); + + /** + * Resets all varables to beggin the mapping process + * @param "type": type of input desired to be returned + */ + void BeginMapping(Polling::InputType type); + + /// Returns an input event with mapping information from the input_queue + [[nodiscard]] const Common::ParamPackage GetNextInput(); + + /** + * Registers mapping input data from the driver + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + void RegisterInput(const MappingData& data); + + /// Stop polling from all backends + void StopMapping(); + +private: + /** + * If provided data satisfies the requeriments it will push an element to the input_queue + * Supported input: + * - Button: Creates a basic button ParamPackage + * - HatButton: Creates a basic hat button ParamPackage + * - Analog: Creates a basic analog ParamPackage + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + void RegisterButton(const MappingData& data); + + /** + * If provided data satisfies the requeriments it will push an element to the input_queue + * Supported input: + * - Button, HatButton: Pass the data to RegisterButton + * - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + void RegisterStick(const MappingData& data); + + /** + * If provided data satisfies the requeriments it will push an element to the input_queue + * Supported input: + * - Button, HatButton: Pass the data to RegisterButton + * - Analog: Stores the first two axis and on the third axis creates a basic Motion + * ParamPackage + * - Motion: Creates a basic Motion ParamPackage + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + void RegisterMotion(const MappingData& data); + + Common::SPSCQueue input_queue; + Polling::InputType input_type{Polling::InputType::None}; + bool is_enabled{}; + int first_axis = -1; + int second_axis = -1; +}; + +} // namespace InputCommon diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp new file mode 100644 index 000000000..46a7dd276 --- /dev/null +++ b/src/input_common/input_poller.cpp @@ -0,0 +1,860 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/common_types.h" +#include "common/input.h" + +#include "input_common/input_engine.h" +#include "input_common/input_poller.h" + +namespace InputCommon { + +class DummyInput final : public Input::InputDevice { +public: + explicit DummyInput() {} + ~DummyInput() {} +}; + +class InputFromButton final : public Input::InputDevice { +public: + explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, + InputEngine* input_engine_) + : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), + input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::Button, + .index = button, + .callback = engine_callback, + }; + last_button_value = false; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromButton() { + input_engine->DeleteCallback(callback_key); + } + + Input::ButtonStatus GetStatus() const { + return { + .value = input_engine->GetButton(identifier, button), + .inverted = inverted, + .toggle = toggle, + }; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Button, + .button_status = GetStatus(), + }; + + if (status.button_status.value != last_button_value) { + last_button_value = status.button_status.value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 button; + const bool toggle; + const bool inverted; + int callback_key; + bool last_button_value; + InputEngine* input_engine; +}; + +class InputFromHatButton final : public Input::InputDevice { +public: + explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_, + bool inverted_, InputEngine* input_engine_) + : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), + inverted(inverted_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::HatButton, + .index = button, + .callback = engine_callback, + }; + last_button_value = false; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromHatButton() { + input_engine->DeleteCallback(callback_key); + } + + Input::ButtonStatus GetStatus() const { + return { + .value = input_engine->GetHatButton(identifier, button, direction), + .inverted = inverted, + .toggle = toggle, + }; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Button, + .button_status = GetStatus(), + }; + + if (status.button_status.value != last_button_value) { + last_button_value = status.button_status.value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 button; + const u8 direction; + const bool toggle; + const bool inverted; + int callback_key; + bool last_button_value; + InputEngine* input_engine; +}; + +class InputFromStick final : public Input::InputDevice { +public: + explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, + Input::AnalogProperties properties_x_, + Input::AnalogProperties properties_y_, InputEngine* input_engine_) + : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), + properties_y(properties_y_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier x_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_x, + .callback = engine_callback, + }; + const InputIdentifier y_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_y, + .callback = engine_callback, + }; + last_axis_x_value = 0.0f; + last_axis_y_value = 0.0f; + callback_key_x = input_engine->SetCallback(x_input_identifier); + callback_key_y = input_engine->SetCallback(y_input_identifier); + } + + ~InputFromStick() { + input_engine->DeleteCallback(callback_key_x); + input_engine->DeleteCallback(callback_key_y); + } + + Input::StickStatus GetStatus() const { + Input::StickStatus status; + status.x = { + .raw_value = input_engine->GetAxis(identifier, axis_x), + .properties = properties_x, + }; + status.y = { + .raw_value = input_engine->GetAxis(identifier, axis_y), + .properties = properties_y, + }; + return status; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Stick, + .stick_status = GetStatus(), + }; + + if (status.stick_status.x.raw_value != last_axis_x_value || + status.stick_status.y.raw_value != last_axis_y_value) { + last_axis_x_value = status.stick_status.x.raw_value; + last_axis_y_value = status.stick_status.y.raw_value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 axis_x; + const u32 axis_y; + const Input::AnalogProperties properties_x; + const Input::AnalogProperties properties_y; + int callback_key_x; + int callback_key_y; + float last_axis_x_value; + float last_axis_y_value; + InputEngine* input_engine; +}; + +class InputFromTouch final : public Input::InputDevice { +public: + explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_, + bool inverted_, u32 axis_x_, u32 axis_y_, + Input::AnalogProperties properties_x_, + Input::AnalogProperties properties_y_, InputEngine* input_engine_) + : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), + inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), + properties_y(properties_y_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier button_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Button, + .index = button, + .callback = engine_callback, + }; + const InputIdentifier x_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_x, + .callback = engine_callback, + }; + const InputIdentifier y_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_y, + .callback = engine_callback, + }; + last_axis_x_value = 0.0f; + last_axis_y_value = 0.0f; + last_button_value = false; + callback_key_button = input_engine->SetCallback(button_input_identifier); + callback_key_x = input_engine->SetCallback(x_input_identifier); + callback_key_y = input_engine->SetCallback(y_input_identifier); + } + + ~InputFromTouch() { + input_engine->DeleteCallback(callback_key_button); + input_engine->DeleteCallback(callback_key_x); + input_engine->DeleteCallback(callback_key_y); + } + + Input::TouchStatus GetStatus() const { + Input::TouchStatus status; + status.id = touch_id; + status.pressed = { + .value = input_engine->GetButton(identifier, button), + .inverted = inverted, + .toggle = toggle, + }; + status.x = { + .raw_value = input_engine->GetAxis(identifier, axis_x), + .properties = properties_x, + }; + status.y = { + .raw_value = input_engine->GetAxis(identifier, axis_y), + .properties = properties_y, + }; + return status; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Touch, + .touch_status = GetStatus(), + }; + + if (status.touch_status.x.raw_value != last_axis_x_value || + status.touch_status.y.raw_value != last_axis_y_value || + status.touch_status.pressed.value != last_button_value) { + last_axis_x_value = status.touch_status.x.raw_value; + last_axis_y_value = status.touch_status.y.raw_value; + last_button_value = status.touch_status.pressed.value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 touch_id; + const u32 button; + const bool toggle; + const bool inverted; + const u32 axis_x; + const u32 axis_y; + const Input::AnalogProperties properties_x; + const Input::AnalogProperties properties_y; + int callback_key_button; + int callback_key_x; + int callback_key_y; + bool last_button_value; + float last_axis_x_value; + float last_axis_y_value; + InputEngine* input_engine; +}; + +class InputFromTrigger final : public Input::InputDevice { +public: + explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, + u32 axis_, Input::AnalogProperties properties_, + InputEngine* input_engine_) + : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), + axis(axis_), properties(properties_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier button_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Button, + .index = button, + .callback = engine_callback, + }; + const InputIdentifier axis_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis, + .callback = engine_callback, + }; + last_axis_value = 0.0f; + last_button_value = false; + callback_key_button = input_engine->SetCallback(button_input_identifier); + axis_callback_key = input_engine->SetCallback(axis_input_identifier); + } + + ~InputFromTrigger() { + input_engine->DeleteCallback(callback_key_button); + input_engine->DeleteCallback(axis_callback_key); + } + + Input::TriggerStatus GetStatus() const { + const Input::AnalogStatus analog_status{ + .raw_value = input_engine->GetAxis(identifier, axis), + .properties = properties, + }; + return { + .analog = analog_status, + .pressed = input_engine->GetButton(identifier, button), + }; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Trigger, + .trigger_status = GetStatus(), + }; + + if (status.trigger_status.analog.raw_value != last_axis_value || + status.trigger_status.pressed != last_button_value) { + last_axis_value = status.trigger_status.analog.raw_value; + last_button_value = status.trigger_status.pressed; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 button; + const bool toggle; + const bool inverted; + const u32 axis; + const Input::AnalogProperties properties; + int callback_key_button; + int axis_callback_key; + bool last_button_value; + float last_axis_value; + InputEngine* input_engine; +}; + +class InputFromAnalog final : public Input::InputDevice { +public: + explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_, + Input::AnalogProperties properties_, InputEngine* input_engine_) + : identifier(identifier_), axis(axis_), properties(properties_), + input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis, + .callback = engine_callback, + }; + last_axis_value = 0.0f; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromAnalog() { + input_engine->DeleteCallback(callback_key); + } + + Input::AnalogStatus GetStatus() const { + return { + .raw_value = input_engine->GetAxis(identifier, axis), + .properties = properties, + }; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Analog, + .analog_status = GetStatus(), + }; + + if (status.analog_status.raw_value != last_axis_value) { + last_axis_value = status.analog_status.raw_value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 axis; + const Input::AnalogProperties properties; + int callback_key; + float last_axis_value; + InputEngine* input_engine; +}; + +class InputFromBattery final : public Input::InputDevice { +public: + explicit InputFromBattery(PadIdentifier identifier_, InputEngine* input_engine_) + : identifier(identifier_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::Battery, + .index = 0, + .callback = engine_callback, + }; + last_battery_value = Input::BatteryStatus::Charging; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromBattery() { + input_engine->DeleteCallback(callback_key); + } + + Input::BatteryStatus GetStatus() const { + return static_cast(input_engine->GetBattery(identifier)); + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Battery, + .battery_status = GetStatus(), + }; + + if (status.battery_status != last_battery_value) { + last_battery_value = status.battery_status; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + int callback_key; + Input::BatteryStatus last_battery_value; + InputEngine* input_engine; +}; + +class InputFromMotion final : public Input::InputDevice { +public: + explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_, + InputEngine* input_engine_) + : identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::Motion, + .index = motion_sensor, + .callback = engine_callback, + }; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromMotion() { + input_engine->DeleteCallback(callback_key); + } + + Input::MotionStatus GetStatus() const { + const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor); + Input::MotionStatus status{}; + const Input::AnalogProperties properties = { + .deadzone = 0.001f, + .range = 1.0f, + .offset = 0.0f, + }; + status.accel.x = {.raw_value = basic_motion.accel_x, .properties = properties}; + status.accel.y = {.raw_value = basic_motion.accel_y, .properties = properties}; + status.accel.z = {.raw_value = basic_motion.accel_z, .properties = properties}; + status.gyro.x = {.raw_value = basic_motion.gyro_x, .properties = properties}; + status.gyro.y = {.raw_value = basic_motion.gyro_y, .properties = properties}; + status.gyro.z = {.raw_value = basic_motion.gyro_z, .properties = properties}; + status.delta_timestamp = basic_motion.delta_timestamp; + return status; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Motion, + .motion_status = GetStatus(), + }; + + TriggerOnChange(status); + } + +private: + const PadIdentifier identifier; + const u32 motion_sensor; + int callback_key; + InputEngine* input_engine; +}; + +class InputFromAxisMotion final : public Input::InputDevice { +public: + explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_, + Input::AnalogProperties properties_x_, + Input::AnalogProperties properties_y_, + Input::AnalogProperties properties_z_, InputEngine* input_engine_) + : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), axis_z(axis_z_), + properties_x(properties_x_), properties_y(properties_y_), properties_z(properties_z_), + input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier x_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_x, + .callback = engine_callback, + }; + const InputIdentifier y_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_y, + .callback = engine_callback, + }; + const InputIdentifier z_input_identifier{ + .identifier = identifier, + .type = EngineInputType::Analog, + .index = axis_z, + .callback = engine_callback, + }; + last_axis_x_value = 0.0f; + last_axis_y_value = 0.0f; + last_axis_z_value = 0.0f; + callback_key_x = input_engine->SetCallback(x_input_identifier); + callback_key_y = input_engine->SetCallback(y_input_identifier); + callback_key_z = input_engine->SetCallback(z_input_identifier); + } + + ~InputFromAxisMotion() { + input_engine->DeleteCallback(callback_key_x); + input_engine->DeleteCallback(callback_key_y); + input_engine->DeleteCallback(callback_key_z); + } + + Input::MotionStatus GetStatus() const { + Input::MotionStatus status{}; + status.gyro.x = { + .raw_value = input_engine->GetAxis(identifier, axis_x), + .properties = properties_x, + }; + status.gyro.y = { + .raw_value = input_engine->GetAxis(identifier, axis_y), + .properties = properties_y, + }; + status.gyro.z = { + .raw_value = input_engine->GetAxis(identifier, axis_z), + .properties = properties_z, + }; + return status; + } + + void OnChange() { + const Input::CallbackStatus status{ + .type = Input::InputType::Motion, + .motion_status = GetStatus(), + }; + + if (status.motion_status.gyro.x.raw_value != last_axis_x_value || + status.motion_status.gyro.y.raw_value != last_axis_y_value || + status.motion_status.gyro.z.raw_value != last_axis_z_value) { + last_axis_x_value = status.motion_status.gyro.x.raw_value; + last_axis_y_value = status.motion_status.gyro.y.raw_value; + last_axis_z_value = status.motion_status.gyro.z.raw_value; + TriggerOnChange(status); + } + } + +private: + const PadIdentifier identifier; + const u32 axis_x; + const u32 axis_y; + const u32 axis_z; + const Input::AnalogProperties properties_x; + const Input::AnalogProperties properties_y; + const Input::AnalogProperties properties_z; + int callback_key_x; + int callback_key_y; + int callback_key_z; + float last_axis_x_value; + float last_axis_y_value; + float last_axis_z_value; + InputEngine* input_engine; +}; + +std::unique_ptr InputFactory::CreateButtonDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto button_id = static_cast(params.Get("button", 0)); + const auto keyboard_key = static_cast(params.Get("code", 0)); + const auto toggle = params.Get("toggle", false); + const auto inverted = params.Get("inverted", false); + input_engine->PreSetController(identifier); + input_engine->PreSetButton(identifier, button_id); + input_engine->PreSetButton(identifier, keyboard_key); + if (keyboard_key != 0) { + return std::make_unique(identifier, keyboard_key, toggle, inverted, + input_engine.get()); + } + return std::make_unique(identifier, button_id, toggle, inverted, + input_engine.get()); +} + +std::unique_ptr InputFactory::CreateHatButtonDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto button_id = static_cast(params.Get("hat", 0)); + const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); + const auto toggle = params.Get("toggle", false); + const auto inverted = params.Get("inverted", false); + + input_engine->PreSetController(identifier); + input_engine->PreSetHatButton(identifier, button_id); + return std::make_unique(identifier, button_id, direction, toggle, inverted, + input_engine.get()); +} + +std::unique_ptr InputFactory::CreateStickDevice( + const Common::ParamPackage& params) { + const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f); + const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); + const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto axis_x = static_cast(params.Get("axis_x", 0)); + const Input::AnalogProperties properties_x = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_x", "+") == "-", + }; + + const auto axis_y = static_cast(params.Get("axis_y", 1)); + const Input::AnalogProperties properties_y = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_y", "+") != "+", + }; + input_engine->PreSetController(identifier); + input_engine->PreSetAxis(identifier, axis_x); + input_engine->PreSetAxis(identifier, axis_y); + return std::make_unique(identifier, axis_x, axis_y, properties_x, properties_y, + input_engine.get()); +} + +std::unique_ptr InputFactory::CreateAnalogDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto axis = static_cast(params.Get("axis", 0)); + const Input::AnalogProperties properties = { + .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), + .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f), + .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), + .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert", "+") == "-", + }; + input_engine->PreSetController(identifier); + input_engine->PreSetAxis(identifier, axis); + return std::make_unique(identifier, axis, properties, input_engine.get()); +} + +std::unique_ptr InputFactory::CreateTriggerDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto button = static_cast(params.Get("button", 0)); + const auto toggle = params.Get("toggle", false); + const auto inverted = params.Get("inverted", false); + + const auto axis = static_cast(params.Get("axis", 0)); + const Input::AnalogProperties properties = { + .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), + .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f), + .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), + .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert", false) != 0, + }; + input_engine->PreSetController(identifier); + input_engine->PreSetAxis(identifier, axis); + input_engine->PreSetButton(identifier, button); + return std::make_unique(identifier, button, toggle, inverted, axis, + properties, input_engine.get()); +} + +std::unique_ptr InputFactory::CreateTouchDevice( + const Common::ParamPackage& params) { + const auto touch_id = params.Get("touch_id", 0); + const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); + const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); + const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + const auto button = static_cast(params.Get("button", 0)); + const auto toggle = params.Get("toggle", false); + const auto inverted = params.Get("inverted", false); + + const auto axis_x = static_cast(params.Get("axis_x", 0)); + const Input::AnalogProperties properties_x = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_x", "+") == "-", + }; + + const auto axis_y = static_cast(params.Get("axis_y", 1)); + const Input::AnalogProperties properties_y = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_y", false) != 0, + }; + input_engine->PreSetController(identifier); + input_engine->PreSetAxis(identifier, axis_x); + input_engine->PreSetAxis(identifier, axis_y); + input_engine->PreSetButton(identifier, button); + return std::make_unique(identifier, touch_id, button, toggle, inverted, axis_x, + axis_y, properties_x, properties_y, input_engine.get()); +} + +std::unique_ptr InputFactory::CreateBatteryDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + input_engine->PreSetController(identifier); + return std::make_unique(identifier, input_engine.get()); +} + +std::unique_ptr InputFactory::CreateMotionDevice(Common::ParamPackage params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + if (params.Has("motion")) { + const auto motion_sensor = params.Get("motion", 0); + input_engine->PreSetController(identifier); + input_engine->PreSetMotion(identifier, motion_sensor); + return std::make_unique(identifier, motion_sensor, input_engine.get()); + } + + const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f); + const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); + const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); + + const auto axis_x = static_cast(params.Get("axis_x", 0)); + const Input::AnalogProperties properties_x = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_x", "+") == "-", + }; + + const auto axis_y = static_cast(params.Get("axis_y", 1)); + const Input::AnalogProperties properties_y = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_y", "+") != "+", + }; + + const auto axis_z = static_cast(params.Get("axis_z", 1)); + const Input::AnalogProperties properties_z = { + .deadzone = deadzone, + .range = range, + .threshold = threshold, + .offset = std::clamp(params.Get("offset_z", 0.0f), -1.0f, 1.0f), + .inverted = params.Get("invert_z", "+") != "+", + }; + input_engine->PreSetController(identifier); + input_engine->PreSetAxis(identifier, axis_x); + input_engine->PreSetAxis(identifier, axis_y); + input_engine->PreSetAxis(identifier, axis_z); + return std::make_unique(identifier, axis_x, axis_y, axis_z, properties_x, + properties_y, properties_z, input_engine.get()); +} + +InputFactory::InputFactory(std::shared_ptr input_engine_) + : input_engine(std::move(input_engine_)) {} + +std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { + if (params.Has("button") && params.Has("axis")) { + return CreateTriggerDevice(params); + } + if (params.Has("button") && params.Has("axis_x") && params.Has("axis_y")) { + return CreateTouchDevice(params); + } + if (params.Has("button") || params.Has("code")) { + return CreateButtonDevice(params); + } + if (params.Has("hat")) { + return CreateHatButtonDevice(params); + } + if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { + return CreateMotionDevice(params); + } + if (params.Has("motion")) { + return CreateMotionDevice(params); + } + if (params.Has("axis_x") && params.Has("axis_y")) { + return CreateStickDevice(params); + } + if (params.Has("axis")) { + return CreateAnalogDevice(params); + } + if (params.Has("battery")) { + return CreateBatteryDevice(params); + } + LOG_ERROR(Input, "Invalid parameters given"); + return std::make_unique(); +} + +} // namespace InputCommon diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h new file mode 100644 index 000000000..3c1e5b541 --- /dev/null +++ b/src/input_common/input_poller.h @@ -0,0 +1,189 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +namespace Input { +class InputDevice; + +template +class Factory; +}; // namespace Input + +namespace InputCommon { +class InputEngine; +/** + * An Input factory. It receives input events and forward them to all input devices it created. + */ +class InputFactory final : public Input::Factory { +public: + explicit InputFactory(std::shared_ptr input_engine_); + + /** + * Creates a input device from the parameters given. Identifies the type of input to be returned + * if it contains the following parameters: + * - button: Contains "button" or "code" + * - hat_button: Contains "hat" + * - analog: Contains "axis" + * - trigger: Contains "button" and "axis" + * - stick: Contains "axis_x" and "axis_y" + * - motion: Contains "axis_x", "axis_y" and "axis_z" + * - motion: Contains "motion" + * - touch: Contains "button", "axis_x" and "axis_y" + * - battery: Contains "battery" + * @param params contains parameters for creating the device: + * @param - "code": the code of the keyboard key to bind with the input + * @param - "button": same as "code" but for controller buttons + * @param - "hat": similar as "button" but it's a group of hat buttons from SDL + * @param - "axis": the axis number of the axis to bind with the input + * @param - "motion": the motion number of the motion to bind with the input + * @param - "axis_x": same as axis but specifing horizontal direction + * @param - "axis_y": same as axis but specifing vertical direction + * @param - "axis_z": same as axis but specifing forward direction + * @param - "battery": Only used as a placeholder to set the input type + * @return an unique input device with the parameters specified + */ + std::unique_ptr Create(const Common::ParamPackage& params) override; + +private: + /** + * Creates a button device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "code": the code of the keyboard key to bind with the input + * @param - "button": same as "code" but for controller buttons + * @param - "toggle": press once to enable, press again to disable + * @param - "inverted": inverts the output of the button + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateButtonDevice(const Common::ParamPackage& params); + + /** + * Creates a hat button device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "button": the controller hat id to bind with the input + * @param - "direction": the direction id to be detected + * @param - "toggle": press once to enable, press again to disable + * @param - "inverted": inverts the output of the button + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateHatButtonDevice(const Common::ParamPackage& params); + + /** + * Creates a stick device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "axis_x": the controller horizontal axis id to bind with the input + * @param - "axis_y": the controller vertical axis id to bind with the input + * @param - "deadzone": the mimimum required value to be detected + * @param - "range": the maximum value required to reach 100% + * @param - "threshold": the mimimum required value to considered pressed + * @param - "offset_x": the amount of offset in the x axis + * @param - "offset_y": the amount of offset in the y axis + * @param - "invert_x": inverts the sign of the horizontal axis + * @param - "invert_y": inverts the sign of the vertical axis + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateStickDevice(const Common::ParamPackage& params); + + /** + * Creates an analog device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "axis": the controller axis id to bind with the input + * @param - "deadzone": the mimimum required value to be detected + * @param - "range": the maximum value required to reach 100% + * @param - "threshold": the mimimum required value to considered pressed + * @param - "offset": the amount of offset in the axis + * @param - "invert": inverts the sign of the axis + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateAnalogDevice(const Common::ParamPackage& params); + + /** + * Creates a trigger device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "button": the controller hat id to bind with the input + * @param - "direction": the direction id to be detected + * @param - "toggle": press once to enable, press again to disable + * @param - "inverted": inverts the output of the button + * @param - "axis": the controller axis id to bind with the input + * @param - "deadzone": the mimimum required value to be detected + * @param - "range": the maximum value required to reach 100% + * @param - "threshold": the mimimum required value to considered pressed + * @param - "offset": the amount of offset in the axis + * @param - "invert": inverts the sign of the axis + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateTriggerDevice(const Common::ParamPackage& params); + + /** + * Creates a touch device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "button": the controller hat id to bind with the input + * @param - "direction": the direction id to be detected + * @param - "toggle": press once to enable, press again to disable + * @param - "inverted": inverts the output of the button + * @param - "axis_x": the controller horizontal axis id to bind with the input + * @param - "axis_y": the controller vertical axis id to bind with the input + * @param - "deadzone": the mimimum required value to be detected + * @param - "range": the maximum value required to reach 100% + * @param - "threshold": the mimimum required value to considered pressed + * @param - "offset_x": the amount of offset in the x axis + * @param - "offset_y": the amount of offset in the y axis + * @param - "invert_x": inverts the sign of the horizontal axis + * @param - "invert_y": inverts the sign of the vertical axis + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateTouchDevice(const Common::ParamPackage& params); + + /** + * Creates a battery device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateBatteryDevice(const Common::ParamPackage& params); + + /** + * Creates a motion device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "axis_x": the controller horizontal axis id to bind with the input + * @param - "axis_y": the controller vertical axis id to bind with the input + * @param - "axis_z": the controller fordward axis id to bind with the input + * @param - "deadzone": the mimimum required value to be detected + * @param - "range": the maximum value required to reach 100% + * @param - "offset_x": the amount of offset in the x axis + * @param - "offset_y": the amount of offset in the y axis + * @param - "offset_z": the amount of offset in the z axis + * @param - "invert_x": inverts the sign of the horizontal axis + * @param - "invert_y": inverts the sign of the vertical axis + * @param - "invert_z": inverts the sign of the fordward axis + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique input device with the parameters specified + */ + std::unique_ptr CreateMotionDevice(Common::ParamPackage params); + + std::shared_ptr input_engine; +}; +} // namespace InputCommon diff --git a/src/input_common/main.h b/src/input_common/main.h index 6390d3f09..eb247e164 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -38,6 +38,9 @@ namespace Polling { enum class DeviceType { Button, AnalogPreferred, Motion }; +/// Type of input desired for mapping purposes +enum class InputType { None, Button, Stick, Motion, Touch }; + /** * A class that can be used to get inputs from an input device like controllers without having to * poll the device's status yourself From 4c6f2c2547e1d97f12ebe708fac693a6183bbc45 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 16:57:55 -0500 Subject: [PATCH 053/291] input_common: Move touch and analog from button. Move udp protocol --- src/input_common/CMakeLists.txt | 12 +- .../stick_from_buttons.cpp} | 144 +++++++++++------- .../stick_from_buttons.h} | 8 +- .../helpers/touch_from_buttons.cpp | 70 +++++++++ .../touch_from_buttons.h} | 7 +- .../protocol.cpp => helpers/udp_protocol.cpp} | 2 +- .../protocol.h => helpers/udp_protocol.h} | 0 src/input_common/main.cpp | 8 - src/input_common/touch_from_button.cpp | 53 ------- src/input_common/udp/client.cpp | 2 +- 10 files changed, 173 insertions(+), 133 deletions(-) rename src/input_common/{analog_from_button.cpp => helpers/stick_from_buttons.cpp} (56%) mode change 100755 => 100644 rename src/input_common/{analog_from_button.h => helpers/stick_from_buttons.h} (82%) mode change 100755 => 100644 create mode 100644 src/input_common/helpers/touch_from_buttons.cpp rename src/input_common/{touch_from_button.h => helpers/touch_from_buttons.h} (68%) rename src/input_common/{udp/protocol.cpp => helpers/udp_protocol.cpp} (98%) rename src/input_common/{udp/protocol.h => helpers/udp_protocol.h} (100%) delete mode 100644 src/input_common/touch_from_button.cpp diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 72f1e0f4a..90e7618ce 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,8 +1,12 @@ add_library(input_common STATIC - analog_from_button.cpp - analog_from_button.h keyboard.cpp keyboard.h + helpers/stick_from_buttons.cpp + helpers/stick_from_buttons.h + helpers/touch_from_buttons.cpp + helpers/touch_from_buttons.h + helpers/udp_protocol.cpp + helpers/udp_protocol.h input_engine.cpp input_engine.h input_mapping.cpp @@ -15,8 +19,6 @@ add_library(input_common STATIC motion_from_button.h motion_input.cpp motion_input.h - touch_from_button.cpp - touch_from_button.h gcadapter/gc_adapter.cpp gcadapter/gc_adapter.h gcadapter/gc_poller.cpp @@ -33,8 +35,6 @@ add_library(input_common STATIC tas/tas_poller.h udp/client.cpp udp/client.h - udp/protocol.cpp - udp/protocol.h udp/udp.cpp udp/udp.h ) diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/helpers/stick_from_buttons.cpp old mode 100755 new mode 100644 similarity index 56% rename from src/input_common/analog_from_button.cpp rename to src/input_common/helpers/stick_from_buttons.cpp index 2fafd077f..38f150746 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -2,32 +2,38 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include #include -#include #include "common/math_util.h" #include "common/settings.h" -#include "input_common/analog_from_button.h" +#include "input_common/helpers/stick_from_buttons.h" namespace InputCommon { -class Analog final : public Input::AnalogDevice { +class Stick final : public Input::InputDevice { public: - using Button = std::unique_ptr; + using Button = std::unique_ptr; - Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, - float modifier_scale_, float modifier_angle_) + Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, + float modifier_scale_, float modifier_angle_) : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { - Input::InputCallback callbacks{ - [this]([[maybe_unused]] bool status) { UpdateStatus(); }}; - up->SetCallback(callbacks); - down->SetCallback(callbacks); - left->SetCallback(callbacks); - right->SetCallback(callbacks); - modifier->SetCallback(callbacks); + Input::InputCallback button_up_callback{ + [this](Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; + Input::InputCallback button_down_callback{ + [this](Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; + Input::InputCallback button_left_callback{ + [this](Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; + Input::InputCallback button_right_callback{ + [this](Input::CallbackStatus callback_) { UpdateRightButtonStatus(callback_); }}; + Input::InputCallback button_modifier_callback{ + [this](Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; + up->SetCallback(button_up_callback); + down->SetCallback(button_down_callback); + left->SetCallback(button_left_callback); + right->SetCallback(button_right_callback); + modifier->SetCallback(button_modifier_callback); } bool IsAngleGreater(float old_angle, float new_angle) const { @@ -123,13 +129,38 @@ public: } } - void UpdateStatus() { - const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; + void UpdateUpButtonStatus(Input::CallbackStatus button_callback) { + up_status = button_callback.button_status.value; + UpdateStatus(); + } - bool r = right->GetStatus(); - bool l = left->GetStatus(); - bool u = up->GetStatus(); - bool d = down->GetStatus(); + void UpdateDownButtonStatus(Input::CallbackStatus button_callback) { + down_status = button_callback.button_status.value; + UpdateStatus(); + } + + void UpdateLeftButtonStatus(Input::CallbackStatus button_callback) { + left_status = button_callback.button_status.value; + UpdateStatus(); + } + + void UpdateRightButtonStatus(Input::CallbackStatus button_callback) { + right_status = button_callback.button_status.value; + UpdateStatus(); + } + + void UpdateModButtonStatus(Input::CallbackStatus button_callback) { + modifier_status = button_callback.button_status.value; + UpdateStatus(); + } + + void UpdateStatus() { + const float coef = modifier_status ? modifier_scale : 1.0f; + + bool r = right_status; + bool l = left_status; + bool u = up_status; + bool d = down_status; // Eliminate contradictory movements if (r && l) { @@ -162,49 +193,42 @@ public: } last_update = now; + Input::CallbackStatus status{ + .type = Input::InputType::Stick, + .stick_status = GetStatus(), + }; + TriggerOnChange(status); } - std::tuple GetStatus() const override { + Input::StickStatus GetStatus() const { + Input::StickStatus status{}; + status.x.properties = properties; + status.y.properties = properties; if (Settings::values.emulate_analog_keyboard) { const auto now = std::chrono::steady_clock::now(); float angle_ = GetAngle(now); - return std::make_tuple(std::cos(angle_) * amplitude, std::sin(angle_) * amplitude); + status.x.raw_value = std::cos(angle_) * amplitude; + status.y.raw_value = std::sin(angle_) * amplitude; + return status; } constexpr float SQRT_HALF = 0.707106781f; int x = 0, y = 0; - if (right->GetStatus()) { + if (right_status) { ++x; } - if (left->GetStatus()) { + if (left_status) { --x; } - if (up->GetStatus()) { + if (up_status) { ++y; } - if (down->GetStatus()) { + if (down_status) { --y; } - const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; - return std::make_tuple(static_cast(x) * coef * (y == 0 ? 1.0f : SQRT_HALF), - static_cast(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {modifier_scale, 1.0f, 0.5f}; - } - - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { - switch (direction) { - case Input::AnalogDirection::RIGHT: - return right->GetStatus(); - case Input::AnalogDirection::LEFT: - return left->GetStatus(); - case Input::AnalogDirection::UP: - return up->GetStatus(); - case Input::AnalogDirection::DOWN: - return down->GetStatus(); - } - return false; + const float coef = modifier_status ? modifier_scale : 1.0f; + status.x.raw_value = static_cast(x) * coef * (y == 0 ? 1.0f : SQRT_HALF); + status.y.raw_value = static_cast(y) * coef * (x == 0 ? 1.0f : SQRT_HALF); + return status; } private: @@ -218,21 +242,29 @@ private: float angle{}; float goal_angle{}; float amplitude{}; + bool up_status; + bool down_status; + bool left_status; + bool right_status; + bool modifier_status; + const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point last_update; }; -std::unique_ptr AnalogFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto up = Input::CreateDevice(params.Get("up", null_engine)); - auto down = Input::CreateDevice(params.Get("down", null_engine)); - auto left = Input::CreateDevice(params.Get("left", null_engine)); - auto right = Input::CreateDevice(params.Get("right", null_engine)); - auto modifier = Input::CreateDevice(params.Get("modifier", null_engine)); + auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); + auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); + auto left = Input::CreateDeviceFromString(params.Get("left", null_engine)); + auto right = + Input::CreateDeviceFromString(params.Get("right", null_engine)); + auto modifier = + Input::CreateDeviceFromString(params.Get("modifier", null_engine)); auto modifier_scale = params.Get("modifier_scale", 0.5f); auto modifier_angle = params.Get("modifier_angle", 5.5f); - return std::make_unique(std::move(up), std::move(down), std::move(left), - std::move(right), std::move(modifier), modifier_scale, - modifier_angle); + return std::make_unique(std::move(up), std::move(down), std::move(left), + std::move(right), std::move(modifier), modifier_scale, + modifier_angle); } } // namespace InputCommon diff --git a/src/input_common/analog_from_button.h b/src/input_common/helpers/stick_from_buttons.h old mode 100755 new mode 100644 similarity index 82% rename from src/input_common/analog_from_button.h rename to src/input_common/helpers/stick_from_buttons.h index bbd583dd9..1d6e24c98 --- a/src/input_common/analog_from_button.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -1,11 +1,11 @@ + // Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once -#include -#include "core/frontend/input.h" +#include "common/input.h" namespace InputCommon { @@ -13,7 +13,7 @@ namespace InputCommon { * An analog device factory that takes direction button devices and combines them into a analog * device. */ -class AnalogFromButton final : public Input::Factory { +class StickFromButton final : public Input::Factory { public: /** * Creates an analog device from direction button devices @@ -25,7 +25,7 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp new file mode 100644 index 000000000..2abfaf841 --- /dev/null +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -0,0 +1,70 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/settings.h" +#include "core/frontend/framebuffer_layout.h" +#include "input_common/helpers/touch_from_buttons.h" + +namespace InputCommon { + +class TouchFromButtonDevice final : public Input::InputDevice { +public: + using Button = std::unique_ptr; + TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_) + : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { + Input::InputCallback button_up_callback{ + [this](Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; + button->SetCallback(button_up_callback); + } + + Input::TouchStatus GetStatus(bool pressed) const { + const Input::ButtonStatus button_status{ + .value = pressed, + }; + Input::TouchStatus status{ + .pressed = button_status, + .x = {}, + .y = {}, + .id = touch_id, + }; + status.x.properties = properties; + status.y.properties = properties; + + if (!pressed) { + return status; + } + + status.x.raw_value = x; + status.y.raw_value = y; + return status; + } + + void UpdateButtonStatus(Input::CallbackStatus button_callback) { + const Input::CallbackStatus status{ + .type = Input::InputType::Touch, + .touch_status = GetStatus(button_callback.button_status.value), + }; + TriggerOnChange(status); + } + +private: + Button button; + const u32 touch_id; + const float x; + const float y; + const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; +}; + +std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { + const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); + auto button = + Input::CreateDeviceFromString(params.Get("button", null_engine)); + const auto touch_id = params.Get("touch_id", 0); + const float x = params.Get("x", 0.0f) / 1280.0f; + const float y = params.Get("y", 0.0f) / 720.0f; + return std::make_unique(std::move(button), touch_id, x, y); +} + +} // namespace InputCommon diff --git a/src/input_common/touch_from_button.h b/src/input_common/helpers/touch_from_buttons.h similarity index 68% rename from src/input_common/touch_from_button.h rename to src/input_common/helpers/touch_from_buttons.h index 8b4d1aa96..21b353728 100644 --- a/src/input_common/touch_from_button.h +++ b/src/input_common/helpers/touch_from_buttons.h @@ -4,20 +4,19 @@ #pragma once -#include -#include "core/frontend/input.h" +#include "common/input.h" namespace InputCommon { /** * A touch device factory that takes a list of button devices and combines them into a touch device. */ -class TouchFromButtonFactory final : public Input::Factory { +class TouchFromButton final : public Input::Factory { public: /** * Creates a touch device from a list of button devices */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/udp/protocol.cpp b/src/input_common/helpers/udp_protocol.cpp similarity index 98% rename from src/input_common/udp/protocol.cpp rename to src/input_common/helpers/udp_protocol.cpp index 5e50bd612..cdeab7e11 100644 --- a/src/input_common/udp/protocol.cpp +++ b/src/input_common/helpers/udp_protocol.cpp @@ -5,7 +5,7 @@ #include #include #include "common/logging/log.h" -#include "input_common/udp/protocol.h" +#include "input_common/helpers/udp_protocol.h" namespace InputCommon::CemuhookUDP { diff --git a/src/input_common/udp/protocol.h b/src/input_common/helpers/udp_protocol.h similarity index 100% rename from src/input_common/udp/protocol.h rename to src/input_common/helpers/udp_protocol.h diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index f3907c65a..7a5c29b40 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -6,7 +6,6 @@ #include #include "common/param_package.h" #include "common/settings.h" -#include "input_common/analog_from_button.h" #include "input_common/gcadapter/gc_adapter.h" #include "input_common/gcadapter/gc_poller.h" #include "input_common/keyboard.h" @@ -16,7 +15,6 @@ #include "input_common/mouse/mouse_poller.h" #include "input_common/tas/tas_input.h" #include "input_common/tas/tas_poller.h" -#include "input_common/touch_from_button.h" #include "input_common/udp/client.h" #include "input_common/udp/udp.h" #ifdef HAVE_SDL2 @@ -37,12 +35,8 @@ struct InputSubsystem::Impl { keyboard = std::make_shared(); Input::RegisterFactory("keyboard", keyboard); - Input::RegisterFactory("analog_from_button", - std::make_shared()); Input::RegisterFactory("keyboard", std::make_shared()); - Input::RegisterFactory("touch_from_button", - std::make_shared()); #ifdef HAVE_SDL2 sdl = SDL::Init(); @@ -75,8 +69,6 @@ struct InputSubsystem::Impl { Input::UnregisterFactory("keyboard"); Input::UnregisterFactory("keyboard"); keyboard.reset(); - Input::UnregisterFactory("analog_from_button"); - Input::UnregisterFactory("touch_from_button"); #ifdef HAVE_SDL2 sdl.reset(); #endif diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp deleted file mode 100644 index 7878a56d7..000000000 --- a/src/input_common/touch_from_button.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/settings.h" -#include "core/frontend/framebuffer_layout.h" -#include "input_common/touch_from_button.h" - -namespace InputCommon { - -class TouchFromButtonDevice final : public Input::TouchDevice { -public: - TouchFromButtonDevice() { - const auto button_index = - static_cast(Settings::values.touch_from_button_map_index.GetValue()); - const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons; - - for (const auto& config_entry : buttons) { - const Common::ParamPackage package{config_entry}; - map.emplace_back( - Input::CreateDevice(config_entry), - std::clamp(package.Get("x", 0), 0, static_cast(Layout::ScreenUndocked::Width)), - std::clamp(package.Get("y", 0), 0, - static_cast(Layout::ScreenUndocked::Height))); - } - } - - Input::TouchStatus GetStatus() const override { - Input::TouchStatus touch_status{}; - for (std::size_t id = 0; id < map.size() && id < touch_status.size(); ++id) { - const bool state = std::get<0>(map[id])->GetStatus(); - if (state) { - const float x = static_cast(std::get<1>(map[id])) / - static_cast(Layout::ScreenUndocked::Width); - const float y = static_cast(std::get<2>(map[id])) / - static_cast(Layout::ScreenUndocked::Height); - touch_status[id] = {x, y, true}; - } - } - return touch_status; - } - -private: - // A vector of the mapped button, its x and its y-coordinate - std::vector, int, int>> map; -}; - -std::unique_ptr TouchFromButtonFactory::Create(const Common::ParamPackage&) { - return std::make_unique(); -} - -} // namespace InputCommon diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index b9512aa2e..bcc29c4e0 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -11,7 +11,7 @@ #include "common/logging/log.h" #include "common/settings.h" #include "input_common/udp/client.h" -#include "input_common/udp/protocol.h" +#include "input_common/helpers/udp_protocol.h" using boost::asio::ip::udp; From 5a785ed794fff8c944283271bf25cb835c11700a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:18:40 -0500 Subject: [PATCH 054/291] input_common: Rewrite keyboard --- src/input_common/CMakeLists.txt | 4 +- src/input_common/drivers/keyboard.cpp | 35 +++ src/input_common/{ => drivers}/keyboard.h | 29 +- src/input_common/keyboard.cpp | 121 -------- src/input_common/main.cpp | 263 +----------------- src/input_common/main.h | 89 ------ src/yuzu/bootmanager.cpp | 56 ++-- src/yuzu/bootmanager.h | 2 +- .../configuration/configure_input_player.cpp | 83 +----- src/yuzu/debugger/controller.cpp | 3 +- src/yuzu/main.cpp | 18 +- 11 files changed, 92 insertions(+), 611 deletions(-) create mode 100644 src/input_common/drivers/keyboard.cpp rename src/input_common/{ => drivers}/keyboard.h (52%) delete mode 100644 src/input_common/keyboard.cpp diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 90e7618ce..0fcf7a9d7 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(input_common STATIC - keyboard.cpp - keyboard.h + drivers/keyboard.cpp + drivers/keyboard.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp new file mode 100644 index 000000000..b00a4b8d9 --- /dev/null +++ b/src/input_common/drivers/keyboard.cpp @@ -0,0 +1,35 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/param_package.h" +#include "input_common/drivers/keyboard.h" + +namespace InputCommon { + +Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); +} + +void Keyboard::PressKey(int key_code) { + SetButton(identifier, key_code, true); +} + +void Keyboard::ReleaseKey(int key_code) { + SetButton(identifier, key_code, false); +} + +void Keyboard::ReleaseAllKeys() { + ResetButtonState(); +} + +std::vector Keyboard::GetInputDevices() const { + std::vector devices; + devices.emplace_back(Common::ParamPackage{ + {"engine", "keyboard"}, + {"display", "Keyboard Only"}, + }); + return devices; +} + +} // namespace InputCommon diff --git a/src/input_common/keyboard.h b/src/input_common/drivers/keyboard.h similarity index 52% rename from src/input_common/keyboard.h rename to src/input_common/drivers/keyboard.h index 861950472..a3e0d8a61 100644 --- a/src/input_common/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -1,30 +1,20 @@ -// Copyright 2017 Citra Emulator Project +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// Refer to the license.txt file included #pragma once -#include -#include "core/frontend/input.h" +#include "input_common/input_engine.h" namespace InputCommon { -class KeyButtonList; - /** * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class Keyboard final : public Input::Factory { +class Keyboard final : public InputCommon::InputEngine { public: - Keyboard(); - - /** - * Creates a button device from a keyboard key - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + explicit Keyboard(const std::string& input_engine_); /** * Sets the status of all buttons bound with the key to pressed @@ -40,8 +30,15 @@ public: void ReleaseAllKeys(); + /// Used for automapping features + std::vector GetInputDevices() const override; + private: - std::shared_ptr key_button_list; + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; }; } // namespace InputCommon diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp deleted file mode 100644 index 8261e76fd..000000000 --- a/src/input_common/keyboard.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include "input_common/keyboard.h" - -namespace InputCommon { - -class KeyButton final : public Input::ButtonDevice { -public: - explicit KeyButton(std::shared_ptr key_button_list_, bool toggle_) - : key_button_list(std::move(key_button_list_)), toggle(toggle_) {} - - ~KeyButton() override; - - bool GetStatus() const override { - if (toggle) { - return toggled_status.load(std::memory_order_relaxed); - } - return status.load(); - } - - void ToggleButton() { - if (lock) { - return; - } - lock = true; - const bool old_toggle_status = toggled_status.load(); - toggled_status.store(!old_toggle_status); - } - - void UnlockButton() { - lock = false; - } - - friend class KeyButtonList; - -private: - std::shared_ptr key_button_list; - std::atomic status{false}; - std::atomic toggled_status{false}; - bool lock{false}; - const bool toggle; -}; - -struct KeyButtonPair { - int key_code; - KeyButton* key_button; -}; - -class KeyButtonList { -public: - void AddKeyButton(int key_code, KeyButton* key_button) { - std::lock_guard guard{mutex}; - list.push_back(KeyButtonPair{key_code, key_button}); - } - - void RemoveKeyButton(const KeyButton* key_button) { - std::lock_guard guard{mutex}; - list.remove_if( - [key_button](const KeyButtonPair& pair) { return pair.key_button == key_button; }); - } - - void ChangeKeyStatus(int key_code, bool pressed) { - std::lock_guard guard{mutex}; - for (const KeyButtonPair& pair : list) { - if (pair.key_code == key_code) { - pair.key_button->status.store(pressed); - if (pressed) { - pair.key_button->ToggleButton(); - } else { - pair.key_button->UnlockButton(); - } - pair.key_button->TriggerOnChange(); - } - } - } - - void ChangeAllKeyStatus(bool pressed) { - std::lock_guard guard{mutex}; - for (const KeyButtonPair& pair : list) { - pair.key_button->status.store(pressed); - } - } - -private: - std::mutex mutex; - std::list list; -}; - -Keyboard::Keyboard() : key_button_list{std::make_shared()} {} - -KeyButton::~KeyButton() { - key_button_list->RemoveKeyButton(this); -} - -std::unique_ptr Keyboard::Create(const Common::ParamPackage& params) { - const int key_code = params.Get("code", 0); - const bool toggle = params.Get("toggle", false); - std::unique_ptr button = std::make_unique(key_button_list, toggle); - key_button_list->AddKeyButton(key_code, button.get()); - return button; -} - -void Keyboard::PressKey(int key_code) { - key_button_list->ChangeKeyStatus(key_code, true); -} - -void Keyboard::ReleaseKey(int key_code) { - key_button_list->ChangeKeyStatus(key_code, false); -} - -void Keyboard::ReleaseAllKeys() { - key_button_list->ChangeAllKeyStatus(false); -} - -} // namespace InputCommon diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 7a5c29b40..da501b6cc 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -6,17 +6,7 @@ #include #include "common/param_package.h" #include "common/settings.h" -#include "input_common/gcadapter/gc_adapter.h" -#include "input_common/gcadapter/gc_poller.h" -#include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_from_button.h" -#include "input_common/mouse/mouse_input.h" -#include "input_common/mouse/mouse_poller.h" -#include "input_common/tas/tas_input.h" -#include "input_common/tas/tas_poller.h" -#include "input_common/udp/client.h" -#include "input_common/udp/udp.h" #ifdef HAVE_SDL2 #include "input_common/sdl/sdl.h" #endif @@ -25,82 +15,9 @@ namespace InputCommon { struct InputSubsystem::Impl { void Initialize() { - gcadapter = std::make_shared(); - gcbuttons = std::make_shared(gcadapter); - Input::RegisterFactory("gcpad", gcbuttons); - gcanalog = std::make_shared(gcadapter); - Input::RegisterFactory("gcpad", gcanalog); - gcvibration = std::make_shared(gcadapter); - Input::RegisterFactory("gcpad", gcvibration); - - keyboard = std::make_shared(); - Input::RegisterFactory("keyboard", keyboard); - Input::RegisterFactory("keyboard", - std::make_shared()); - -#ifdef HAVE_SDL2 - sdl = SDL::Init(); -#endif - - udp = std::make_shared(); - udpmotion = std::make_shared(udp); - Input::RegisterFactory("cemuhookudp", udpmotion); - udptouch = std::make_shared(udp); - Input::RegisterFactory("cemuhookudp", udptouch); - - mouse = std::make_shared(); - mousebuttons = std::make_shared(mouse); - Input::RegisterFactory("mouse", mousebuttons); - mouseanalog = std::make_shared(mouse); - Input::RegisterFactory("mouse", mouseanalog); - mousemotion = std::make_shared(mouse); - Input::RegisterFactory("mouse", mousemotion); - mousetouch = std::make_shared(mouse); - Input::RegisterFactory("mouse", mousetouch); - - tas = std::make_shared(); - tasbuttons = std::make_shared(tas); - Input::RegisterFactory("tas", tasbuttons); - tasanalog = std::make_shared(tas); - Input::RegisterFactory("tas", tasanalog); } void Shutdown() { - Input::UnregisterFactory("keyboard"); - Input::UnregisterFactory("keyboard"); - keyboard.reset(); -#ifdef HAVE_SDL2 - sdl.reset(); -#endif - Input::UnregisterFactory("gcpad"); - Input::UnregisterFactory("gcpad"); - Input::UnregisterFactory("gcpad"); - - gcbuttons.reset(); - gcanalog.reset(); - gcvibration.reset(); - - Input::UnregisterFactory("cemuhookudp"); - Input::UnregisterFactory("cemuhookudp"); - - udpmotion.reset(); - udptouch.reset(); - - Input::UnregisterFactory("mouse"); - Input::UnregisterFactory("mouse"); - Input::UnregisterFactory("mouse"); - Input::UnregisterFactory("mouse"); - - mousebuttons.reset(); - mouseanalog.reset(); - mousemotion.reset(); - mousetouch.reset(); - - Input::UnregisterFactory("tas"); - Input::UnregisterFactory("tas"); - - tasbuttons.reset(); - tasanalog.reset(); } [[nodiscard]] std::vector GetInputDevices() const { @@ -108,19 +25,7 @@ struct InputSubsystem::Impl { Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, }; - if (Settings::values.tas_enable) { - devices.emplace_back( - Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); - } -#ifdef HAVE_SDL2 - auto sdl_devices = sdl->GetInputDevices(); - devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); -#endif - auto udp_devices = udp->GetInputDevices(); - devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); - auto gcpad_devices = gcadapter->GetInputDevices(); - devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end()); - return devices; + return {}; } [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( @@ -128,17 +33,6 @@ struct InputSubsystem::Impl { if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - if (params.Get("class", "") == "gcpad") { - return gcadapter->GetAnalogMappingForDevice(params); - } - if (params.Get("class", "") == "tas") { - return tas->GetAnalogMappingForDevice(params); - } -#ifdef HAVE_SDL2 - if (params.Get("class", "") == "sdl") { - return sdl->GetAnalogMappingForDevice(params); - } -#endif return {}; } @@ -147,17 +41,6 @@ struct InputSubsystem::Impl { if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - if (params.Get("class", "") == "gcpad") { - return gcadapter->GetButtonMappingForDevice(params); - } - if (params.Get("class", "") == "tas") { - return tas->GetButtonMappingForDevice(params); - } -#ifdef HAVE_SDL2 - if (params.Get("class", "") == "sdl") { - return sdl->GetButtonMappingForDevice(params); - } -#endif return {}; } @@ -166,37 +49,9 @@ struct InputSubsystem::Impl { if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - if (params.Get("class", "") == "cemuhookudp") { - // TODO return the correct motion device - return {}; - } -#ifdef HAVE_SDL2 - if (params.Get("class", "") == "sdl") { - return sdl->GetMotionMappingForDevice(params); - } -#endif return {}; } - std::shared_ptr keyboard; -#ifdef HAVE_SDL2 - std::unique_ptr sdl; -#endif - std::shared_ptr gcbuttons; - std::shared_ptr gcanalog; - std::shared_ptr gcvibration; - std::shared_ptr udpmotion; - std::shared_ptr udptouch; - std::shared_ptr mousebuttons; - std::shared_ptr mouseanalog; - std::shared_ptr mousemotion; - std::shared_ptr mousetouch; - std::shared_ptr tasbuttons; - std::shared_ptr tasanalog; - std::shared_ptr udp; - std::shared_ptr gcadapter; - std::shared_ptr mouse; - std::shared_ptr tas; }; InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} @@ -211,30 +66,6 @@ void InputSubsystem::Shutdown() { impl->Shutdown(); } -Keyboard* InputSubsystem::GetKeyboard() { - return impl->keyboard.get(); -} - -const Keyboard* InputSubsystem::GetKeyboard() const { - return impl->keyboard.get(); -} - -MouseInput::Mouse* InputSubsystem::GetMouse() { - return impl->mouse.get(); -} - -const MouseInput::Mouse* InputSubsystem::GetMouse() const { - return impl->mouse.get(); -} - -TasInput::Tas* InputSubsystem::GetTas() { - return impl->tas.get(); -} - -const TasInput::Tas* InputSubsystem::GetTas() const { - return impl->tas.get(); -} - std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } @@ -251,100 +82,12 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka return impl->GetMotionMappingForDevice(device); } -GCAnalogFactory* InputSubsystem::GetGCAnalogs() { - return impl->gcanalog.get(); -} - -const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const { - return impl->gcanalog.get(); -} - -GCButtonFactory* InputSubsystem::GetGCButtons() { - return impl->gcbuttons.get(); -} - -const GCButtonFactory* InputSubsystem::GetGCButtons() const { - return impl->gcbuttons.get(); -} - -UDPMotionFactory* InputSubsystem::GetUDPMotions() { - return impl->udpmotion.get(); -} - -const UDPMotionFactory* InputSubsystem::GetUDPMotions() const { - return impl->udpmotion.get(); -} - -UDPTouchFactory* InputSubsystem::GetUDPTouch() { - return impl->udptouch.get(); -} - -const UDPTouchFactory* InputSubsystem::GetUDPTouch() const { - return impl->udptouch.get(); -} - -MouseButtonFactory* InputSubsystem::GetMouseButtons() { - return impl->mousebuttons.get(); -} - -const MouseButtonFactory* InputSubsystem::GetMouseButtons() const { - return impl->mousebuttons.get(); -} - -MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() { - return impl->mouseanalog.get(); -} - -const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const { - return impl->mouseanalog.get(); -} - -MouseMotionFactory* InputSubsystem::GetMouseMotions() { - return impl->mousemotion.get(); -} - -const MouseMotionFactory* InputSubsystem::GetMouseMotions() const { - return impl->mousemotion.get(); -} - -MouseTouchFactory* InputSubsystem::GetMouseTouch() { - return impl->mousetouch.get(); -} - -const MouseTouchFactory* InputSubsystem::GetMouseTouch() const { - return impl->mousetouch.get(); -} - -TasButtonFactory* InputSubsystem::GetTasButtons() { - return impl->tasbuttons.get(); -} - -const TasButtonFactory* InputSubsystem::GetTasButtons() const { - return impl->tasbuttons.get(); -} - -TasAnalogFactory* InputSubsystem::GetTasAnalogs() { - return impl->tasanalog.get(); -} - -const TasAnalogFactory* InputSubsystem::GetTasAnalogs() const { - return impl->tasanalog.get(); -} - void InputSubsystem::ReloadInputDevices() { - if (!impl->udp) { - return; - } - impl->udp->ReloadSockets(); } -std::vector> InputSubsystem::GetPollers( - [[maybe_unused]] Polling::DeviceType type) const { -#ifdef HAVE_SDL2 - return impl->sdl->GetPollers(type); -#else +std::vector> InputSubsystem::GetPollers([ + [maybe_unused]] Polling::DeviceType type) const { return {}; -#endif } std::string GenerateKeyboardParam(int key_code) { diff --git a/src/input_common/main.h b/src/input_common/main.h index eb247e164..b504ebe54 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -63,18 +63,6 @@ public: }; } // namespace Polling -class GCAnalogFactory; -class GCButtonFactory; -class UDPMotionFactory; -class UDPTouchFactory; -class MouseButtonFactory; -class MouseAnalogFactory; -class MouseMotionFactory; -class MouseTouchFactory; -class TasButtonFactory; -class TasAnalogFactory; -class Keyboard; - /** * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default * mapping for the device. This is currently only implemented for the SDL backend devices. @@ -100,23 +88,6 @@ public: /// Unregisters all built-in input device factories and shuts them down. void Shutdown(); - /// Retrieves the underlying keyboard device. - [[nodiscard]] Keyboard* GetKeyboard(); - - /// Retrieves the underlying keyboard device. - [[nodiscard]] const Keyboard* GetKeyboard() const; - - /// Retrieves the underlying mouse device. - [[nodiscard]] MouseInput::Mouse* GetMouse(); - - /// Retrieves the underlying mouse device. - [[nodiscard]] const MouseInput::Mouse* GetMouse() const; - - /// Retrieves the underlying tas device. - [[nodiscard]] TasInput::Tas* GetTas(); - - /// Retrieves the underlying tas device. - [[nodiscard]] const TasInput::Tas* GetTas() const; /** * Returns all available input devices that this Factory can create a new device with. * Each returned ParamPackage should have a `display` field used for display, a class field for @@ -134,66 +105,6 @@ public: /// Retrieves the motion mappings for the given device. [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; - /// Retrieves the underlying GameCube analog handler. - [[nodiscard]] GCAnalogFactory* GetGCAnalogs(); - - /// Retrieves the underlying GameCube analog handler. - [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const; - - /// Retrieves the underlying GameCube button handler. - [[nodiscard]] GCButtonFactory* GetGCButtons(); - - /// Retrieves the underlying GameCube button handler. - [[nodiscard]] const GCButtonFactory* GetGCButtons() const; - - /// Retrieves the underlying udp motion handler. - [[nodiscard]] UDPMotionFactory* GetUDPMotions(); - - /// Retrieves the underlying udp motion handler. - [[nodiscard]] const UDPMotionFactory* GetUDPMotions() const; - - /// Retrieves the underlying udp touch handler. - [[nodiscard]] UDPTouchFactory* GetUDPTouch(); - - /// Retrieves the underlying udp touch handler. - [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; - - /// Retrieves the underlying mouse button handler. - [[nodiscard]] MouseButtonFactory* GetMouseButtons(); - - /// Retrieves the underlying mouse button handler. - [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const; - - /// Retrieves the underlying mouse analog handler. - [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs(); - - /// Retrieves the underlying mouse analog handler. - [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const; - - /// Retrieves the underlying mouse motion handler. - [[nodiscard]] MouseMotionFactory* GetMouseMotions(); - - /// Retrieves the underlying mouse motion handler. - [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const; - - /// Retrieves the underlying mouse touch handler. - [[nodiscard]] MouseTouchFactory* GetMouseTouch(); - - /// Retrieves the underlying mouse touch handler. - [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const; - - /// Retrieves the underlying tas button handler. - [[nodiscard]] TasButtonFactory* GetTasButtons(); - - /// Retrieves the underlying tas button handler. - [[nodiscard]] const TasButtonFactory* GetTasButtons() const; - - /// Retrieves the underlying tas analogs handler. - [[nodiscard]] TasAnalogFactory* GetTasAnalogs(); - - /// Retrieves the underlying tas analogs handler. - [[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const; - /// Reloads the input devices void ReloadInputDevices(); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index fd0a130a3..8a0ea90f9 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -34,8 +34,6 @@ #include "core/frontend/framebuffer_layout.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/mouse/mouse_input.h" -#include "input_common/tas/tas_input.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" #include "yuzu/bootmanager.h" @@ -394,34 +392,34 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - input_subsystem->GetKeyboard()->PressKey(event->key()); + // input_subsystem->GetKeyboard()->PressKey(event->key()); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - input_subsystem->GetKeyboard()->ReleaseKey(event->key()); + // input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } -MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { - switch (button) { - case Qt::LeftButton: - return MouseInput::MouseButton::Left; - case Qt::RightButton: - return MouseInput::MouseButton::Right; - case Qt::MiddleButton: - return MouseInput::MouseButton::Wheel; - case Qt::BackButton: - return MouseInput::MouseButton::Backward; - case Qt::ForwardButton: - return MouseInput::MouseButton::Forward; - case Qt::TaskButton: - return MouseInput::MouseButton::Task; - default: - return MouseInput::MouseButton::Extra; - } -} +//MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { +// switch (button) { +// case Qt::LeftButton: +// return MouseInput::MouseButton::Left; +// case Qt::RightButton: +// return MouseInput::MouseButton::Right; +// case Qt::MiddleButton: +// return MouseInput::MouseButton::Wheel; +// case Qt::BackButton: +// return MouseInput::MouseButton::Backward; +// case Qt::ForwardButton: +// return MouseInput::MouseButton::Forward; +// case Qt::TaskButton: +// return MouseInput::MouseButton::Task; +// default: +// return MouseInput::MouseButton::Extra; +// } +//} void GRenderWindow::mousePressEvent(QMouseEvent* event) { // Touch input is handled in TouchBeginEvent @@ -432,8 +430,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { // coordinates and map them to the current render area const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); - const auto button = QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(x, y, button); + //const auto button = QtButtonToMouseButton(event->button()); + //input_subsystem->GetMouse()->PressButton(x, y, button); if (event->button() == Qt::LeftButton) { this->TouchPressed(x, y, 0); @@ -453,7 +451,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { const auto [x, y] = ScaleTouch(pos); const int center_x = width() / 2; const int center_y = height() / 2; - input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y); + //input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y); this->TouchMoved(x, y, 0); if (Settings::values.mouse_panning) { @@ -469,8 +467,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { return; } - const auto button = QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->ReleaseButton(button); + //const auto button = QtButtonToMouseButton(event->button()); + //input_subsystem->GetMouse()->ReleaseButton(button); if (event->button() == Qt::LeftButton) { this->TouchReleased(0); @@ -558,8 +556,8 @@ bool GRenderWindow::event(QEvent* event) { void GRenderWindow::focusOutEvent(QFocusEvent* event) { QWidget::focusOutEvent(event); - input_subsystem->GetKeyboard()->ReleaseAllKeys(); - input_subsystem->GetMouse()->ReleaseAllButtons(); + //input_subsystem->GetKeyboard()->ReleaseAllKeys(); + //input_subsystem->GetMouse()->ReleaseAllButtons(); this->TouchReleased(0); } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 061e3605f..f0784046b 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -165,7 +165,7 @@ public: void keyReleaseEvent(QKeyEvent* event) override; /// Converts a Qt mouse button into MouseInput mouse button - static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); + // static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 3aab5d5f8..09f0b219b 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -16,10 +16,7 @@ #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/sm/sm.h" -#include "input_common/gcadapter/gc_poller.h" #include "input_common/main.h" -#include "input_common/mouse/mouse_poller.h" -#include "input_common/udp/udp.h" #include "ui_configure_input_player.h" #include "yuzu/bootmanager.h" #include "yuzu/configuration/config.h" @@ -564,55 +561,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(poll_timer.get(), &QTimer::timeout, [this] { Common::ParamPackage params; - if (input_subsystem->GetGCButtons()->IsPolling()) { - params = input_subsystem->GetGCButtons()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetGCAnalogs()->IsPolling()) { - params = input_subsystem->GetGCAnalogs()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetUDPMotions()->IsPolling()) { - params = input_subsystem->GetUDPMotions()->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetMouseButtons()->IsPolling()) { - params = input_subsystem->GetMouseButtons()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetMouseAnalogs()->IsPolling()) { - params = input_subsystem->GetMouseAnalogs()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetMouseMotions()->IsPolling()) { - params = input_subsystem->GetMouseMotions()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } - if (input_subsystem->GetMouseTouch()->IsPolling()) { - params = input_subsystem->GetMouseTouch()->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } - } for (auto& poller : device_pollers) { params = poller->GetNextInput(); if (params.Has("engine") && IsInputAcceptable(params)) { @@ -1353,25 +1301,6 @@ void ConfigureInputPlayer::HandleClick( QWidget::grabMouse(); QWidget::grabKeyboard(); - if (type == InputCommon::Polling::DeviceType::Button) { - input_subsystem->GetGCButtons()->BeginConfiguration(); - } else { - input_subsystem->GetGCAnalogs()->BeginConfiguration(); - } - - if (type == InputCommon::Polling::DeviceType::Motion) { - input_subsystem->GetUDPMotions()->BeginConfiguration(); - } - - if (type == InputCommon::Polling::DeviceType::Button) { - input_subsystem->GetMouseButtons()->BeginConfiguration(); - } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { - input_subsystem->GetMouseAnalogs()->BeginConfiguration(); - } else if (type == InputCommon::Polling::DeviceType::Motion) { - input_subsystem->GetMouseMotions()->BeginConfiguration(); - } else { - input_subsystem->GetMouseTouch()->BeginConfiguration(); - } if (type == InputCommon::Polling::DeviceType::Button) { ui->controllerFrame->BeginMappingButton(button_id); @@ -1393,15 +1322,6 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, QWidget::releaseMouse(); QWidget::releaseKeyboard(); - input_subsystem->GetGCButtons()->EndConfiguration(); - input_subsystem->GetGCAnalogs()->EndConfiguration(); - - input_subsystem->GetUDPMotions()->EndConfiguration(); - - input_subsystem->GetMouseButtons()->EndConfiguration(); - input_subsystem->GetMouseAnalogs()->EndConfiguration(); - input_subsystem->GetMouseMotions()->EndConfiguration(); - input_subsystem->GetMouseTouch()->EndConfiguration(); if (!abort) { (*input_setter)(params); @@ -1435,8 +1355,7 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { return; } - const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(0, 0, button); + //const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 5a844409b..0e190a3d5 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -7,7 +7,6 @@ #include #include "common/settings.h" #include "input_common/main.h" -#include "input_common/tas/tas_input.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" @@ -81,5 +80,5 @@ void ControllerDialog::InputController(ControllerInput input) { buttons |= (btn ? 1U : 0U) << index; index++; } - input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); + //input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 88e84e8f7..663760a1e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2969,15 +2969,15 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie } QString GMainWindow::GetTasStateDescription() const { - auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); - switch (tas_status) { - case TasInput::TasState::Running: - return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); - case TasInput::TasState::Recording: - return tr("TAS state: Recording %1").arg(total_tas_frames); - case TasInput::TasState::Stopped: - return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); - default: + //auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); + //switch (tas_status) { + //case TasInput::TasState::Running: + // return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); + //case TasInput::TasState::Recording: + // return tr("TAS state: Recording %1").arg(total_tas_frames); + //case TasInput::TasState::Stopped: + // return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); + //default: return tr("TAS State: Invalid"); } } From 00834b84dd954f6aea2354e07de2054a99f53fa4 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:19:55 -0500 Subject: [PATCH 055/291] input_common: Rewrite mouse --- src/input_common/CMakeLists.txt | 6 +- src/input_common/drivers/mouse.cpp | 138 +++++++++++ src/input_common/drivers/mouse.h | 77 ++++++ src/input_common/mouse/mouse_input.cpp | 223 ------------------ src/input_common/mouse/mouse_input.h | 116 --------- src/input_common/mouse/mouse_poller.cpp | 299 ------------------------ src/input_common/mouse/mouse_poller.h | 109 --------- 7 files changed, 217 insertions(+), 751 deletions(-) create mode 100644 src/input_common/drivers/mouse.cpp create mode 100644 src/input_common/drivers/mouse.h delete mode 100644 src/input_common/mouse/mouse_input.cpp delete mode 100644 src/input_common/mouse/mouse_input.h delete mode 100644 src/input_common/mouse/mouse_poller.cpp delete mode 100644 src/input_common/mouse/mouse_poller.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 0fcf7a9d7..34b41ce01 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(input_common STATIC drivers/keyboard.cpp drivers/keyboard.h + drivers/mouse.cpp + drivers/mouse.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp @@ -23,10 +25,6 @@ add_library(input_common STATIC gcadapter/gc_adapter.h gcadapter/gc_poller.cpp gcadapter/gc_poller.h - mouse/mouse_input.cpp - mouse/mouse_input.h - mouse/mouse_poller.cpp - mouse/mouse_poller.h sdl/sdl.cpp sdl/sdl.h tas/tas_input.cpp diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp new file mode 100644 index 000000000..2c2432fb7 --- /dev/null +++ b/src/input_common/drivers/mouse.cpp @@ -0,0 +1,138 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include +#include +#include + +#include "common/param_package.h" +#include "common/settings.h" +#include "common/thread.h" +#include "input_common/drivers/mouse.h" + +namespace InputCommon { +constexpr int touch_axis_x = 10; +constexpr int touch_axis_y = 11; + +Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); + update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); +} + +void Mouse::UpdateThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("yuzu:input:Mouse"); + constexpr int update_time = 10; + while (!stop_token.stop_requested()) { + if (Settings::values.mouse_panning) { + // Slow movement by 4% + last_mouse_change *= 0.96f; + const float sensitivity = + Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; + SetAxis(identifier, 0, last_mouse_change.x * sensitivity); + SetAxis(identifier, 1, -last_mouse_change.y * sensitivity); + } + + if (mouse_panning_timout++ > 20) { + StopPanning(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); + } +} + +void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) { + SetAxis(identifier, touch_axis_x, touch_x); + SetAxis(identifier, touch_axis_y, touch_y); + + if (Settings::values.mouse_panning) { + auto mouse_change = + (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); + mouse_panning_timout = 0; + + const auto move_distance = mouse_change.Length(); + if (move_distance == 0) { + return; + } + + // Make slow movements at least 3 units on lenght + if (move_distance < 3.0f) { + // Normalize value + mouse_change /= move_distance; + mouse_change *= 3.0f; + } + + // Average mouse movements + last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); + + const auto last_move_distance = last_mouse_change.Length(); + + // Make fast movements clamp to 8 units on lenght + if (last_move_distance > 8.0f) { + // Normalize value + last_mouse_change /= last_move_distance; + last_mouse_change *= 8.0f; + } + + // Ignore average if it's less than 1 unit and use current movement value + if (last_move_distance < 1.0f) { + last_mouse_change = mouse_change / mouse_change.Length(); + } + + return; + } + + if (button_pressed) { + const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; + const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; + SetAxis(identifier, 0, static_cast(mouse_move.x) * sensitivity); + SetAxis(identifier, 1, static_cast(-mouse_move.y) * sensitivity); + } +} + +void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button) { + SetAxis(identifier, touch_axis_x, touch_x); + SetAxis(identifier, touch_axis_y, touch_y); + SetButton(identifier, static_cast(button), true); + // Set initial analog parameters + mouse_origin = {x, y}; + last_mouse_position = {x, y}; + button_pressed = true; +} + +void Mouse::ReleaseButton(MouseButton button) { + SetButton(identifier, static_cast(button), false); + + if (!Settings::values.mouse_panning) { + SetAxis(identifier, 0, 0); + SetAxis(identifier, 1, 0); + } + button_pressed = false; +} + +void Mouse::ReleaseAllButtons() { + ResetButtonState(); + button_pressed = false; +} + +void Mouse::StopPanning() { + last_mouse_change = {}; +} + +std::vector Mouse::GetInputDevices() const { + std::vector devices; + devices.emplace_back(Common::ParamPackage{ + {"engine", "keyboard"}, + {"display", "Keyboard/Mouse"}, + }); + return devices; +} + +std::string Mouse::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return fmt::format("Mouse {}", params.Get("button", 0)); + } + + return "Bad Mouse"; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h new file mode 100644 index 000000000..e8355751a --- /dev/null +++ b/src/input_common/drivers/mouse.h @@ -0,0 +1,77 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include +#include + +#include "common/vector_math.h" +#include "input_common/input_engine.h" + +namespace InputCommon { + +enum class MouseButton { + Left, + Right, + Wheel, + Backward, + Forward, + Task, + Extra, + Undefined, +}; + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class Mouse final : public InputCommon::InputEngine { +public: + explicit Mouse(const std::string input_engine_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + * @param center_x the x-coordinate of the middle of the screen + * @param center_y the y-coordinate of the middle of the screen + */ + void MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param key_code the code of the key to press + */ + void PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button); + + /** + * Sets the status of all buttons bound with the key to released + * @param key_code the code of the key to release + */ + void ReleaseButton(MouseButton button); + + void ReleaseAllButtons(); + + std::vector GetInputDevices() const override; + std::string GetUIName(const Common::ParamPackage& params) const override; + +private: + void UpdateThread(std::stop_token stop_token); + void StopPanning(); + + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; + Common::Vec2 mouse_origin; + Common::Vec2 last_mouse_position; + Common::Vec2 last_mouse_change; + bool button_pressed; + int mouse_panning_timout{}; + std::jthread update_thread; +}; + +} // namespace InputCommon diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp deleted file mode 100644 index 3b052ffb2..000000000 --- a/src/input_common/mouse/mouse_input.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include - -#include "common/settings.h" -#include "input_common/mouse/mouse_input.h" - -namespace MouseInput { - -Mouse::Mouse() { - update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); -} - -Mouse::~Mouse() = default; - -void Mouse::UpdateThread(std::stop_token stop_token) { - constexpr int update_time = 10; - while (!stop_token.stop_requested()) { - for (MouseInfo& info : mouse_info) { - const Common::Vec3f angular_direction{ - -info.tilt_direction.y, - 0.0f, - -info.tilt_direction.x, - }; - - info.motion.SetGyroscope(angular_direction * info.tilt_speed); - info.motion.UpdateRotation(update_time * 1000); - info.motion.UpdateOrientation(update_time * 1000); - info.tilt_speed = 0; - info.data.motion = info.motion.GetMotion(); - if (Settings::values.mouse_panning) { - info.last_mouse_change *= 0.96f; - info.data.axis = {static_cast(16 * info.last_mouse_change.x), - static_cast(16 * -info.last_mouse_change.y)}; - } - } - if (configuring) { - UpdateYuzuSettings(); - } - if (mouse_panning_timout++ > 20) { - StopPanning(); - } - std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); - } -} - -void Mouse::UpdateYuzuSettings() { - if (buttons == 0) { - return; - } - - mouse_queue.Push(MouseStatus{ - .button = last_button, - }); -} - -void Mouse::PressButton(int x, int y, MouseButton button_) { - const auto button_index = static_cast(button_); - if (button_index >= mouse_info.size()) { - return; - } - - const auto button = 1U << button_index; - buttons |= static_cast(button); - last_button = button_; - - mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); - mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); - mouse_info[button_index].data.pressed = true; -} - -void Mouse::StopPanning() { - for (MouseInfo& info : mouse_info) { - if (Settings::values.mouse_panning) { - info.data.axis = {}; - info.tilt_speed = 0; - info.last_mouse_change = {}; - } - } -} - -void Mouse::MouseMove(int x, int y, int center_x, int center_y) { - for (MouseInfo& info : mouse_info) { - if (Settings::values.mouse_panning) { - auto mouse_change = - (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); - mouse_panning_timout = 0; - - if (mouse_change.y == 0 && mouse_change.x == 0) { - continue; - } - const auto mouse_change_length = mouse_change.Length(); - if (mouse_change_length < 3.0f) { - mouse_change /= mouse_change_length / 3.0f; - } - - info.last_mouse_change = (info.last_mouse_change * 0.91f) + (mouse_change * 0.09f); - - const auto last_mouse_change_length = info.last_mouse_change.Length(); - if (last_mouse_change_length > 8.0f) { - info.last_mouse_change /= last_mouse_change_length / 8.0f; - } else if (last_mouse_change_length < 1.0f) { - info.last_mouse_change = mouse_change / mouse_change.Length(); - } - - info.tilt_direction = info.last_mouse_change; - info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; - continue; - } - - if (info.data.pressed) { - const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; - const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; - info.last_mouse_position = Common::MakeVec(x, y); - info.data.axis = {mouse_move.x, -mouse_move.y}; - - if (mouse_change.x == 0 && mouse_change.y == 0) { - info.tilt_speed = 0; - } else { - info.tilt_direction = mouse_change.Cast(); - info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; - } - } - } -} - -void Mouse::ReleaseButton(MouseButton button_) { - const auto button_index = static_cast(button_); - if (button_index >= mouse_info.size()) { - return; - } - - const auto button = 1U << button_index; - buttons &= static_cast(0xFF - button); - - mouse_info[button_index].tilt_speed = 0; - mouse_info[button_index].data.pressed = false; - mouse_info[button_index].data.axis = {0, 0}; -} - -void Mouse::ReleaseAllButtons() { - buttons = 0; - for (auto& info : mouse_info) { - info.tilt_speed = 0; - info.data.pressed = false; - info.data.axis = {0, 0}; - } -} - -void Mouse::BeginConfiguration() { - buttons = 0; - last_button = MouseButton::Undefined; - mouse_queue.Clear(); - configuring = true; -} - -void Mouse::EndConfiguration() { - buttons = 0; - for (MouseInfo& info : mouse_info) { - info.tilt_speed = 0; - info.data.pressed = false; - info.data.axis = {0, 0}; - } - last_button = MouseButton::Undefined; - mouse_queue.Clear(); - configuring = false; -} - -bool Mouse::ToggleButton(std::size_t button_) { - if (button_ >= mouse_info.size()) { - return false; - } - const auto button = 1U << button_; - const bool button_state = (toggle_buttons & button) != 0; - const bool button_lock = (lock_buttons & button) != 0; - - if (button_lock) { - return button_state; - } - - lock_buttons |= static_cast(button); - - if (button_state) { - toggle_buttons &= static_cast(0xFF - button); - } else { - toggle_buttons |= static_cast(button); - } - - return !button_state; -} - -bool Mouse::UnlockButton(std::size_t button_) { - if (button_ >= mouse_info.size()) { - return false; - } - - const auto button = 1U << button_; - const bool button_state = (toggle_buttons & button) != 0; - - lock_buttons &= static_cast(0xFF - button); - - return button_state; -} - -Common::SPSCQueue& Mouse::GetMouseQueue() { - return mouse_queue; -} - -const Common::SPSCQueue& Mouse::GetMouseQueue() const { - return mouse_queue; -} - -MouseData& Mouse::GetMouseState(std::size_t button) { - return mouse_info[button].data; -} - -const MouseData& Mouse::GetMouseState(std::size_t button) const { - return mouse_info[button].data; -} -} // namespace MouseInput diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h deleted file mode 100644 index c8bae99c1..000000000 --- a/src/input_common/mouse/mouse_input.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -#include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "common/vector_math.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" - -namespace MouseInput { - -enum class MouseButton { - Left, - Right, - Wheel, - Backward, - Forward, - Task, - Extra, - Undefined, -}; - -struct MouseStatus { - MouseButton button{MouseButton::Undefined}; -}; - -struct MouseData { - bool pressed{}; - std::array axis{}; - Input::MotionStatus motion{}; - Input::TouchStatus touch{}; -}; - -class Mouse { -public: - Mouse(); - ~Mouse(); - - /// Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - /** - * Signals that a button is pressed. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - * @param button_ the button pressed - */ - void PressButton(int x, int y, MouseButton button_); - - /** - * Signals that mouse has moved. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - * @param center_x the x-coordinate of the middle of the screen - * @param center_y the y-coordinate of the middle of the screen - */ - void MouseMove(int x, int y, int center_x, int center_y); - - /** - * Signals that a button is released. - * @param button_ the button pressed - */ - void ReleaseButton(MouseButton button_); - - /** - * Signals that all buttons are released - */ - void ReleaseAllButtons(); - - [[nodiscard]] bool ToggleButton(std::size_t button_); - [[nodiscard]] bool UnlockButton(std::size_t button_); - - [[nodiscard]] Common::SPSCQueue& GetMouseQueue(); - [[nodiscard]] const Common::SPSCQueue& GetMouseQueue() const; - - [[nodiscard]] MouseData& GetMouseState(std::size_t button); - [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; - -private: - void UpdateThread(std::stop_token stop_token); - void UpdateYuzuSettings(); - void StopPanning(); - - struct MouseInfo { - InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; - Common::Vec2 mouse_origin; - Common::Vec2 last_mouse_position; - Common::Vec2 last_mouse_change; - bool is_tilting = false; - float sensitivity{0.120f}; - - float tilt_speed = 0; - Common::Vec2 tilt_direction; - MouseData data; - }; - - u16 buttons{}; - u16 toggle_buttons{}; - u16 lock_buttons{}; - std::jthread update_thread; - MouseButton last_button{MouseButton::Undefined}; - std::array mouse_info; - Common::SPSCQueue mouse_queue; - bool configuring{false}; - int mouse_panning_timout{}; -}; -} // namespace MouseInput diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp deleted file mode 100644 index 090b26972..000000000 --- a/src/input_common/mouse/mouse_poller.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include - -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "input_common/mouse/mouse_input.h" -#include "input_common/mouse/mouse_poller.h" - -namespace InputCommon { - -class MouseButton final : public Input::ButtonDevice { -public: - explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_) - : button(button_), toggle(toggle_), mouse_input(mouse_input_) {} - - bool GetStatus() const override { - const bool button_state = mouse_input->GetMouseState(button).pressed; - if (!toggle) { - return button_state; - } - - if (button_state) { - return mouse_input->ToggleButton(button); - } - return mouse_input->UnlockButton(button); - } - -private: - const u32 button; - const bool toggle; - MouseInput::Mouse* mouse_input; -}; - -MouseButtonFactory::MouseButtonFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseButtonFactory::Create( - const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - const auto toggle = params.Get("toggle", false); - - return std::make_unique(button_id, toggle, mouse_input.get()); -} - -Common::ParamPackage MouseButtonFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - params.Set("toggle", false); - return params; - } - } - return params; -} - -void MouseButtonFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseButtonFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -class MouseAnalog final : public Input::AnalogDevice { -public: - explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, - float deadzone_, float range_, const MouseInput::Mouse* mouse_input_) - : button(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), - deadzone(deadzone_), range(range_), mouse_input(mouse_input_) {} - - float GetAxis(u32 axis) const { - std::lock_guard lock{mutex}; - const auto axis_value = - static_cast(mouse_input->GetMouseState(button).axis.at(axis)); - const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.10f; - return axis_value * sensitivity / (100.0f * range); - } - - std::pair GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { - float x = GetAxis(analog_axis_x); - float y = GetAxis(analog_axis_y); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return {x, y}; - } - - std::tuple GetStatus() const override { - const auto [x, y] = GetAnalog(axis_x, axis_y); - const float r = std::sqrt((x * x) + (y * y)); - if (r > deadzone) { - return {x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)}; - } - return {0.0f, 0.0f}; - } - - std::tuple GetRawStatus() const override { - const float x = GetAxis(axis_x); - const float y = GetAxis(axis_y); - return {x, y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - -private: - const u32 button; - const u32 axis_x; - const u32 axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const MouseInput::Mouse* mouse_input; - mutable std::mutex mutex; -}; - -/// An analog device factory that creates analog devices from GC Adapter -MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -/** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ -std::unique_ptr MouseAnalogFactory::Create( - const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - const auto axis_x = static_cast(params.Get("axis_x", 0)); - const auto axis_y = static_cast(params.Get("axis_y", 1)); - const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - - return std::make_unique(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, - mouse_input.get()); -} - -void MouseAnalogFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseAnalogFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -Common::ParamPackage MouseAnalogFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("port", static_cast(pad.button)); - params.Set("axis_x", 0); - params.Set("axis_y", 1); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - return params; - } - } - return params; -} - -class MouseMotion final : public Input::MotionDevice { -public: - explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_) - : button(button_), mouse_input(mouse_input_) {} - - Input::MotionStatus GetStatus() const override { - return mouse_input->GetMouseState(button).motion; - } - -private: - const u32 button; - const MouseInput::Mouse* mouse_input; -}; - -MouseMotionFactory::MouseMotionFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseMotionFactory::Create( - const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - - return std::make_unique(button_id, mouse_input.get()); -} - -Common::ParamPackage MouseMotionFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - return params; - } - } - return params; -} - -void MouseMotionFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseMotionFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -class MouseTouch final : public Input::TouchDevice { -public: - explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_) - : button(button_), mouse_input(mouse_input_) {} - - Input::TouchStatus GetStatus() const override { - return mouse_input->GetMouseState(button).touch; - } - -private: - const u32 button; - const MouseInput::Mouse* mouse_input; -}; - -MouseTouchFactory::MouseTouchFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseTouchFactory::Create(const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - - return std::make_unique(button_id, mouse_input.get()); -} - -Common::ParamPackage MouseTouchFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - return params; - } - } - return params; -} - -void MouseTouchFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseTouchFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -} // namespace InputCommon diff --git a/src/input_common/mouse/mouse_poller.h b/src/input_common/mouse/mouse_poller.h deleted file mode 100644 index cf331293b..000000000 --- a/src/input_common/mouse/mouse_poller.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/mouse/mouse_input.h" - -namespace InputCommon { - -/** - * A button device factory representing a mouse. It receives mouse events and forward them - * to all button devices it created. - */ -class MouseButtonFactory final : public Input::Factory { -public: - explicit MouseButtonFactory(std::shared_ptr mouse_input_); - - /** - * Creates a button device from a button press - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// An analog device factory that creates analog devices from mouse -class MouseAnalogFactory final : public Input::Factory { -public: - explicit MouseAnalogFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// A motion device factory that creates motion devices from mouse -class MouseMotionFactory final : public Input::Factory { -public: - explicit MouseMotionFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// An touch device factory that creates touch devices from mouse -class MouseTouchFactory final : public Input::Factory { -public: - explicit MouseTouchFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -} // namespace InputCommon From fa8e23b84281022bf6b4e8916231a17e9997e5aa Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:20:56 -0500 Subject: [PATCH 056/291] input_common: Rewrite touch --- src/input_common/CMakeLists.txt | 2 + src/input_common/drivers/touch_screen.cpp | 47 +++++++++++++++++++++ src/input_common/drivers/touch_screen.h | 50 +++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/input_common/drivers/touch_screen.cpp create mode 100644 src/input_common/drivers/touch_screen.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 34b41ce01..71091767d 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -3,6 +3,8 @@ add_library(input_common STATIC drivers/keyboard.h drivers/mouse.cpp drivers/mouse.h + drivers/touch_screen.cpp + drivers/touch_screen.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp new file mode 100644 index 000000000..e13835e9f --- /dev/null +++ b/src/input_common/drivers/touch_screen.cpp @@ -0,0 +1,47 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/param_package.h" +#include "input_common/drivers/touch_screen.h" + +namespace InputCommon { + +TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); +} + +void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { + if (finger >= 16) { + return; + } + TouchPressed(x, y, finger); +} + +void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { + if (finger >= 16) { + return; + } + SetButton(identifier, static_cast(finger), true); + SetAxis(identifier, static_cast(finger * 2), x); + SetAxis(identifier, static_cast(finger * 2 + 1), y); +} + +void TouchScreen::TouchReleased(std::size_t finger) { + if (finger >= 16) { + return; + } + SetButton(identifier, static_cast(finger), false); + SetAxis(identifier, static_cast(finger * 2), 0.0f); + SetAxis(identifier, static_cast(finger * 2 + 1), 0.0f); +} + +void TouchScreen::ReleaseAllTouch() { + for (int index = 0; index < 16; ++index) { + SetButton(identifier, index, false); + SetAxis(identifier, index * 2, 0.0f); + SetAxis(identifier, index * 2 + 1, 0.0f); + } +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h new file mode 100644 index 000000000..5fbb2f47f --- /dev/null +++ b/src/input_common/drivers/touch_screen.h @@ -0,0 +1,50 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class TouchScreen final : public InputCommon::InputEngine { +public: + explicit TouchScreen(const std::string input_engine_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + * @param center_x the x-coordinate of the middle of the screen + * @param center_y the y-coordinate of the middle of the screen + */ + void TouchMoved(float x, float y, std::size_t finger); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param key_code the code of the key to press + */ + void TouchPressed(float x, float y, std::size_t finger); + + /** + * Sets the status of all buttons bound with the key to released + * @param key_code the code of the key to release + */ + void TouchReleased(std::size_t finger); + + void ReleaseAllTouch(); + +private: + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; +}; + +} // namespace InputCommon From 395e9a449d338e56ade9ea88ffeed297a7d86b10 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:22:07 -0500 Subject: [PATCH 057/291] input_common: Rewrite gc_adapter --- src/input_common/CMakeLists.txt | 6 +- .../{gcadapter => drivers}/gc_adapter.cpp | 427 +++++++++--------- src/input_common/drivers/gc_adapter.h | 128 ++++++ src/input_common/drivers/tas_input.cpp | 320 +++++++++++++ src/input_common/drivers/tas_input.h | 200 ++++++++ src/input_common/gcadapter/gc_adapter.h | 168 ------- src/input_common/gcadapter/gc_poller.cpp | 356 --------------- src/input_common/gcadapter/gc_poller.h | 78 ---- 8 files changed, 852 insertions(+), 831 deletions(-) rename src/input_common/{gcadapter => drivers}/gc_adapter.cpp (61%) create mode 100644 src/input_common/drivers/gc_adapter.h create mode 100644 src/input_common/drivers/tas_input.cpp create mode 100644 src/input_common/drivers/tas_input.h delete mode 100644 src/input_common/gcadapter/gc_adapter.h delete mode 100644 src/input_common/gcadapter/gc_poller.cpp delete mode 100644 src/input_common/gcadapter/gc_poller.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 71091767d..c8871513c 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,4 +1,6 @@ add_library(input_common STATIC + drivers/gc_adapter.cpp + drivers/gc_adapter.h drivers/keyboard.cpp drivers/keyboard.h drivers/mouse.cpp @@ -23,10 +25,6 @@ add_library(input_common STATIC motion_from_button.h motion_input.cpp motion_input.h - gcadapter/gc_adapter.cpp - gcadapter/gc_adapter.h - gcadapter/gc_poller.cpp - gcadapter/gc_poller.h sdl/sdl.cpp sdl/sdl.h tas/tas_input.cpp diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp similarity index 61% rename from src/input_common/gcadapter/gc_adapter.cpp rename to src/input_common/drivers/gc_adapter.cpp index a2f1bb67c..6721ba4f7 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -2,47 +2,103 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include -#include - +#include #include #include "common/logging/log.h" #include "common/param_package.h" #include "common/settings_input.h" -#include "input_common/gcadapter/gc_adapter.h" +#include "common/thread.h" +#include "input_common/drivers/gc_adapter.h" -namespace GCAdapter { +namespace InputCommon { -Adapter::Adapter() { - if (usb_adapter_handle != nullptr) { +class LibUSBContext { +public: + explicit LibUSBContext() { + init_result = libusb_init(&ctx); + } + + ~LibUSBContext() { + libusb_exit(ctx); + } + + LibUSBContext& operator=(const LibUSBContext&) = delete; + LibUSBContext(const LibUSBContext&) = delete; + + LibUSBContext& operator=(LibUSBContext&&) noexcept = delete; + LibUSBContext(LibUSBContext&&) noexcept = delete; + + [[nodiscard]] int InitResult() const noexcept { + return init_result; + } + + [[nodiscard]] libusb_context* get() noexcept { + return ctx; + } + +private: + libusb_context* ctx; + int init_result{}; +}; + +class LibUSBDeviceHandle { +public: + explicit LibUSBDeviceHandle(libusb_context* ctx, uint16_t vid, uint16_t pid) noexcept { + handle = libusb_open_device_with_vid_pid(ctx, vid, pid); + } + + ~LibUSBDeviceHandle() noexcept { + if (handle) { + libusb_release_interface(handle, 1); + libusb_close(handle); + } + } + + LibUSBDeviceHandle& operator=(const LibUSBDeviceHandle&) = delete; + LibUSBDeviceHandle(const LibUSBDeviceHandle&) = delete; + + LibUSBDeviceHandle& operator=(LibUSBDeviceHandle&&) noexcept = delete; + LibUSBDeviceHandle(LibUSBDeviceHandle&&) noexcept = delete; + + [[nodiscard]] libusb_device_handle* get() noexcept { + return handle; + } + +private: + libusb_device_handle* handle{}; +}; + +GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine_) { + if (usb_adapter_handle) { return; } LOG_INFO(Input, "GC Adapter Initialization started"); - const int init_res = libusb_init(&libusb_ctx); + libusb_ctx = std::make_unique(); + const int init_res = libusb_ctx->InitResult(); if (init_res == LIBUSB_SUCCESS) { - adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); + adapter_scan_thread = + std::jthread([this](std::stop_token stop_token) { AdapterScanThread(stop_token); }); } else { LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); } } -Adapter::~Adapter() { +GCAdapter::~GCAdapter() { Reset(); } -void Adapter::AdapterInputThread() { +void GCAdapter::AdapterInputThread(std::stop_token stop_token) { LOG_DEBUG(Input, "GC Adapter input thread started"); + Common::SetCurrentThreadName("yuzu:input:GCAdapter"); s32 payload_size{}; AdapterPayload adapter_payload{}; - if (adapter_scan_thread.joinable()) { - adapter_scan_thread.join(); - } + adapter_scan_thread = {}; - while (adapter_input_thread_running) { - libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), + while (!stop_token.stop_requested()) { + libusb_interrupt_transfer(usb_adapter_handle->get(), input_endpoint, adapter_payload.data(), static_cast(adapter_payload.size()), &payload_size, 16); if (IsPayloadCorrect(adapter_payload, payload_size)) { UpdateControllers(adapter_payload); @@ -52,19 +108,20 @@ void Adapter::AdapterInputThread() { } if (restart_scan_thread) { - adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); + adapter_scan_thread = + std::jthread([this](std::stop_token token) { AdapterScanThread(token); }); restart_scan_thread = false; } } -bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) { +bool GCAdapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) { if (payload_size != static_cast(adapter_payload.size()) || adapter_payload[0] != LIBUSB_DT_HID) { LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size, adapter_payload[0]); if (input_error_counter++ > 20) { LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); - adapter_input_thread_running = false; + adapter_input_thread.request_stop(); restart_scan_thread = true; } return false; @@ -74,7 +131,7 @@ bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payloa return true; } -void Adapter::UpdateControllers(const AdapterPayload& adapter_payload) { +void GCAdapter::UpdateControllers(const AdapterPayload& adapter_payload) { for (std::size_t port = 0; port < pads.size(); ++port) { const std::size_t offset = 1 + (9 * port); const auto type = static_cast(adapter_payload[offset] >> 4); @@ -84,23 +141,21 @@ void Adapter::UpdateControllers(const AdapterPayload& adapter_payload) { const u8 b2 = adapter_payload[offset + 2]; UpdateStateButtons(port, b1, b2); UpdateStateAxes(port, adapter_payload); - if (configuring) { - UpdateYuzuSettings(port); - } } } } -void Adapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { +void GCAdapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { if (pads[port].type == pad_type) { return; } // Device changed reset device and set new type - ResetDevice(port); + pads[port] = {}; pads[port].type = pad_type; } -void Adapter::UpdateStateButtons(std::size_t port, u8 b1, u8 b2) { +void GCAdapter::UpdateStateButtons(std::size_t port, [[maybe_unused]] u8 b1, + [[maybe_unused]] u8 b2) { if (port >= pads.size()) { return; } @@ -116,25 +171,21 @@ void Adapter::UpdateStateButtons(std::size_t port, u8 b1, u8 b2) { PadButton::TriggerR, PadButton::TriggerL, }; - pads[port].buttons = 0; + for (std::size_t i = 0; i < b1_buttons.size(); ++i) { - if ((b1 & (1U << i)) != 0) { - pads[port].buttons = - static_cast(pads[port].buttons | static_cast(b1_buttons[i])); - pads[port].last_button = b1_buttons[i]; - } + const bool button_status = (b1 & (1U << i)) != 0; + const int button = static_cast(b1_buttons[i]); + SetButton(pads[port].identifier, button, button_status); } for (std::size_t j = 0; j < b2_buttons.size(); ++j) { - if ((b2 & (1U << j)) != 0) { - pads[port].buttons = - static_cast(pads[port].buttons | static_cast(b2_buttons[j])); - pads[port].last_button = b2_buttons[j]; - } + const bool button_status = (b2 & (1U << j)) != 0; + const int button = static_cast(b2_buttons[j]); + SetButton(pads[port].identifier, button, button_status); } } -void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) { +void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) { if (port >= pads.size()) { return; } @@ -155,134 +206,70 @@ void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_pa pads[port].axis_origin[index] = axis_value; pads[port].reset_origin_counter++; } - pads[port].axis_values[index] = - static_cast(axis_value - pads[port].axis_origin[index]); + const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 110.0f; + SetAxis(pads[port].identifier, static_cast(index), axis_status); } } -void Adapter::UpdateYuzuSettings(std::size_t port) { - if (port >= pads.size()) { - return; - } - - constexpr u8 axis_threshold = 50; - GCPadStatus pad_status = {.port = port}; - - if (pads[port].buttons != 0) { - pad_status.button = pads[port].last_button; - pad_queue.Push(pad_status); - } - - // Accounting for a threshold here to ensure an intentional press - for (std::size_t i = 0; i < pads[port].axis_values.size(); ++i) { - const s16 value = pads[port].axis_values[i]; - - if (value > axis_threshold || value < -axis_threshold) { - pad_status.axis = static_cast(i); - pad_status.axis_value = value; - pad_status.axis_threshold = axis_threshold; - pad_queue.Push(pad_status); - } +void GCAdapter::AdapterScanThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("yuzu:input:ScanGCAdapter"); + usb_adapter_handle = nullptr; + pads = {}; + while (!stop_token.stop_requested() && !Setup()) { + std::this_thread::sleep_for(std::chrono::seconds(2)); } } -void Adapter::UpdateVibrations() { - // Use 8 states to keep the switching between on/off fast enough for - // a human to not notice the difference between switching from on/off - // More states = more rumble strengths = slower update time - constexpr u8 vibration_states = 8; - - vibration_counter = (vibration_counter + 1) % vibration_states; - - for (GCController& pad : pads) { - const bool vibrate = pad.rumble_amplitude > vibration_counter; - vibration_changed |= vibrate != pad.enable_vibration; - pad.enable_vibration = vibrate; - } - SendVibrations(); -} - -void Adapter::SendVibrations() { - if (!rumble_enabled || !vibration_changed) { - return; - } - s32 size{}; - constexpr u8 rumble_command = 0x11; - const u8 p1 = pads[0].enable_vibration; - const u8 p2 = pads[1].enable_vibration; - const u8 p3 = pads[2].enable_vibration; - const u8 p4 = pads[3].enable_vibration; - std::array payload = {rumble_command, p1, p2, p3, p4}; - const int err = libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, payload.data(), - static_cast(payload.size()), &size, 16); - if (err) { - LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); - if (output_error_counter++ > 5) { - LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); - rumble_enabled = false; - } - return; - } - output_error_counter = 0; - vibration_changed = false; -} - -bool Adapter::RumblePlay(std::size_t port, u8 amplitude) { - pads[port].rumble_amplitude = amplitude; - - return rumble_enabled; -} - -void Adapter::AdapterScanThread() { - adapter_scan_thread_running = true; - adapter_input_thread_running = false; - if (adapter_input_thread.joinable()) { - adapter_input_thread.join(); - } - ClearLibusbHandle(); - ResetDevices(); - while (adapter_scan_thread_running && !adapter_input_thread_running) { - Setup(); - std::this_thread::sleep_for(std::chrono::seconds(1)); - } -} - -void Adapter::Setup() { - usb_adapter_handle = libusb_open_device_with_vid_pid(libusb_ctx, 0x057e, 0x0337); - - if (usb_adapter_handle == NULL) { - return; +bool GCAdapter::Setup() { + constexpr u16 nintendo_vid = 0x057e; + constexpr u16 gc_adapter_pid = 0x0337; + usb_adapter_handle = + std::make_unique(libusb_ctx->get(), nintendo_vid, gc_adapter_pid); + if (!usb_adapter_handle->get()) { + return false; } if (!CheckDeviceAccess()) { - ClearLibusbHandle(); - return; + usb_adapter_handle = nullptr; + return false; } - libusb_device* device = libusb_get_device(usb_adapter_handle); + libusb_device* const device = libusb_get_device(usb_adapter_handle->get()); LOG_INFO(Input, "GC adapter is now connected"); // GC Adapter found and accessible, registering it if (GetGCEndpoint(device)) { - adapter_scan_thread_running = false; - adapter_input_thread_running = true; rumble_enabled = true; input_error_counter = 0; output_error_counter = 0; - adapter_input_thread = std::thread(&Adapter::AdapterInputThread, this); + + std::size_t port = 0; + for (GCController& pad : pads) { + pad.identifier = { + .guid = Common::UUID{""}, + .port = port++, + .pad = 0, + }; + PreSetController(pad.identifier); + } + + adapter_input_thread = + std::jthread([this](std::stop_token stop_token) { AdapterInputThread(stop_token); }); + return true; } + return false; } -bool Adapter::CheckDeviceAccess() { +bool GCAdapter::CheckDeviceAccess() { // This fixes payload problems from offbrand GCAdapters const s32 control_transfer_error = - libusb_control_transfer(usb_adapter_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000); + libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); if (control_transfer_error < 0) { LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); } - s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0); + s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle->get(), 0); if (kernel_driver_error == 1) { - kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0); + kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle->get(), 0); if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", kernel_driver_error); @@ -290,15 +277,13 @@ bool Adapter::CheckDeviceAccess() { } if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { - libusb_close(usb_adapter_handle); usb_adapter_handle = nullptr; return false; } - const int interface_claim_error = libusb_claim_interface(usb_adapter_handle, 0); + const int interface_claim_error = libusb_claim_interface(usb_adapter_handle->get(), 0); if (interface_claim_error) { LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); - libusb_close(usb_adapter_handle); usb_adapter_handle = nullptr; return false; } @@ -306,7 +291,7 @@ bool Adapter::CheckDeviceAccess() { return true; } -bool Adapter::GetGCEndpoint(libusb_device* device) { +bool GCAdapter::GetGCEndpoint(libusb_device* device) { libusb_config_descriptor* config = nullptr; const int config_descriptor_return = libusb_get_config_descriptor(device, 0, &config); if (config_descriptor_return != LIBUSB_SUCCESS) { @@ -332,68 +317,83 @@ bool Adapter::GetGCEndpoint(libusb_device* device) { // This transfer seems to be responsible for clearing the state of the adapter // Used to clear the "busy" state of when the device is unexpectedly unplugged unsigned char clear_payload = 0x13; - libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload, + libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, &clear_payload, sizeof(clear_payload), nullptr, 16); return true; } -void Adapter::JoinThreads() { - restart_scan_thread = false; - adapter_input_thread_running = false; - adapter_scan_thread_running = false; +bool GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { + const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; + const auto processed_amplitude = + static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); - if (adapter_scan_thread.joinable()) { - adapter_scan_thread.join(); - } - - if (adapter_input_thread.joinable()) { - adapter_input_thread.join(); - } + pads[identifier.port].rumble_amplitude = processed_amplitude; + return rumble_enabled; } -void Adapter::ClearLibusbHandle() { - if (usb_adapter_handle) { - libusb_release_interface(usb_adapter_handle, 1); - libusb_close(usb_adapter_handle); - usb_adapter_handle = nullptr; +void GCAdapter::UpdateVibrations() { + // Use 8 states to keep the switching between on/off fast enough for + // a human to feel different vibration strenght + // More states == more rumble strengths == slower update time + constexpr u8 vibration_states = 8; + + vibration_counter = (vibration_counter + 1) % vibration_states; + + for (GCController& pad : pads) { + const bool vibrate = pad.rumble_amplitude > vibration_counter; + vibration_changed |= vibrate != pad.enable_vibration; + pad.enable_vibration = vibrate; } + SendVibrations(); } -void Adapter::ResetDevices() { - for (std::size_t i = 0; i < pads.size(); ++i) { - ResetDevice(i); +void GCAdapter::SendVibrations() { + if (!rumble_enabled || !vibration_changed) { + return; } -} - -void Adapter::ResetDevice(std::size_t port) { - pads[port].type = ControllerTypes::None; - pads[port].enable_vibration = false; - pads[port].rumble_amplitude = 0; - pads[port].buttons = 0; - pads[port].last_button = PadButton::Undefined; - pads[port].axis_values.fill(0); - pads[port].reset_origin_counter = 0; -} - -void Adapter::Reset() { - JoinThreads(); - ClearLibusbHandle(); - ResetDevices(); - - if (libusb_ctx) { - libusb_exit(libusb_ctx); + s32 size{}; + constexpr u8 rumble_command = 0x11; + const u8 p1 = pads[0].enable_vibration; + const u8 p2 = pads[1].enable_vibration; + const u8 p3 = pads[2].enable_vibration; + const u8 p4 = pads[3].enable_vibration; + std::array payload = {rumble_command, p1, p2, p3, p4}; + const int err = + libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, payload.data(), + static_cast(payload.size()), &size, 16); + if (err) { + LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); + if (output_error_counter++ > 5) { + LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); + rumble_enabled = false; + } + return; } + output_error_counter = 0; + vibration_changed = false; } -std::vector Adapter::GetInputDevices() const { +bool GCAdapter::DeviceConnected(std::size_t port) const { + return pads[port].type != ControllerTypes::None; +} + +void GCAdapter::Reset() { + adapter_scan_thread = {}; + adapter_input_thread = {}; + usb_adapter_handle = nullptr; + pads = {}; + libusb_ctx = nullptr; +} + +std::vector GCAdapter::GetInputDevices() const { std::vector devices; for (std::size_t port = 0; port < pads.size(); ++port) { if (!DeviceConnected(port)) { continue; } - std::string name = fmt::format("Gamecube Controller {}", port + 1); + const std::string name = fmt::format("Gamecube Controller {}", port + 1); devices.emplace_back(Common::ParamPackage{ - {"class", "gcpad"}, + {"engine", "gcpad"}, {"display", std::move(name)}, {"port", std::to_string(port)}, }); @@ -401,8 +401,7 @@ std::vector Adapter::GetInputDevices() const { return devices; } -InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice( - const Common::ParamPackage& params) const { +ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& params) { // 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 @@ -425,7 +424,7 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice( return {}; } - InputCommon::ButtonMapping mapping{}; + ButtonMapping mapping{}; for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { Common::ParamPackage button_params({{"engine", "gcpad"}}); button_params.Set("port", params.Get("port", 0)); @@ -434,30 +433,30 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice( } // Add the missing bindings for ZL/ZR - static constexpr std::array, 2> + static constexpr std::array, 2> switch_to_gcadapter_axis = { - std::pair{Settings::NativeButton::ZL, PadAxes::TriggerLeft}, - {Settings::NativeButton::ZR, PadAxes::TriggerRight}, + std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft}, + {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, }; - for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) { + for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) { Common::ParamPackage button_params({{"engine", "gcpad"}}); button_params.Set("port", params.Get("port", 0)); - button_params.Set("button", static_cast(PadButton::Stick)); + button_params.Set("button", static_cast(gcadapter_buton)); button_params.Set("axis", static_cast(gcadapter_axis)); button_params.Set("threshold", 0.5f); + button_params.Set("range", 1.9f); button_params.Set("direction", "+"); mapping.insert_or_assign(switch_button, std::move(button_params)); } return mapping; } -InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice( - const Common::ParamPackage& params) const { +AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& params) { if (!params.Has("port")) { return {}; } - InputCommon::AnalogMapping mapping = {}; + AnalogMapping mapping = {}; Common::ParamPackage left_analog_params; left_analog_params.Set("engine", "gcpad"); left_analog_params.Set("port", params.Get("port", 0)); @@ -473,34 +472,12 @@ InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice( return mapping; } -bool Adapter::DeviceConnected(std::size_t port) const { - return pads[port].type != ControllerTypes::None; +std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return fmt::format("Button {}", params.Get("button", 0)); + } + + return "Bad GC Adapter"; } -void Adapter::BeginConfiguration() { - pad_queue.Clear(); - configuring = true; -} - -void Adapter::EndConfiguration() { - pad_queue.Clear(); - configuring = false; -} - -Common::SPSCQueue& Adapter::GetPadQueue() { - return pad_queue; -} - -const Common::SPSCQueue& Adapter::GetPadQueue() const { - return pad_queue; -} - -GCController& Adapter::GetPadState(std::size_t port) { - return pads.at(port); -} - -const GCController& Adapter::GetPadState(std::size_t port) const { - return pads.at(port); -} - -} // namespace GCAdapter +} // namespace InputCommon diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h new file mode 100644 index 000000000..c0bf1ed7a --- /dev/null +++ b/src/input_common/drivers/gc_adapter.h @@ -0,0 +1,128 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "input_common/input_engine.h" + +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + +namespace InputCommon { + +class LibUSBContext; +class LibUSBDeviceHandle; + +class GCAdapter : public InputCommon::InputEngine { +public: + explicit GCAdapter(const std::string input_engine_); + ~GCAdapter(); + + bool SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) override; + + /// Used for automapping features + std::vector GetInputDevices() const override; + ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + std::string GetUIName(const Common::ParamPackage& params) const override; + +private: + enum class PadButton { + Undefined = 0x0000, + ButtonLeft = 0x0001, + ButtonRight = 0x0002, + ButtonDown = 0x0004, + ButtonUp = 0x0008, + TriggerZ = 0x0010, + TriggerR = 0x0020, + TriggerL = 0x0040, + ButtonA = 0x0100, + ButtonB = 0x0200, + ButtonX = 0x0400, + ButtonY = 0x0800, + ButtonStart = 0x1000, + }; + + enum class PadAxes : u8 { + StickX, + StickY, + SubstickX, + SubstickY, + TriggerLeft, + TriggerRight, + Undefined, + }; + + enum class ControllerTypes { + None, + Wired, + Wireless, + }; + + struct GCController { + ControllerTypes type = ControllerTypes::None; + PadIdentifier identifier{}; + bool enable_vibration = false; + u8 rumble_amplitude{}; + std::array axis_origin{}; + u8 reset_origin_counter{}; + }; + + using AdapterPayload = std::array; + + void UpdatePadType(std::size_t port, ControllerTypes pad_type); + void UpdateControllers(const AdapterPayload& adapter_payload); + void UpdateStateButtons(std::size_t port, u8 b1, u8 b2); + void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); + + void AdapterInputThread(std::stop_token stop_token); + + void AdapterScanThread(std::stop_token stop_token); + + bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); + + /// For use in initialization, querying devices to find the adapter + bool Setup(); + + /// Returns true if we successfully gain access to GC Adapter + bool CheckDeviceAccess(); + + /// Captures GC Adapter endpoint address + /// Returns true if the endpoint was set correctly + bool GetGCEndpoint(libusb_device* device); + + /// Returns true if there is a device connected to port + bool DeviceConnected(std::size_t port) const; + + /// For shutting down, clear all data, join all threads, release usb + void Reset(); + + void UpdateVibrations(); + // Updates vibration state of all controllers + void SendVibrations(); + std::unique_ptr usb_adapter_handle; + std::array pads; + + std::jthread adapter_input_thread; + std::jthread adapter_scan_thread; + bool restart_scan_thread{}; + + std::unique_ptr libusb_ctx; + + u8 input_endpoint{0}; + u8 output_endpoint{0}; + u8 input_error_counter{0}; + u8 output_error_counter{0}; + int vibration_counter{0}; + + bool rumble_enabled{true}; + bool vibration_changed{true}; +}; +} // namespace InputCommon diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp new file mode 100644 index 000000000..5e2101b27 --- /dev/null +++ b/src/input_common/drivers/tas_input.cpp @@ -0,0 +1,320 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "common/fs/file.h" +#include "common/fs/fs_types.h" +#include "common/fs/path_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "input_common/drivers/tas_input.h" + +namespace InputCommon::TasInput { + +enum TasAxes : u8 { + StickX, + StickY, + SubstickX, + SubstickY, + Undefined, +}; + +// Supported keywords and buttons from a TAS file +constexpr std::array, 20> text_to_tas_button = { + std::pair{"KEY_A", TasButton::BUTTON_A}, + {"KEY_B", TasButton::BUTTON_B}, + {"KEY_X", TasButton::BUTTON_X}, + {"KEY_Y", TasButton::BUTTON_Y}, + {"KEY_LSTICK", TasButton::STICK_L}, + {"KEY_RSTICK", TasButton::STICK_R}, + {"KEY_L", TasButton::TRIGGER_L}, + {"KEY_R", TasButton::TRIGGER_R}, + {"KEY_PLUS", TasButton::BUTTON_PLUS}, + {"KEY_MINUS", TasButton::BUTTON_MINUS}, + {"KEY_DLEFT", TasButton::BUTTON_LEFT}, + {"KEY_DUP", TasButton::BUTTON_UP}, + {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, + {"KEY_DDOWN", TasButton::BUTTON_DOWN}, + {"KEY_SL", TasButton::BUTTON_SL}, + {"KEY_SR", TasButton::BUTTON_SR}, + {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, + {"KEY_HOME", TasButton::BUTTON_HOME}, + {"KEY_ZL", TasButton::TRIGGER_ZL}, + {"KEY_ZR", TasButton::TRIGGER_ZR}, +}; + +Tas::Tas(const std::string input_engine_) : InputCommon::InputEngine(input_engine_) { + for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { + PadIdentifier identifier{ + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; + PreSetController(identifier); + } + ClearInput(); + if (!Settings::values.tas_enable) { + needs_reset = true; + return; + } + LoadTasFiles(); +} + +Tas::~Tas() { + Stop(); +}; + +void Tas::LoadTasFiles() { + script_length = 0; + for (size_t i = 0; i < commands.size(); i++) { + LoadTasFile(i); + if (commands[i].size() > script_length) { + script_length = commands[i].size(); + } + } +} + +void Tas::LoadTasFile(size_t player_index) { + if (!commands[player_index].empty()) { + commands[player_index].clear(); + } + std::string file = + Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / + fmt::format("script0-{}.txt", player_index + 1), + Common::FS::FileType::BinaryFile); + std::stringstream command_line(file); + std::string line; + int frame_no = 0; + while (std::getline(command_line, line, '\n')) { + if (line.empty()) { + continue; + } + std::smatch m; + + std::stringstream linestream(line); + std::string segment; + std::vector seglist; + + while (std::getline(linestream, segment, ' ')) { + seglist.push_back(segment); + } + + if (seglist.size() < 4) { + continue; + } + + while (frame_no < std::stoi(seglist.at(0))) { + commands[player_index].push_back({}); + frame_no++; + } + + TASCommand command = { + .buttons = ReadCommandButtons(seglist.at(1)), + .l_axis = ReadCommandAxis(seglist.at(2)), + .r_axis = ReadCommandAxis(seglist.at(3)), + }; + commands[player_index].push_back(command); + frame_no++; + } + LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); +} + +void Tas::WriteTasFile(std::u8string file_name) { + std::string output_text; + for (size_t frame = 0; frame < record_commands.size(); frame++) { + const TASCommand& line = record_commands[frame]; + output_text += fmt::format("{} {} {} {} {}\n", frame, WriteCommandButtons(line.buttons), + WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); + } + const auto bytes_written = Common::FS::WriteStringToFile( + Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, + Common::FS::FileType::TextFile, output_text); + if (bytes_written == output_text.size()) { + LOG_INFO(Input, "TAS file written to file!"); + } else { + LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytes_written, + output_text.size()); + } +} + +void Tas::RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis) { + last_input = { + .buttons = buttons, + .l_axis = FlipAxisY(left_axis), + .r_axis = FlipAxisY(right_axis), + }; +} + +TasAnalog Tas::FlipAxisY(TasAnalog old) { + return { + .x = old.x, + .y = -old.y, + }; +} + +std::tuple Tas::GetStatus() const { + TasState state; + if (is_recording) { + return {TasState::Recording, 0, record_commands.size()}; + } + + if (is_running) { + state = TasState::Running; + } else { + state = TasState::Stopped; + } + + return {state, current_command, script_length}; +} + +void Tas::UpdateThread() { + if (!Settings::values.tas_enable) { + if (is_running) { + Stop(); + } + return; + } + + if (is_recording) { + record_commands.push_back(last_input); + } + if (needs_reset) { + current_command = 0; + needs_reset = false; + LoadTasFiles(); + LOG_DEBUG(Input, "tas_reset done"); + } + + if (!is_running) { + ClearInput(); + return; + } + if (current_command < script_length) { + LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); + size_t frame = current_command++; + for (size_t player_index = 0; player_index < commands.size(); player_index++) { + TASCommand command{}; + if (frame < commands[player_index].size()) { + command = commands[player_index][frame]; + } + + PadIdentifier identifier{ + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; + for (std::size_t i = 0; i < sizeof(command.buttons); ++i) { + const bool button_status = (command.buttons & (1U << i)) != 0; + const int button = static_cast(i); + SetButton(identifier, button, button_status); + } + SetAxis(identifier, TasAxes::StickX, command.l_axis.x); + SetAxis(identifier, TasAxes::StickY, command.l_axis.y); + SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); + SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); + } + } else { + is_running = Settings::values.tas_loop.GetValue(); + current_command = 0; + ClearInput(); + } +} + +void Tas::ClearInput() { + ResetButtonState(); + ResetAnalogState(); +} + +TasAnalog Tas::ReadCommandAxis(const std::string& line) const { + std::stringstream linestream(line); + std::string segment; + std::vector seglist; + + while (std::getline(linestream, segment, ';')) { + seglist.push_back(segment); + } + + const float x = std::stof(seglist.at(0)) / 32767.0f; + const float y = std::stof(seglist.at(1)) / 32767.0f; + + return {x, y}; +} + +u32 Tas::ReadCommandButtons(const std::string& data) const { + std::stringstream button_text(data); + std::string line; + u32 buttons = 0; + while (std::getline(button_text, line, ';')) { + for (auto [text, tas_button] : text_to_tas_button) { + if (text == line) { + buttons |= static_cast(tas_button); + break; + } + } + } + return buttons; +} + +std::string Tas::WriteCommandButtons(u32 buttons) const { + std::string returns = ""; + for (auto [text_button, tas_button] : text_to_tas_button) { + if ((buttons & static_cast(tas_button)) != 0) + returns += fmt::format("{};", text_button.substr(4)); + } + return returns.empty() ? "NONE" : returns.substr(2); +} + +std::string Tas::WriteCommandAxis(TasAnalog analog) const { + return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); +} + +void Tas::StartStop() { + if (!Settings::values.tas_enable) { + return; + } + if (is_running) { + Stop(); + } else { + is_running = true; + } +} + +void Tas::Stop() { + is_running = false; +} + +void Tas::Reset() { + if (!Settings::values.tas_enable) { + return; + } + needs_reset = true; +} + +bool Tas::Record() { + if (!Settings::values.tas_enable) { + return true; + } + is_recording = !is_recording; + return is_recording; +} + +void Tas::SaveRecording(bool overwrite_file) { + if (is_recording) { + return; + } + if (record_commands.empty()) { + return; + } + WriteTasFile(u8"record.txt"); + if (overwrite_file) { + WriteTasFile(u8"script0-1.txt"); + } + needs_reset = true; + record_commands.clear(); +} + +} // namespace InputCommon::TasInput diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h new file mode 100644 index 000000000..9fadc118b --- /dev/null +++ b/src/input_common/drivers/tas_input.h @@ -0,0 +1,200 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" +#include "common/settings_input.h" +#include "input_common/input_engine.h" +#include "input_common/main.h" + +/* +To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below +Tools -> Configure TAS. The file itself has normal text format and has to be called script0-1.txt +for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players). + +A script file has the same format as TAS-nx uses, so final files will look like this: + +1 KEY_B 0;0 0;0 +6 KEY_ZL 0;0 0;0 +41 KEY_ZL;KEY_Y 0;0 0;0 +43 KEY_X;KEY_A 32767;0 0;0 +44 KEY_A 32767;0 0;0 +45 KEY_A 32767;0 0;0 +46 KEY_A 32767;0 0;0 +47 KEY_A 32767;0 0;0 + +After placing the file at the correct location, it can be read into Yuzu with the (default) hotkey +CTRL+F6 (refresh). In the bottom left corner, it will display the amount of frames the script file +has. Playback can be started or stopped using CTRL+F5. + +However, for playback to actually work, the correct input device has to be selected: In the Controls +menu, select TAS from the device list for the controller that the script should be played on. + +Recording a new script file is really simple: Just make sure that the proper device (not TAS) is +connected on P1, and press CTRL+F7 to start recording. When done, just press the same keystroke +again (CTRL+F7). The new script will be saved at the location previously selected, as the filename +record.txt. + +For debugging purposes, the common controller debugger can be used (View -> Debugging -> Controller +P1). +*/ + +namespace InputCommon::TasInput { + +constexpr size_t PLAYER_NUMBER = 10; + +enum class TasButton : u32 { + BUTTON_A = 1U << 0, + BUTTON_B = 1U << 1, + BUTTON_X = 1U << 2, + BUTTON_Y = 1U << 3, + STICK_L = 1U << 4, + STICK_R = 1U << 5, + TRIGGER_L = 1U << 6, + TRIGGER_R = 1U << 7, + TRIGGER_ZL = 1U << 8, + TRIGGER_ZR = 1U << 9, + BUTTON_PLUS = 1U << 10, + BUTTON_MINUS = 1U << 11, + BUTTON_LEFT = 1U << 12, + BUTTON_UP = 1U << 13, + BUTTON_RIGHT = 1U << 14, + BUTTON_DOWN = 1U << 15, + BUTTON_SL = 1U << 16, + BUTTON_SR = 1U << 17, + BUTTON_HOME = 1U << 18, + BUTTON_CAPTURE = 1U << 19, +}; + +struct TasAnalog { + float x{}; + float y{}; +}; + +enum class TasState { + Running, + Recording, + Stopped, +}; + +class Tas final : public InputCommon::InputEngine { +public: + explicit Tas(const std::string input_engine_); + ~Tas(); + + /** + * Changes the input status that will be stored in each frame + * @param buttons: bitfield with the status of the buttons + * @param left_axis: value of the left axis + * @param right_axis: value of the right axis + */ + void RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis); + + // Main loop that records or executes input + void UpdateThread(); + + // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles + void StartStop(); + + // Stop the TAS and reverts any controller profile + void Stop(); + + // Sets the flag to reload the file and start from the begining in the next update + void Reset(); + + /** + * Sets the flag to enable or disable recording of inputs + * @return Returns true if the current recording status is enabled + */ + bool Record(); + + /** + * Saves contents of record_commands on a file + * @param overwrite_file: Indicates if player 1 should be overwritten + */ + void SaveRecording(bool overwrite_file); + + /** + * Returns the current status values of TAS playback/recording + * @return Tuple of + * TasState indicating the current state out of Running ; + * Current playback progress ; + * Total length of script file currently loaded or being recorded + */ + std::tuple GetStatus() const; + +private: + struct TASCommand { + u32 buttons{}; + TasAnalog l_axis{}; + TasAnalog r_axis{}; + }; + + /// Loads TAS files from all players + void LoadTasFiles(); + + /** Loads TAS file from the specified player + * @param player_index: player number where data is going to be stored + */ + void LoadTasFile(size_t player_index); + + /** Writes a TAS file from the recorded commands + * @param file_name: name of the file to be written + */ + void WriteTasFile(std::u8string file_name); + + /** Inverts the Y axis polarity + * @param old: value of the axis + * @return new value of the axis + */ + TasAnalog FlipAxisY(TasAnalog old); + + /** + * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 + * @param line: string containing axis values with the following format "x;y" + * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 + */ + TasAnalog ReadCommandAxis(const std::string& line) const; + + /** + * Parses a string containing the button values. Each button is represented by it's text format + * specified in text_to_tas_button array + * @param line: string containing button name with the following format "a;b;c;d..." + * @return Returns a u32 with each bit representing the status of a button + */ + u32 ReadCommandButtons(const std::string& line) const; + + /** + * Reset state of all players + */ + void ClearInput(); + + /** + * Converts an u32 containing the button status into the text equivalent + * @param buttons: bitfield with the status of the buttons + * @return Returns a string with the name of the buttons to be written to the file + */ + std::string WriteCommandButtons(u32 buttons) const; + + /** + * Converts an TAS analog object containing the axis status into the text equivalent + * @param data: value of the axis + * @return A string with the value of the axis to be written to the file + */ + std::string WriteCommandAxis(TasAnalog data) const; + + size_t script_length{0}; + bool is_old_input_saved{false}; + bool is_recording{false}; + bool is_running{false}; + bool needs_reset{false}; + std::array, PLAYER_NUMBER> commands{}; + std::vector record_commands{}; + size_t current_command{0}; + TASCommand last_input{}; // only used for recording +}; +} // namespace InputCommon::TasInput diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h deleted file mode 100644 index e5de5e94f..000000000 --- a/src/input_common/gcadapter/gc_adapter.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2014 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "input_common/main.h" - -struct libusb_context; -struct libusb_device; -struct libusb_device_handle; - -namespace GCAdapter { - -enum class PadButton { - Undefined = 0x0000, - ButtonLeft = 0x0001, - ButtonRight = 0x0002, - ButtonDown = 0x0004, - ButtonUp = 0x0008, - TriggerZ = 0x0010, - TriggerR = 0x0020, - TriggerL = 0x0040, - ButtonA = 0x0100, - ButtonB = 0x0200, - ButtonX = 0x0400, - ButtonY = 0x0800, - ButtonStart = 0x1000, - // Below is for compatibility with "AxisButton" type - Stick = 0x2000, -}; - -enum class PadAxes : u8 { - StickX, - StickY, - SubstickX, - SubstickY, - TriggerLeft, - TriggerRight, - Undefined, -}; - -enum class ControllerTypes { - None, - Wired, - Wireless, -}; - -struct GCPadStatus { - std::size_t port{}; - - PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits - - PadAxes axis{PadAxes::Undefined}; - s16 axis_value{}; - u8 axis_threshold{50}; -}; - -struct GCController { - ControllerTypes type{}; - bool enable_vibration{}; - u8 rumble_amplitude{}; - u16 buttons{}; - PadButton last_button{}; - std::array axis_values{}; - std::array axis_origin{}; - u8 reset_origin_counter{}; -}; - -class Adapter { -public: - Adapter(); - ~Adapter(); - - /// Request a vibration for a controller - bool RumblePlay(std::size_t port, u8 amplitude); - - /// Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - Common::SPSCQueue& GetPadQueue(); - const Common::SPSCQueue& GetPadQueue() const; - - GCController& GetPadState(std::size_t port); - const GCController& GetPadState(std::size_t port) const; - - /// Returns true if there is a device connected to port - bool DeviceConnected(std::size_t port) const; - - /// Used for automapping features - std::vector GetInputDevices() const; - InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; - InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; - -private: - using AdapterPayload = std::array; - - void UpdatePadType(std::size_t port, ControllerTypes pad_type); - void UpdateControllers(const AdapterPayload& adapter_payload); - void UpdateYuzuSettings(std::size_t port); - void UpdateStateButtons(std::size_t port, u8 b1, u8 b2); - void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); - void UpdateVibrations(); - - void AdapterInputThread(); - - void AdapterScanThread(); - - bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); - - // Updates vibration state of all controllers - void SendVibrations(); - - /// For use in initialization, querying devices to find the adapter - void Setup(); - - /// Resets status of all GC controller devices to a disconnected state - void ResetDevices(); - - /// Resets status of device connected to a disconnected state - void ResetDevice(std::size_t port); - - /// Returns true if we successfully gain access to GC Adapter - bool CheckDeviceAccess(); - - /// Captures GC Adapter endpoint address - /// Returns true if the endpoint was set correctly - bool GetGCEndpoint(libusb_device* device); - - /// For shutting down, clear all data, join all threads, release usb - void Reset(); - - // Join all threads - void JoinThreads(); - - // Release usb handles - void ClearLibusbHandle(); - - libusb_device_handle* usb_adapter_handle = nullptr; - std::array pads; - Common::SPSCQueue pad_queue; - - std::thread adapter_input_thread; - std::thread adapter_scan_thread; - bool adapter_input_thread_running; - bool adapter_scan_thread_running; - bool restart_scan_thread; - - libusb_context* libusb_ctx; - - u8 input_endpoint{0}; - u8 output_endpoint{0}; - u8 input_error_counter{0}; - u8 output_error_counter{0}; - int vibration_counter{0}; - - bool configuring{false}; - bool rumble_enabled{true}; - bool vibration_changed{true}; -}; -} // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp deleted file mode 100644 index 1b6ded8d6..000000000 --- a/src/input_common/gcadapter/gc_poller.cpp +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include "common/assert.h" -#include "common/threadsafe_queue.h" -#include "input_common/gcadapter/gc_adapter.h" -#include "input_common/gcadapter/gc_poller.h" - -namespace InputCommon { - -class GCButton final : public Input::ButtonDevice { -public: - explicit GCButton(u32 port_, s32 button_, const GCAdapter::Adapter* adapter) - : port(port_), button(button_), gcadapter(adapter) {} - - ~GCButton() override; - - bool GetStatus() const override { - if (gcadapter->DeviceConnected(port)) { - return (gcadapter->GetPadState(port).buttons & button) != 0; - } - return false; - } - -private: - const u32 port; - const s32 button; - const GCAdapter::Adapter* gcadapter; -}; - -class GCAxisButton final : public Input::ButtonDevice { -public: - explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_, - const GCAdapter::Adapter* adapter) - : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) {} - - bool GetStatus() const override { - if (gcadapter->DeviceConnected(port)) { - const float current_axis_value = gcadapter->GetPadState(port).axis_values.at(axis); - const float axis_value = current_axis_value / 128.0f; - if (trigger_if_greater) { - // TODO: Might be worthwile to set a slider for the trigger threshold. It is - // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick - return axis_value > threshold; - } - return axis_value < -threshold; - } - return false; - } - -private: - const u32 port; - const u32 axis; - float threshold; - bool trigger_if_greater; - const GCAdapter::Adapter* gcadapter; -}; - -GCButtonFactory::GCButtonFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -GCButton::~GCButton() = default; - -std::unique_ptr GCButtonFactory::Create(const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - const auto port = static_cast(params.Get("port", 0)); - - constexpr s32 PAD_STICK_ID = static_cast(GCAdapter::PadButton::Stick); - - // button is not an axis/stick button - if (button_id != PAD_STICK_ID) { - return std::make_unique(port, button_id, adapter.get()); - } - - // For Axis buttons, used by the binary sticks. - if (button_id == PAD_STICK_ID) { - const int axis = params.Get("axis", 0); - const float threshold = params.Get("threshold", 0.25f); - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - return std::make_unique(port, axis, threshold, trigger_if_greater, - adapter.get()); - } - - return nullptr; -} - -Common::ParamPackage GCButtonFactory::GetNextInput() const { - Common::ParamPackage params; - GCAdapter::GCPadStatus pad; - auto& queue = adapter->GetPadQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - params.Set("engine", "gcpad"); - params.Set("port", static_cast(pad.port)); - if (pad.button != GCAdapter::PadButton::Undefined) { - params.Set("button", static_cast(pad.button)); - } - - // For Axis button implementation - if (pad.axis != GCAdapter::PadAxes::Undefined) { - params.Set("axis", static_cast(pad.axis)); - params.Set("button", static_cast(GCAdapter::PadButton::Stick)); - params.Set("threshold", "0.25"); - if (pad.axis_value > 0) { - params.Set("direction", "+"); - } else { - params.Set("direction", "-"); - } - break; - } - } - return params; -} - -void GCButtonFactory::BeginConfiguration() { - polling = true; - adapter->BeginConfiguration(); -} - -void GCButtonFactory::EndConfiguration() { - polling = false; - adapter->EndConfiguration(); -} - -class GCAnalog final : public Input::AnalogDevice { -public: - explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, - float deadzone_, float range_, const GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), - deadzone(deadzone_), range(range_), gcadapter(adapter) {} - - float GetAxis(u32 axis) const { - if (gcadapter->DeviceConnected(port)) { - std::lock_guard lock{mutex}; - const auto axis_value = - static_cast(gcadapter->GetPadState(port).axis_values.at(axis)); - return (axis_value) / (100.0f * range); - } - return 0.0f; - } - - std::pair GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { - float x = GetAxis(analog_axis_x); - float y = GetAxis(analog_axis_y); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return {x, y}; - } - - std::tuple GetStatus() const override { - const auto [x, y] = GetAnalog(axis_x, axis_y); - const float r = std::sqrt((x * x) + (y * y)); - if (r > deadzone) { - return {x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)}; - } - return {0.0f, 0.0f}; - } - - std::tuple GetRawStatus() const override { - const float x = GetAxis(axis_x); - const float y = GetAxis(axis_y); - return {x, y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { - const auto [x, y] = GetStatus(); - const float directional_deadzone = 0.5f; - switch (direction) { - case Input::AnalogDirection::RIGHT: - return x > directional_deadzone; - case Input::AnalogDirection::LEFT: - return x < -directional_deadzone; - case Input::AnalogDirection::UP: - return y > directional_deadzone; - case Input::AnalogDirection::DOWN: - return y < -directional_deadzone; - } - return false; - } - -private: - const u32 port; - const u32 axis_x; - const u32 axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const GCAdapter::Adapter* gcadapter; - mutable std::mutex mutex; -}; - -/// An analog device factory that creates analog devices from GC Adapter -GCAnalogFactory::GCAnalogFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -/** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ -std::unique_ptr GCAnalogFactory::Create(const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - const auto axis_x = static_cast(params.Get("axis_x", 0)); - const auto axis_y = static_cast(params.Get("axis_y", 1)); - const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - - return std::make_unique(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, - adapter.get()); -} - -void GCAnalogFactory::BeginConfiguration() { - polling = true; - adapter->BeginConfiguration(); -} - -void GCAnalogFactory::EndConfiguration() { - polling = false; - adapter->EndConfiguration(); -} - -Common::ParamPackage GCAnalogFactory::GetNextInput() { - GCAdapter::GCPadStatus pad; - Common::ParamPackage params; - auto& queue = adapter->GetPadQueue(); - while (queue.Pop(pad)) { - if (pad.button != GCAdapter::PadButton::Undefined) { - params.Set("engine", "gcpad"); - params.Set("port", static_cast(pad.port)); - params.Set("button", static_cast(pad.button)); - return params; - } - if (pad.axis == GCAdapter::PadAxes::Undefined || - std::abs(static_cast(pad.axis_value) / 128.0f) < 0.1f) { - continue; - } - // An analog device needs two axes, so we need to store the axis for later and wait for - // a second input event. The axes also must be from the same joystick. - const u8 axis = static_cast(pad.axis); - if (axis == 0 || axis == 1) { - analog_x_axis = 0; - analog_y_axis = 1; - controller_number = static_cast(pad.port); - break; - } - if (axis == 2 || axis == 3) { - analog_x_axis = 2; - analog_y_axis = 3; - controller_number = static_cast(pad.port); - break; - } - - if (analog_x_axis == -1) { - analog_x_axis = axis; - controller_number = static_cast(pad.port); - } else if (analog_y_axis == -1 && analog_x_axis != axis && - controller_number == static_cast(pad.port)) { - analog_y_axis = axis; - break; - } - } - if (analog_x_axis != -1 && analog_y_axis != -1) { - params.Set("engine", "gcpad"); - params.Set("port", controller_number); - params.Set("axis_x", analog_x_axis); - params.Set("axis_y", analog_y_axis); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - analog_x_axis = -1; - analog_y_axis = -1; - controller_number = -1; - return params; - } - return params; -} - -class GCVibration final : public Input::VibrationDevice { -public: - explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter) - : port(port_), gcadapter(adapter) {} - - u8 GetStatus() const override { - return gcadapter->RumblePlay(port, 0); - } - - bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, - [[maybe_unused]] f32 freq_high) const override { - const auto mean_amplitude = (amp_low + amp_high) * 0.5f; - const auto processed_amplitude = - static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); - - return gcadapter->RumblePlay(port, processed_amplitude); - } - -private: - const u32 port; - GCAdapter::Adapter* gcadapter; -}; - -/// An vibration device factory that creates vibration devices from GC Adapter -GCVibrationFactory::GCVibrationFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -/** - * Creates a vibration device from a joystick - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - */ -std::unique_ptr GCVibrationFactory::Create( - const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - - return std::make_unique(port, adapter.get()); -} - -} // namespace InputCommon diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h deleted file mode 100644 index d1271e3ea..000000000 --- a/src/input_common/gcadapter/gc_poller.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/gcadapter/gc_adapter.h" - -namespace InputCommon { - -/** - * A button device factory representing a gcpad. It receives gcpad events and forward them - * to all button devices it created. - */ -class GCButtonFactory final : public Input::Factory { -public: - explicit GCButtonFactory(std::shared_ptr adapter_); - - /** - * Creates a button device from a button press - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr adapter; - bool polling = false; -}; - -/// An analog device factory that creates analog devices from GC Adapter -class GCAnalogFactory final : public Input::Factory { -public: - explicit GCAnalogFactory(std::shared_ptr adapter_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr adapter; - int analog_x_axis = -1; - int analog_y_axis = -1; - int controller_number = -1; - bool polling = false; -}; - -/// A vibration device factory creates vibration devices from GC Adapter -class GCVibrationFactory final : public Input::Factory { -public: - explicit GCVibrationFactory(std::shared_ptr adapter_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - -private: - std::shared_ptr adapter; -}; - -} // namespace InputCommon From dc3ab9e11068998ffd419f65f00fb336585b8e8c Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:26:08 -0500 Subject: [PATCH 058/291] input_common: Rewrite tas input --- src/input_common/CMakeLists.txt | 6 +- src/input_common/tas/tas_input.cpp | 455 ---------------------------- src/input_common/tas/tas_input.h | 237 --------------- src/input_common/tas/tas_poller.cpp | 101 ------ src/input_common/tas/tas_poller.h | 43 --- 5 files changed, 2 insertions(+), 840 deletions(-) delete mode 100644 src/input_common/tas/tas_input.cpp delete mode 100644 src/input_common/tas/tas_input.h delete mode 100644 src/input_common/tas/tas_poller.cpp delete mode 100644 src/input_common/tas/tas_poller.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index c8871513c..19270dc84 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(input_common STATIC drivers/keyboard.h drivers/mouse.cpp drivers/mouse.h + drivers/tas_input.cpp + drivers/tas_input.h drivers/touch_screen.cpp drivers/touch_screen.h helpers/stick_from_buttons.cpp @@ -27,10 +29,6 @@ add_library(input_common STATIC motion_input.h sdl/sdl.cpp sdl/sdl.h - tas/tas_input.cpp - tas/tas_input.h - tas/tas_poller.cpp - tas/tas_poller.h udp/client.cpp udp/client.h udp/udp.cpp diff --git a/src/input_common/tas/tas_input.cpp b/src/input_common/tas/tas_input.cpp deleted file mode 100644 index 1598092b6..000000000 --- a/src/input_common/tas/tas_input.cpp +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include - -#include "common/fs/file.h" -#include "common/fs/fs_types.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "input_common/tas/tas_input.h" - -namespace TasInput { - -// Supported keywords and buttons from a TAS file -constexpr std::array, 20> text_to_tas_button = { - std::pair{"KEY_A", TasButton::BUTTON_A}, - {"KEY_B", TasButton::BUTTON_B}, - {"KEY_X", TasButton::BUTTON_X}, - {"KEY_Y", TasButton::BUTTON_Y}, - {"KEY_LSTICK", TasButton::STICK_L}, - {"KEY_RSTICK", TasButton::STICK_R}, - {"KEY_L", TasButton::TRIGGER_L}, - {"KEY_R", TasButton::TRIGGER_R}, - {"KEY_PLUS", TasButton::BUTTON_PLUS}, - {"KEY_MINUS", TasButton::BUTTON_MINUS}, - {"KEY_DLEFT", TasButton::BUTTON_LEFT}, - {"KEY_DUP", TasButton::BUTTON_UP}, - {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, - {"KEY_DDOWN", TasButton::BUTTON_DOWN}, - {"KEY_SL", TasButton::BUTTON_SL}, - {"KEY_SR", TasButton::BUTTON_SR}, - {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, - {"KEY_HOME", TasButton::BUTTON_HOME}, - {"KEY_ZL", TasButton::TRIGGER_ZL}, - {"KEY_ZR", TasButton::TRIGGER_ZR}, -}; - -Tas::Tas() { - if (!Settings::values.tas_enable) { - needs_reset = true; - return; - } - LoadTasFiles(); -} - -Tas::~Tas() { - Stop(); -}; - -void Tas::LoadTasFiles() { - script_length = 0; - for (size_t i = 0; i < commands.size(); i++) { - LoadTasFile(i); - if (commands[i].size() > script_length) { - script_length = commands[i].size(); - } - } -} - -void Tas::LoadTasFile(size_t player_index) { - if (!commands[player_index].empty()) { - commands[player_index].clear(); - } - std::string file = - Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / - fmt::format("script0-{}.txt", player_index + 1), - Common::FS::FileType::BinaryFile); - std::stringstream command_line(file); - std::string line; - int frame_no = 0; - while (std::getline(command_line, line, '\n')) { - if (line.empty()) { - continue; - } - LOG_DEBUG(Input, "Loading line: {}", line); - std::smatch m; - - std::stringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ' ')) { - seglist.push_back(segment); - } - - if (seglist.size() < 4) { - continue; - } - - while (frame_no < std::stoi(seglist.at(0))) { - commands[player_index].push_back({}); - frame_no++; - } - - TASCommand command = { - .buttons = ReadCommandButtons(seglist.at(1)), - .l_axis = ReadCommandAxis(seglist.at(2)), - .r_axis = ReadCommandAxis(seglist.at(3)), - }; - commands[player_index].push_back(command); - frame_no++; - } - LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); -} - -void Tas::WriteTasFile(std::u8string file_name) { - std::string output_text; - for (size_t frame = 0; frame < record_commands.size(); frame++) { - if (!output_text.empty()) { - output_text += "\n"; - } - const TASCommand& line = record_commands[frame]; - output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " + - WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis); - } - const auto bytes_written = Common::FS::WriteStringToFile( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, - Common::FS::FileType::TextFile, output_text); - if (bytes_written == output_text.size()) { - LOG_INFO(Input, "TAS file written to file!"); - } else { - LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytes_written, - output_text.size()); - } -} - -std::pair Tas::FlipAxisY(std::pair old) { - auto [x, y] = old; - return {x, -y}; -} - -void Tas::RecordInput(u32 buttons, const std::array, 2>& axes) { - last_input = {buttons, FlipAxisY(axes[0]), FlipAxisY(axes[1])}; -} - -std::tuple Tas::GetStatus() const { - TasState state; - if (is_recording) { - return {TasState::Recording, 0, record_commands.size()}; - } - - if (is_running) { - state = TasState::Running; - } else { - state = TasState::Stopped; - } - - return {state, current_command, script_length}; -} - -std::string Tas::DebugButtons(u32 buttons) const { - return fmt::format("{{ {} }}", TasInput::Tas::ButtonsToString(buttons)); -} - -std::string Tas::DebugJoystick(float x, float y) const { - return fmt::format("[ {} , {} ]", std::to_string(x), std::to_string(y)); -} - -std::string Tas::DebugInput(const TasData& data) const { - return fmt::format("{{ {} , {} , {} }}", DebugButtons(data.buttons), - DebugJoystick(data.axis[0], data.axis[1]), - DebugJoystick(data.axis[2], data.axis[3])); -} - -std::string Tas::DebugInputs(const std::array& arr) const { - std::string returns = "[ "; - for (size_t i = 0; i < arr.size(); i++) { - returns += DebugInput(arr[i]); - if (i != arr.size() - 1) { - returns += " , "; - } - } - return returns + "]"; -} - -std::string Tas::ButtonsToString(u32 button) const { - std::string returns; - for (auto [text_button, tas_button] : text_to_tas_button) { - if ((button & static_cast(tas_button)) != 0) - returns += fmt::format(", {}", text_button.substr(4)); - } - return returns.empty() ? "" : returns.substr(2); -} - -void Tas::UpdateThread() { - if (!Settings::values.tas_enable) { - if (is_running) { - Stop(); - } - return; - } - - if (is_recording) { - record_commands.push_back(last_input); - } - if (needs_reset) { - current_command = 0; - needs_reset = false; - LoadTasFiles(); - LOG_DEBUG(Input, "tas_reset done"); - } - - if (!is_running) { - tas_data.fill({}); - return; - } - if (current_command < script_length) { - LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); - size_t frame = current_command++; - for (size_t i = 0; i < commands.size(); i++) { - if (frame < commands[i].size()) { - TASCommand command = commands[i][frame]; - tas_data[i].buttons = command.buttons; - auto [l_axis_x, l_axis_y] = command.l_axis; - tas_data[i].axis[0] = l_axis_x; - tas_data[i].axis[1] = l_axis_y; - auto [r_axis_x, r_axis_y] = command.r_axis; - tas_data[i].axis[2] = r_axis_x; - tas_data[i].axis[3] = r_axis_y; - } else { - tas_data[i] = {}; - } - } - } else { - is_running = Settings::values.tas_loop.GetValue(); - current_command = 0; - tas_data.fill({}); - if (!is_running) { - SwapToStoredController(); - } - } - LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data)); -} - -TasAnalog Tas::ReadCommandAxis(const std::string& line) const { - std::stringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ';')) { - seglist.push_back(segment); - } - - const float x = std::stof(seglist.at(0)) / 32767.0f; - const float y = std::stof(seglist.at(1)) / 32767.0f; - - return {x, y}; -} - -u32 Tas::ReadCommandButtons(const std::string& data) const { - std::stringstream button_text(data); - std::string line; - u32 buttons = 0; - while (std::getline(button_text, line, ';')) { - for (auto [text, tas_button] : text_to_tas_button) { - if (text == line) { - buttons |= static_cast(tas_button); - break; - } - } - } - return buttons; -} - -std::string Tas::WriteCommandAxis(TasAnalog data) const { - auto [x, y] = data; - std::string line; - line += std::to_string(static_cast(x * 32767)); - line += ";"; - line += std::to_string(static_cast(y * 32767)); - return line; -} - -std::string Tas::WriteCommandButtons(u32 data) const { - if (data == 0) { - return "NONE"; - } - - std::string line; - u32 index = 0; - while (data > 0) { - if ((data & 1) == 1) { - for (auto [text, tas_button] : text_to_tas_button) { - if (tas_button == static_cast(1 << index)) { - if (line.size() > 0) { - line += ";"; - } - line += text; - break; - } - } - } - index++; - data >>= 1; - } - return line; -} - -void Tas::StartStop() { - if (!Settings::values.tas_enable) { - return; - } - if (is_running) { - Stop(); - } else { - is_running = true; - SwapToTasController(); - } -} - -void Tas::Stop() { - is_running = false; - SwapToStoredController(); -} - -void Tas::SwapToTasController() { - if (!Settings::values.tas_swap_controllers) { - return; - } - auto& players = Settings::values.players.GetValue(); - for (std::size_t index = 0; index < players.size(); index++) { - auto& player = players[index]; - player_mappings[index] = player; - - // Only swap active controllers - if (!player.connected) { - continue; - } - - Common::ParamPackage tas_param; - tas_param.Set("pad", static_cast(index)); - auto button_mapping = GetButtonMappingForDevice(tas_param); - auto analog_mapping = GetAnalogMappingForDevice(tas_param); - auto& buttons = player.buttons; - auto& analogs = player.analogs; - - for (std::size_t i = 0; i < buttons.size(); ++i) { - buttons[i] = button_mapping[static_cast(i)].Serialize(); - } - for (std::size_t i = 0; i < analogs.size(); ++i) { - analogs[i] = analog_mapping[static_cast(i)].Serialize(); - } - } - is_old_input_saved = true; - Settings::values.is_device_reload_pending.store(true); -} - -void Tas::SwapToStoredController() { - if (!is_old_input_saved) { - return; - } - auto& players = Settings::values.players.GetValue(); - for (std::size_t index = 0; index < players.size(); index++) { - players[index] = player_mappings[index]; - } - is_old_input_saved = false; - Settings::values.is_device_reload_pending.store(true); -} - -void Tas::Reset() { - if (!Settings::values.tas_enable) { - return; - } - needs_reset = true; -} - -bool Tas::Record() { - if (!Settings::values.tas_enable) { - return true; - } - is_recording = !is_recording; - return is_recording; -} - -void Tas::SaveRecording(bool overwrite_file) { - if (is_recording) { - return; - } - if (record_commands.empty()) { - return; - } - WriteTasFile(u8"record.txt"); - if (overwrite_file) { - WriteTasFile(u8"script0-1.txt"); - } - needs_reset = true; - record_commands.clear(); -} - -InputCommon::ButtonMapping Tas::GetButtonMappingForDevice( - const Common::ParamPackage& params) const { - // 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, 20> - switch_to_tas_button = { - std::pair{Settings::NativeButton::A, TasButton::BUTTON_A}, - {Settings::NativeButton::B, TasButton::BUTTON_B}, - {Settings::NativeButton::X, TasButton::BUTTON_X}, - {Settings::NativeButton::Y, TasButton::BUTTON_Y}, - {Settings::NativeButton::LStick, TasButton::STICK_L}, - {Settings::NativeButton::RStick, TasButton::STICK_R}, - {Settings::NativeButton::L, TasButton::TRIGGER_L}, - {Settings::NativeButton::R, TasButton::TRIGGER_R}, - {Settings::NativeButton::Plus, TasButton::BUTTON_PLUS}, - {Settings::NativeButton::Minus, TasButton::BUTTON_MINUS}, - {Settings::NativeButton::DLeft, TasButton::BUTTON_LEFT}, - {Settings::NativeButton::DUp, TasButton::BUTTON_UP}, - {Settings::NativeButton::DRight, TasButton::BUTTON_RIGHT}, - {Settings::NativeButton::DDown, TasButton::BUTTON_DOWN}, - {Settings::NativeButton::SL, TasButton::BUTTON_SL}, - {Settings::NativeButton::SR, TasButton::BUTTON_SR}, - {Settings::NativeButton::Screenshot, TasButton::BUTTON_CAPTURE}, - {Settings::NativeButton::Home, TasButton::BUTTON_HOME}, - {Settings::NativeButton::ZL, TasButton::TRIGGER_ZL}, - {Settings::NativeButton::ZR, TasButton::TRIGGER_ZR}, - }; - - InputCommon::ButtonMapping mapping{}; - for (const auto& [switch_button, tas_button] : switch_to_tas_button) { - Common::ParamPackage button_params({{"engine", "tas"}}); - button_params.Set("pad", params.Get("pad", 0)); - button_params.Set("button", static_cast(tas_button)); - mapping.insert_or_assign(switch_button, std::move(button_params)); - } - - return mapping; -} - -InputCommon::AnalogMapping Tas::GetAnalogMappingForDevice( - const Common::ParamPackage& params) const { - - InputCommon::AnalogMapping mapping = {}; - Common::ParamPackage left_analog_params; - left_analog_params.Set("engine", "tas"); - left_analog_params.Set("pad", params.Get("pad", 0)); - left_analog_params.Set("axis_x", static_cast(TasAxes::StickX)); - left_analog_params.Set("axis_y", static_cast(TasAxes::StickY)); - mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); - Common::ParamPackage right_analog_params; - right_analog_params.Set("engine", "tas"); - right_analog_params.Set("pad", params.Get("pad", 0)); - right_analog_params.Set("axis_x", static_cast(TasAxes::SubstickX)); - right_analog_params.Set("axis_y", static_cast(TasAxes::SubstickY)); - mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); - return mapping; -} - -const TasData& Tas::GetTasState(std::size_t pad) const { - return tas_data[pad]; -} -} // namespace TasInput diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h deleted file mode 100644 index 3e2db8f00..000000000 --- a/src/input_common/tas/tas_input.h +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common/common_types.h" -#include "common/settings_input.h" -#include "core/frontend/input.h" -#include "input_common/main.h" - -/* -To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below -Tools -> Configure TAS. The file itself has normal text format and has to be called script0-1.txt -for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players). - -A script file has the same format as TAS-nx uses, so final files will look like this: - -1 KEY_B 0;0 0;0 -6 KEY_ZL 0;0 0;0 -41 KEY_ZL;KEY_Y 0;0 0;0 -43 KEY_X;KEY_A 32767;0 0;0 -44 KEY_A 32767;0 0;0 -45 KEY_A 32767;0 0;0 -46 KEY_A 32767;0 0;0 -47 KEY_A 32767;0 0;0 - -After placing the file at the correct location, it can be read into Yuzu with the (default) hotkey -CTRL+F6 (refresh). In the bottom left corner, it will display the amount of frames the script file -has. Playback can be started or stopped using CTRL+F5. - -However, for playback to actually work, the correct input device has to be selected: In the Controls -menu, select TAS from the device list for the controller that the script should be played on. - -Recording a new script file is really simple: Just make sure that the proper device (not TAS) is -connected on P1, and press CTRL+F7 to start recording. When done, just press the same keystroke -again (CTRL+F7). The new script will be saved at the location previously selected, as the filename -record.txt. - -For debugging purposes, the common controller debugger can be used (View -> Debugging -> Controller -P1). -*/ - -namespace TasInput { - -constexpr size_t PLAYER_NUMBER = 8; - -using TasAnalog = std::pair; - -enum class TasState { - Running, - Recording, - Stopped, -}; - -enum class TasButton : u32 { - BUTTON_A = 1U << 0, - BUTTON_B = 1U << 1, - BUTTON_X = 1U << 2, - BUTTON_Y = 1U << 3, - STICK_L = 1U << 4, - STICK_R = 1U << 5, - TRIGGER_L = 1U << 6, - TRIGGER_R = 1U << 7, - TRIGGER_ZL = 1U << 8, - TRIGGER_ZR = 1U << 9, - BUTTON_PLUS = 1U << 10, - BUTTON_MINUS = 1U << 11, - BUTTON_LEFT = 1U << 12, - BUTTON_UP = 1U << 13, - BUTTON_RIGHT = 1U << 14, - BUTTON_DOWN = 1U << 15, - BUTTON_SL = 1U << 16, - BUTTON_SR = 1U << 17, - BUTTON_HOME = 1U << 18, - BUTTON_CAPTURE = 1U << 19, -}; - -enum class TasAxes : u8 { - StickX, - StickY, - SubstickX, - SubstickY, - Undefined, -}; - -struct TasData { - u32 buttons{}; - std::array axis{}; -}; - -class Tas { -public: - Tas(); - ~Tas(); - - // Changes the input status that will be stored in each frame - void RecordInput(u32 buttons, const std::array, 2>& axes); - - // Main loop that records or executes input - void UpdateThread(); - - // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles - void StartStop(); - - // Stop the TAS and reverts any controller profile - void Stop(); - - // Sets the flag to reload the file and start from the begining in the next update - void Reset(); - - /** - * Sets the flag to enable or disable recording of inputs - * @return Returns true if the current recording status is enabled - */ - bool Record(); - - // Saves contents of record_commands on a file if overwrite is enabled player 1 will be - // overwritten with the recorded commands - void SaveRecording(bool overwrite_file); - - /** - * Returns the current status values of TAS playback/recording - * @return Tuple of - * TasState indicating the current state out of Running, Recording or Stopped ; - * Current playback progress or amount of frames (so far) for Recording ; - * Total length of script file currently loaded or amount of frames (so far) for Recording - */ - std::tuple GetStatus() const; - - // Retuns an array of the default button mappings - InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; - - // Retuns an array of the default analog mappings - InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; - [[nodiscard]] const TasData& GetTasState(std::size_t pad) const; - -private: - struct TASCommand { - u32 buttons{}; - TasAnalog l_axis{}; - TasAnalog r_axis{}; - }; - - // Loads TAS files from all players - void LoadTasFiles(); - - // Loads TAS file from the specified player - void LoadTasFile(size_t player_index); - - // Writes a TAS file from the recorded commands - void WriteTasFile(std::u8string file_name); - - /** - * Parses a string containing the axis values with the following format "x;y" - * X and Y have a range from -32767 to 32767 - * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 - */ - TasAnalog ReadCommandAxis(const std::string& line) const; - - /** - * Parses a string containing the button values with the following format "a;b;c;d..." - * Each button is represented by it's text format specified in text_to_tas_button array - * @return Returns a u32 with each bit representing the status of a button - */ - u32 ReadCommandButtons(const std::string& line) const; - - /** - * Converts an u32 containing the button status into the text equivalent - * @return Returns a string with the name of the buttons to be written to the file - */ - std::string WriteCommandButtons(u32 data) const; - - /** - * Converts an TAS analog object containing the axis status into the text equivalent - * @return Returns a string with the value of the axis to be written to the file - */ - std::string WriteCommandAxis(TasAnalog data) const; - - // Inverts the Y axis polarity - std::pair FlipAxisY(std::pair old); - - /** - * Converts an u32 containing the button status into the text equivalent - * @return Returns a string with the name of the buttons to be printed on console - */ - std::string DebugButtons(u32 buttons) const; - - /** - * Converts an TAS analog object containing the axis status into the text equivalent - * @return Returns a string with the value of the axis to be printed on console - */ - std::string DebugJoystick(float x, float y) const; - - /** - * Converts the given TAS status into the text equivalent - * @return Returns a string with the value of the TAS status to be printed on console - */ - std::string DebugInput(const TasData& data) const; - - /** - * Converts the given TAS status of multiple players into the text equivalent - * @return Returns a string with the value of the status of all TAS players to be printed on - * console - */ - std::string DebugInputs(const std::array& arr) const; - - /** - * Converts an u32 containing the button status into the text equivalent - * @return Returns a string with the name of the buttons - */ - std::string ButtonsToString(u32 button) const; - - // Stores current controller configuration and sets a TAS controller for every active controller - // to the current config - void SwapToTasController(); - - // Sets the stored controller configuration to the current config - void SwapToStoredController(); - - size_t script_length{0}; - std::array tas_data; - bool is_old_input_saved{false}; - bool is_recording{false}; - bool is_running{false}; - bool needs_reset{false}; - std::array, PLAYER_NUMBER> commands{}; - std::vector record_commands{}; - size_t current_command{0}; - TASCommand last_input{}; // only used for recording - - // Old settings for swapping controllers - std::array player_mappings; -}; -} // namespace TasInput diff --git a/src/input_common/tas/tas_poller.cpp b/src/input_common/tas/tas_poller.cpp deleted file mode 100644 index 15810d6b0..000000000 --- a/src/input_common/tas/tas_poller.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "input_common/tas/tas_input.h" -#include "input_common/tas/tas_poller.h" - -namespace InputCommon { - -class TasButton final : public Input::ButtonDevice { -public: - explicit TasButton(u32 button_, u32 pad_, const TasInput::Tas* tas_input_) - : button(button_), pad(pad_), tas_input(tas_input_) {} - - bool GetStatus() const override { - return (tas_input->GetTasState(pad).buttons & button) != 0; - } - -private: - const u32 button; - const u32 pad; - const TasInput::Tas* tas_input; -}; - -TasButtonFactory::TasButtonFactory(std::shared_ptr tas_input_) - : tas_input(std::move(tas_input_)) {} - -std::unique_ptr TasButtonFactory::Create(const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - const auto pad = params.Get("pad", 0); - - return std::make_unique(button_id, pad, tas_input.get()); -} - -class TasAnalog final : public Input::AnalogDevice { -public: - explicit TasAnalog(u32 pad_, u32 axis_x_, u32 axis_y_, const TasInput::Tas* tas_input_) - : pad(pad_), axis_x(axis_x_), axis_y(axis_y_), tas_input(tas_input_) {} - - float GetAxis(u32 axis) const { - std::lock_guard lock{mutex}; - return tas_input->GetTasState(pad).axis.at(axis); - } - - std::pair GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { - float x = GetAxis(analog_axis_x); - float y = GetAxis(analog_axis_y); - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return {x, y}; - } - - std::tuple GetStatus() const override { - return GetAnalog(axis_x, axis_y); - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {0.0f, 1.0f, 0.5f}; - } - -private: - const u32 pad; - const u32 axis_x; - const u32 axis_y; - const TasInput::Tas* tas_input; - mutable std::mutex mutex; -}; - -/// An analog device factory that creates analog devices from GC Adapter -TasAnalogFactory::TasAnalogFactory(std::shared_ptr tas_input_) - : tas_input(std::move(tas_input_)) {} - -/** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ -std::unique_ptr TasAnalogFactory::Create(const Common::ParamPackage& params) { - const auto pad = static_cast(params.Get("pad", 0)); - const auto axis_x = static_cast(params.Get("axis_x", 0)); - const auto axis_y = static_cast(params.Get("axis_y", 1)); - - return std::make_unique(pad, axis_x, axis_y, tas_input.get()); -} - -} // namespace InputCommon diff --git a/src/input_common/tas/tas_poller.h b/src/input_common/tas/tas_poller.h deleted file mode 100644 index 09e426cef..000000000 --- a/src/input_common/tas/tas_poller.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/tas/tas_input.h" - -namespace InputCommon { - -/** - * A button device factory representing a tas bot. It receives tas events and forward them - * to all button devices it created. - */ -class TasButtonFactory final : public Input::Factory { -public: - explicit TasButtonFactory(std::shared_ptr tas_input_); - - /** - * Creates a button device from a button press - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; - -private: - std::shared_ptr tas_input; -}; - -/// An analog device factory that creates analog devices from tas -class TasAnalogFactory final : public Input::Factory { -public: - explicit TasAnalogFactory(std::shared_ptr tas_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - -private: - std::shared_ptr tas_input; -}; - -} // namespace InputCommon From 10241886ddbead1a24a5924debf83a4fad0ade0d Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:33:19 -0500 Subject: [PATCH 059/291] input_common: Rewrite udp client --- src/input_common/CMakeLists.txt | 6 +- .../client.cpp => drivers/udp_client.cpp} | 240 +++--------------- .../{udp/client.h => drivers/udp_client.h} | 80 +----- src/input_common/udp/udp.cpp | 110 -------- src/input_common/udp/udp.h | 57 ----- 5 files changed, 53 insertions(+), 440 deletions(-) rename src/input_common/{udp/client.cpp => drivers/udp_client.cpp} (60%) rename src/input_common/{udp/client.h => drivers/udp_client.h} (56%) delete mode 100644 src/input_common/udp/udp.cpp delete mode 100644 src/input_common/udp/udp.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 19270dc84..9c0c82138 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -9,6 +9,8 @@ add_library(input_common STATIC drivers/tas_input.h drivers/touch_screen.cpp drivers/touch_screen.h + drivers/udp_client.cpp + drivers/udp_client.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp @@ -29,10 +31,6 @@ add_library(input_common STATIC motion_input.h sdl/sdl.cpp sdl/sdl.h - udp/client.cpp - udp/client.h - udp/udp.cpp - udp/udp.h ) if (MSVC) diff --git a/src/input_common/udp/client.cpp b/src/input_common/drivers/udp_client.cpp similarity index 60% rename from src/input_common/udp/client.cpp rename to src/input_common/drivers/udp_client.cpp index bcc29c4e0..6fcc3a01b 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -2,15 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include -#include -#include #include -#include #include + #include "common/logging/log.h" +#include "common/param_package.h" #include "common/settings.h" -#include "input_common/udp/client.h" +#include "input_common/drivers/udp_client.h" #include "input_common/helpers/udp_protocol.h" using boost::asio::ip::udp; @@ -86,7 +84,6 @@ private: case Type::PadData: { Response::PadData pad_data; std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); - SanitizeMotion(pad_data); callback.pad_data(std::move(pad_data)); break; } @@ -115,28 +112,6 @@ private: StartSend(timer.expiry()); } - void SanitizeMotion(Response::PadData& data) { - // Zero out any non number value - if (!std::isnormal(data.gyro.pitch)) { - data.gyro.pitch = 0; - } - if (!std::isnormal(data.gyro.roll)) { - data.gyro.roll = 0; - } - if (!std::isnormal(data.gyro.yaw)) { - data.gyro.yaw = 0; - } - if (!std::isnormal(data.accel.x)) { - data.accel.x = 0; - } - if (!std::isnormal(data.accel.y)) { - data.accel.y = 0; - } - if (!std::isnormal(data.accel.z)) { - data.accel.z = 0; - } - } - SocketCallback callback; boost::asio::io_service io_service; boost::asio::basic_waitable_timer timer; @@ -160,48 +135,23 @@ static void SocketLoop(Socket* socket) { socket->Loop(); } -Client::Client() { +UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { LOG_INFO(Input, "Udp Initialization started"); - finger_id.fill(MAX_TOUCH_FINGERS); ReloadSockets(); } -Client::~Client() { +UDPClient::~UDPClient() { Reset(); } -Client::ClientConnection::ClientConnection() = default; +UDPClient::ClientConnection::ClientConnection() = default; -Client::ClientConnection::~ClientConnection() = default; +UDPClient::ClientConnection::~ClientConnection() = default; -std::vector Client::GetInputDevices() const { - std::vector devices; - for (std::size_t pad = 0; pad < pads.size(); pad++) { - if (!DeviceConnected(pad)) { - continue; - } - std::string name = fmt::format("UDP Controller {}", pad); - devices.emplace_back(Common::ParamPackage{ - {"class", "cemuhookudp"}, - {"display", std::move(name)}, - {"port", std::to_string(pad)}, - }); - } - return devices; -} - -bool Client::DeviceConnected(std::size_t pad) const { - // Use last timestamp to detect if the socket has stopped sending data - const auto now = std::chrono::steady_clock::now(); - const auto time_difference = static_cast( - std::chrono::duration_cast(now - pads[pad].last_update).count()); - return time_difference < 1000 && pads[pad].connected; -} - -void Client::ReloadSockets() { +void UDPClient::ReloadSockets() { Reset(); - std::stringstream servers_ss(static_cast(Settings::values.udp_input_servers)); + std::stringstream servers_ss(Settings::values.udp_input_servers.GetValue()); std::string server_token; std::size_t client = 0; while (std::getline(servers_ss, server_token, ',')) { @@ -229,7 +179,7 @@ void Client::ReloadSockets() { } } -std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { +std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const { for (std::size_t client = 0; client < clients.size(); client++) { if (clients[client].active == -1) { continue; @@ -241,15 +191,15 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { return MAX_UDP_CLIENTS; } -void Client::OnVersion([[maybe_unused]] Response::Version data) { +void UDPClient::OnVersion([[maybe_unused]] Response::Version data) { LOG_TRACE(Input, "Version packet received: {}", data.version); } -void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { +void UDPClient::OnPortInfo([[maybe_unused]] Response::PortInfo data) { LOG_TRACE(Input, "PortInfo packet received: {}", data.model); } -void Client::OnPadData(Response::PadData data, std::size_t client) { +void UDPClient::OnPadData(Response::PadData data, std::size_t client) { const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; if (pad_index >= pads.size()) { @@ -277,32 +227,25 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { .count()); pads[pad_index].last_update = now; - const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; - pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); // Gyroscope values are not it the correct scale from better joy. // Dividing by 312 allows us to make one full turn = 1 turn // This must be a configurable valued called sensitivity - pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f); - pads[pad_index].motion.UpdateRotation(time_difference); - pads[pad_index].motion.UpdateOrientation(time_difference); + const float gyro_scale = 1.0f / 312.0f; - { - std::lock_guard guard(pads[pad_index].status.update_mutex); - pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion(); - - for (std::size_t id = 0; id < data.touch.size(); ++id) { - UpdateTouchInput(data.touch[id], client, id); - } - - if (configuring) { - const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope(); - const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration(); - UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope); - } - } + const BasicMotion motion{ + .gyro_x = data.gyro.pitch * gyro_scale, + .gyro_y = data.gyro.roll * gyro_scale, + .gyro_z = -data.gyro.yaw * gyro_scale, + .accel_x = data.accel.x, + .accel_y = -data.accel.z, + .accel_z = data.accel.y, + .delta_timestamp = time_difference, + }; + const PadIdentifier identifier = GetPadIdentifier(pad_index); + SetMotion(identifier, 0, motion); } -void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) { +void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, [this](Response::PortInfo info) { OnPortInfo(info); }, [this, client](Response::PadData data) { OnPadData(data, client); }}; @@ -312,16 +255,22 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 clients[client].active = 0; clients[client].socket = std::make_unique(host, port, callback); clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; - - // Set motion parameters - // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode - // Real HW values are unknown, 0.0001 is an approximate to Standard - for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) { - pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f); + for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { + const PadIdentifier identifier = GetPadIdentifier(client * PADS_PER_CLIENT + index); + PreSetController(identifier); } } -void Client::Reset() { +const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { + const std::size_t client = pad_index / PADS_PER_CLIENT; + return { + .guid = Common::UUID{clients[client].host}, + .port = static_cast(clients[client].port), + .pad = pad_index, + }; +} + +void UDPClient::Reset() { for (auto& client : clients) { if (client.thread.joinable()) { client.active = -1; @@ -331,117 +280,6 @@ void Client::Reset() { } } -void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index, - const Common::Vec3& acc, const Common::Vec3& gyro) { - if (gyro.Length() > 0.2f) { - LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, - gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); - } - UDPPadStatus pad{ - .host = clients[client].host, - .port = clients[client].port, - .pad_index = pad_index, - }; - for (std::size_t i = 0; i < 3; ++i) { - if (gyro[i] > 5.0f || gyro[i] < -5.0f) { - pad.motion = static_cast(i); - pad.motion_value = gyro[i]; - pad_queue.Push(pad); - } - if (acc[i] > 1.75f || acc[i] < -1.75f) { - pad.motion = static_cast(i + 3); - pad.motion_value = acc[i]; - pad_queue.Push(pad); - } - } -} - -std::optional Client::GetUnusedFingerID() const { - std::size_t first_free_id = 0; - while (first_free_id < MAX_TOUCH_FINGERS) { - if (!std::get<2>(touch_status[first_free_id])) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { - // TODO: Use custom calibration per device - const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); - const u16 min_x = static_cast(touch_param.Get("min_x", 100)); - const u16 min_y = static_cast(touch_param.Get("min_y", 50)); - const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); - const u16 max_y = static_cast(touch_param.Get("max_y", 850)); - const std::size_t touch_id = client * 2 + id; - if (touch_pad.is_active) { - if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id skip to next input - return; - } - finger_id[touch_id] = *first_free_id; - } - auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; - x = static_cast(std::clamp(static_cast(touch_pad.x), min_x, max_x) - min_x) / - static_cast(max_x - min_x); - y = static_cast(std::clamp(static_cast(touch_pad.y), min_y, max_y) - min_y) / - static_cast(max_y - min_y); - pressed = true; - return; - } - - if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { - touch_status[finger_id[touch_id]] = {}; - finger_id[touch_id] = MAX_TOUCH_FINGERS; - } -} - -void Client::BeginConfiguration() { - pad_queue.Clear(); - configuring = true; -} - -void Client::EndConfiguration() { - pad_queue.Clear(); - configuring = false; -} - -DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { - const std::size_t client_number = GetClientNumber(host, port); - if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { - return pads[0].status; - } - return pads[(client_number * PADS_PER_CLIENT) + pad].status; -} - -const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { - const std::size_t client_number = GetClientNumber(host, port); - if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { - return pads[0].status; - } - return pads[(client_number * PADS_PER_CLIENT) + pad].status; -} - -Input::TouchStatus& Client::GetTouchState() { - return touch_status; -} - -const Input::TouchStatus& Client::GetTouchState() const { - return touch_status; -} - -Common::SPSCQueue& Client::GetPadQueue() { - return pad_queue; -} - -const Common::SPSCQueue& Client::GetPadQueue() const { - return pad_queue; -} - void TestCommunication(const std::string& host, u16 port, const std::function& success_callback, const std::function& failure_callback) { diff --git a/src/input_common/udp/client.h b/src/input_common/drivers/udp_client.h similarity index 56% rename from src/input_common/udp/client.h rename to src/input_common/drivers/udp_client.h index 380f9bb76..58b2e921d 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/drivers/udp_client.h @@ -1,23 +1,14 @@ -// Copyright 2018 Citra Emulator Project +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// Refer to the license.txt file included #pragma once -#include -#include -#include #include -#include -#include -#include + #include "common/common_types.h" -#include "common/param_package.h" #include "common/thread.h" -#include "common/threadsafe_queue.h" -#include "common/vector_math.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" +#include "input_common/input_engine.h" namespace InputCommon::CemuhookUDP { @@ -30,16 +21,6 @@ struct TouchPad; struct Version; } // namespace Response -enum class PadMotion { - GyroX, - GyroY, - GyroZ, - AccX, - AccY, - AccZ, - Undefined, -}; - enum class PadTouch { Click, Undefined, @@ -49,14 +30,10 @@ struct UDPPadStatus { std::string host{"127.0.0.1"}; u16 port{26760}; std::size_t pad_index{}; - PadMotion motion{PadMotion::Undefined}; - f32 motion_value{0.0f}; }; struct DeviceStatus { std::mutex update_mutex; - Input::MotionStatus motion_status; - std::tuple touch_status; // calibration data for scaling the device's touch area to 3ds struct CalibrationData { @@ -68,32 +45,17 @@ struct DeviceStatus { std::optional touch_calibration; }; -class Client { +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class UDPClient final : public InputCommon::InputEngine { public: - // Initialize the UDP client capture and read sequence - Client(); + explicit UDPClient(const std::string& input_engine_); + ~UDPClient(); - // Close and release the client - ~Client(); - - // Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - std::vector GetInputDevices() const; - - bool DeviceConnected(std::size_t pad) const; void ReloadSockets(); - Common::SPSCQueue& GetPadQueue(); - const Common::SPSCQueue& GetPadQueue() const; - - DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); - const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; - - Input::TouchStatus& GetTouchState(); - const Input::TouchStatus& GetTouchState() const; - private: struct PadData { std::size_t pad_index{}; @@ -101,9 +63,6 @@ private: DeviceStatus status; u64 packet_sequence{}; - // Realtime values - // motion is initalized with PID values for drift correction on joycons - InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; std::chrono::time_point last_update; }; @@ -127,28 +86,13 @@ private: void OnPortInfo(Response::PortInfo); void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port); - void UpdateYuzuSettings(std::size_t client, std::size_t pad_index, - const Common::Vec3& acc, const Common::Vec3& gyro); - - // Returns an unused finger id, if there is no fingers available std::nullopt will be - // returned - std::optional GetUnusedFingerID() const; - - // Merges and updates all touch inputs into the touch_status array - void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); - - bool configuring = false; + const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; // Allocate clients for 8 udp servers static constexpr std::size_t MAX_UDP_CLIENTS = 8; static constexpr std::size_t PADS_PER_CLIENT = 4; - // Each client can have up 2 touch inputs - static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; std::array pads{}; std::array clients{}; - Common::SPSCQueue pad_queue{}; - Input::TouchStatus touch_status{}; - std::array finger_id{}; }; /// An async job allowing configuration of the touchpad calibration. diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp deleted file mode 100644 index 9829da6f0..000000000 --- a/src/input_common/udp/udp.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include "common/assert.h" -#include "common/threadsafe_queue.h" -#include "input_common/udp/client.h" -#include "input_common/udp/udp.h" - -namespace InputCommon { - -class UDPMotion final : public Input::MotionDevice { -public: - explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) - : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} - - Input::MotionStatus GetStatus() const override { - return client->GetPadState(ip, port, pad).motion_status; - } - -private: - const std::string ip; - const u16 port; - const u16 pad; - CemuhookUDP::Client* client; - mutable std::mutex mutex; -}; - -/// A motion device factory that creates motion devices from a UDP client -UDPMotionFactory::UDPMotionFactory(std::shared_ptr client_) - : client(std::move(client_)) {} - -/** - * Creates motion device - * @param params contains parameters for creating the device: - * - "port": the UDP port number - */ -std::unique_ptr UDPMotionFactory::Create(const Common::ParamPackage& params) { - auto ip = params.Get("ip", "127.0.0.1"); - const auto port = static_cast(params.Get("port", 26760)); - const auto pad = static_cast(params.Get("pad_index", 0)); - - return std::make_unique(std::move(ip), port, pad, client.get()); -} - -void UDPMotionFactory::BeginConfiguration() { - polling = true; - client->BeginConfiguration(); -} - -void UDPMotionFactory::EndConfiguration() { - polling = false; - client->EndConfiguration(); -} - -Common::ParamPackage UDPMotionFactory::GetNextInput() { - Common::ParamPackage params; - CemuhookUDP::UDPPadStatus pad; - auto& queue = client->GetPadQueue(); - while (queue.Pop(pad)) { - if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", pad.host); - params.Set("port", static_cast(pad.port)); - params.Set("pad_index", static_cast(pad.pad_index)); - params.Set("motion", static_cast(pad.motion)); - return params; - } - return params; -} - -class UDPTouch final : public Input::TouchDevice { -public: - explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) - : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} - - Input::TouchStatus GetStatus() const override { - return client->GetTouchState(); - } - -private: - const std::string ip; - [[maybe_unused]] const u16 port; - [[maybe_unused]] const u16 pad; - CemuhookUDP::Client* client; - mutable std::mutex mutex; -}; - -/// A motion device factory that creates motion devices from a UDP client -UDPTouchFactory::UDPTouchFactory(std::shared_ptr client_) - : client(std::move(client_)) {} - -/** - * Creates motion device - * @param params contains parameters for creating the device: - * - "port": the UDP port number - */ -std::unique_ptr UDPTouchFactory::Create(const Common::ParamPackage& params) { - auto ip = params.Get("ip", "127.0.0.1"); - const auto port = static_cast(params.Get("port", 26760)); - const auto pad = static_cast(params.Get("pad_index", 0)); - - return std::make_unique(std::move(ip), port, pad, client.get()); -} - -} // namespace InputCommon diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h deleted file mode 100644 index ea3fd4175..000000000 --- a/src/input_common/udp/udp.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/udp/client.h" - -namespace InputCommon { - -/// A motion device factory that creates motion devices from udp clients -class UDPMotionFactory final : public Input::Factory { -public: - explicit UDPMotionFactory(std::shared_ptr client_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr client; - bool polling = false; -}; - -/// A touch device factory that creates touch devices from udp clients -class UDPTouchFactory final : public Input::Factory { -public: - explicit UDPTouchFactory(std::shared_ptr client_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr client; - bool polling = false; -}; - -} // namespace InputCommon From 59b995a9e53f09b9831b03608cfe5ce27c3e3485 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:36:23 -0500 Subject: [PATCH 060/291] input_common: Rewrite SDL --- src/input_common/CMakeLists.txt | 8 +- src/input_common/drivers/sdl_driver.cpp | 915 +++++++++ .../{sdl/sdl_impl.h => drivers/sdl_driver.h} | 56 +- src/input_common/sdl/sdl.cpp | 19 - src/input_common/sdl/sdl.h | 51 - src/input_common/sdl/sdl_impl.cpp | 1658 ----------------- 6 files changed, 950 insertions(+), 1757 deletions(-) create mode 100644 src/input_common/drivers/sdl_driver.cpp rename src/input_common/{sdl/sdl_impl.h => drivers/sdl_driver.h} (67%) delete mode 100644 src/input_common/sdl/sdl.cpp delete mode 100644 src/input_common/sdl/sdl.h delete mode 100644 src/input_common/sdl/sdl_impl.cpp diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 9c0c82138..8cdcd315b 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(input_common STATIC drivers/keyboard.h drivers/mouse.cpp drivers/mouse.h + drivers/sdl_driver.cpp + drivers/sdl_driver.h drivers/tas_input.cpp drivers/tas_input.h drivers/touch_screen.cpp @@ -29,8 +31,6 @@ add_library(input_common STATIC motion_from_button.h motion_input.cpp motion_input.h - sdl/sdl.cpp - sdl/sdl.h ) if (MSVC) @@ -57,8 +57,8 @@ endif() if (ENABLE_SDL2) target_sources(input_common PRIVATE - sdl/sdl_impl.cpp - sdl/sdl_impl.h + drivers/sdl_driver.cpp + drivers/sdl_driver.h ) target_link_libraries(input_common PRIVATE SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp new file mode 100644 index 000000000..efb4a2106 --- /dev/null +++ b/src/input_common/drivers/sdl_driver.cpp @@ -0,0 +1,915 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "common/math_util.h" +#include "common/param_package.h" +#include "common/settings.h" +#include "common/thread.h" +#include "common/vector_math.h" +#include "input_common/drivers/sdl_driver.h" + +namespace InputCommon { + +namespace { +std::string GetGUID(SDL_Joystick* joystick) { + const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + char guid_str[33]; + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + return guid_str; +} +} // Anonymous namespace + +static int SDLEventWatcher(void* user_data, SDL_Event* event) { + auto* const sdl_state = static_cast(user_data); + + sdl_state->HandleGameControllerEvent(*event); + + return 0; +} + +class SDLJoystick { +public: + SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, + SDL_GameController* game_controller) + : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, + sdl_controller{game_controller, &SDL_GameControllerClose} { + EnableMotion(); + } + + void EnableMotion() { + if (sdl_controller) { + SDL_GameController* controller = sdl_controller.get(); + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); + has_accel = true; + } + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); + has_gyro = true; + } + } + } + + bool HasGyro() const { + return has_gyro; + } + + bool HasAccel() const { + return has_accel; + } + + bool UpdateMotion(SDL_ControllerSensorEvent event) { + constexpr float gravity_constant = 9.80665f; + std::lock_guard lock{mutex}; + const u64 time_difference = event.timestamp - last_motion_update; + last_motion_update = event.timestamp; + switch (event.sensor) { + case SDL_SENSOR_ACCEL: { + motion.accel_x = -event.data[0] / gravity_constant; + motion.accel_y = event.data[2] / gravity_constant; + motion.accel_z = -event.data[1] / gravity_constant; + break; + } + case SDL_SENSOR_GYRO: { + motion.gyro_x = event.data[0] / (Common::PI * 2); + motion.gyro_y = -event.data[2] / (Common::PI * 2); + motion.gyro_z = event.data[1] / (Common::PI * 2); + break; + } + } + + // Ignore duplicated timestamps + if (time_difference == 0) { + return false; + } + motion.delta_timestamp = time_difference * 1000; + return true; + } + + BasicMotion GetMotion() { + return motion; + } + + bool RumblePlay(const Input::VibrationStatus vibration) { + constexpr u32 rumble_max_duration_ms = 1000; + + if (sdl_controller) { + return SDL_GameControllerRumble( + sdl_controller.get(), static_cast(vibration.low_amplitude), + static_cast(vibration.high_amplitude), rumble_max_duration_ms) != -1; + } else if (sdl_joystick) { + return SDL_JoystickRumble(sdl_joystick.get(), static_cast(vibration.low_amplitude), + static_cast(vibration.high_amplitude), + rumble_max_duration_ms) != -1; + } + + return false; + } + /** + * The Pad identifier of the joystick + */ + const PadIdentifier GetPadIdentifier() const { + return { + .guid = Common::UUID{guid}, + .port = static_cast(port), + .pad = 0, + }; + } + + /** + * The guid of the joystick + */ + const std::string& GetGUID() const { + return guid; + } + + /** + * The number of joystick from the same type that were connected before this joystick + */ + int GetPort() const { + return port; + } + + SDL_Joystick* GetSDLJoystick() const { + return sdl_joystick.get(); + } + + SDL_GameController* GetSDLGameController() const { + return sdl_controller.get(); + } + + void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) { + sdl_joystick.reset(joystick); + sdl_controller.reset(controller); + } + + bool IsJoyconLeft() const { + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { + return true; + } + return false; + } + + bool IsJoyconRight() const { + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { + return true; + } + return false; + } + + BatteryLevel GetBatteryLevel() { + const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); + switch (level) { + case SDL_JOYSTICK_POWER_EMPTY: + return BatteryLevel::Empty; + case SDL_JOYSTICK_POWER_LOW: + return BatteryLevel::Critical; + case SDL_JOYSTICK_POWER_MEDIUM: + return BatteryLevel::Low; + case SDL_JOYSTICK_POWER_FULL: + return BatteryLevel::Medium; + case SDL_JOYSTICK_POWER_MAX: + return BatteryLevel::Full; + case SDL_JOYSTICK_POWER_UNKNOWN: + case SDL_JOYSTICK_POWER_WIRED: + default: + return BatteryLevel::Charging; + } + } + + std::string GetControllerName() const { + if (sdl_controller) { + switch (SDL_GameControllerGetType(sdl_controller.get())) { + case SDL_CONTROLLER_TYPE_XBOX360: + return "XBox 360 Controller"; + case SDL_CONTROLLER_TYPE_XBOXONE: + return "XBox One Controller"; + default: + break; + } + const auto name = SDL_GameControllerName(sdl_controller.get()); + if (name) { + return name; + } + } + + if (sdl_joystick) { + const auto name = SDL_JoystickName(sdl_joystick.get()); + if (name) { + return name; + } + } + + return "Unknown"; + } + + bool IsYAxis(u8 index) { + if (!sdl_controller) { + return false; + } + + const auto& binding_left_y = + SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_LEFTY); + const auto& binding_right_y = + SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_RIGHTY); + if (index == binding_left_y.value.axis) { + return true; + } + if (index == binding_right_y.value.axis) { + return true; + } + return false; + } + +private: + std::string guid; + int port; + std::unique_ptr sdl_joystick; + std::unique_ptr sdl_controller; + mutable std::mutex mutex; + + u64 last_motion_update{}; + bool has_gyro{false}; + bool has_accel{false}; + BasicMotion motion; +}; + +std::shared_ptr SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { + std::lock_guard lock{joystick_map_mutex}; + const auto it = joystick_map.find(guid); + + if (it != joystick_map.end()) { + while (it->second.size() <= static_cast(port)) { + auto joystick = std::make_shared(guid, static_cast(it->second.size()), + nullptr, nullptr); + it->second.emplace_back(std::move(joystick)); + } + + return it->second[static_cast(port)]; + } + + auto joystick = std::make_shared(guid, 0, nullptr, nullptr); + + return joystick_map[guid].emplace_back(std::move(joystick)); +} + +std::shared_ptr SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { + auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + const auto map_it = joystick_map.find(guid); + + if (map_it == joystick_map.end()) { + return nullptr; + } + + const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), + [&sdl_joystick](const auto& joystick) { + return joystick->GetSDLJoystick() == sdl_joystick; + }); + + if (vec_it == map_it->second.end()) { + return nullptr; + } + + return *vec_it; +} + +void SDLDriver::InitJoystick(int joystick_index) { + SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); + SDL_GameController* sdl_gamecontroller = nullptr; + + if (SDL_IsGameController(joystick_index)) { + sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); + } + + if (!sdl_joystick) { + LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); + return; + } + + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + if (joystick_map.find(guid) == joystick_map.end()) { + auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); + PreSetController(joystick->GetPadIdentifier()); + joystick_map[guid].emplace_back(std::move(joystick)); + return; + } + + auto& joystick_guid_list = joystick_map[guid]; + const auto joystick_it = + std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), + [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); + + if (joystick_it != joystick_guid_list.end()) { + (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); + return; + } + + const int port = static_cast(joystick_guid_list.size()); + auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); + PreSetController(joystick->GetPadIdentifier()); + joystick_guid_list.emplace_back(std::move(joystick)); +} + +void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + // This call to guid is safe since the joystick is guaranteed to be in the map + const auto& joystick_guid_list = joystick_map[guid]; + const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), + [&sdl_joystick](const auto& joystick) { + return joystick->GetSDLJoystick() == sdl_joystick; + }); + + if (joystick_it != joystick_guid_list.end()) { + (*joystick_it)->SetSDLJoystick(nullptr, nullptr); + } +} + +void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { + switch (event.type) { + case SDL_JOYBUTTONUP: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetButton(identifier, event.jbutton.button, false); + } + break; + } + case SDL_JOYBUTTONDOWN: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetButton(identifier, event.jbutton.button, true); + } + break; + } + case SDL_JOYHATMOTION: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetHatButton(identifier, event.jhat.hat, event.jhat.value); + } + break; + } + case SDL_JOYAXISMOTION: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + // Vertical axis is inverted on nintendo compared to SDL + if (joystick->IsYAxis(event.jaxis.axis)) { + SetAxis(identifier, event.jaxis.axis, -event.jaxis.value / 32767.0f); + break; + } + SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f); + } + break; + } + case SDL_CONTROLLERSENSORUPDATE: { + if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { + if (joystick->UpdateMotion(event.csensor)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetMotion(identifier, 0, joystick->GetMotion()); + }; + } + break; + } + case SDL_JOYDEVICEREMOVED: + LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); + CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); + break; + case SDL_JOYDEVICEADDED: + LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); + InitJoystick(event.jdevice.which); + break; + } +} + +void SDLDriver::CloseJoysticks() { + std::lock_guard lock{joystick_map_mutex}; + joystick_map.clear(); +} + +SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { + Common::SetCurrentThreadName("yuzu:input:SDL"); + + if (!Settings::values.enable_raw_input) { + // Disable raw input. When enabled this setting causes SDL to die when a web applet opens + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); + } + + // Prevent SDL from adding undesired axis + SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); + + // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + + // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and + // not a generic one + SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + + // Turn off Pro controller home led + SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + + // If the frontend is going to manage the event loop, then we don't start one here + start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; + if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { + LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError()); + return; + } + + SDL_AddEventWatch(&SDLEventWatcher, this); + + initialized = true; + if (start_thread) { + poll_thread = std::thread([this] { + using namespace std::chrono_literals; + while (initialized) { + SDL_PumpEvents(); + std::this_thread::sleep_for(1ms); + } + }); + } + // Because the events for joystick connection happens before we have our event watcher added, we + // can just open all the joysticks right here + for (int i = 0; i < SDL_NumJoysticks(); ++i) { + InitJoystick(i); + } +} + +SDLDriver::~SDLDriver() { + CloseJoysticks(); + SDL_DelEventWatch(&SDLEventWatcher, this); + + initialized = false; + if (start_thread) { + poll_thread.join(); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); + } +} + +std::vector SDLDriver::GetInputDevices() const { + std::vector devices; + std::unordered_map> joycon_pairs; + for (const auto& [key, value] : joystick_map) { + for (const auto& joystick : value) { + if (!joystick->GetSDLJoystick()) { + continue; + } + const std::string name = + fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); + devices.emplace_back(Common::ParamPackage{ + {"engine", "sdl"}, + {"display", std::move(name)}, + {"guid", joystick->GetGUID()}, + {"port", std::to_string(joystick->GetPort())}, + }); + if (joystick->IsJoyconLeft()) { + joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); + } + } + } + + // Add dual controllers + for (const auto& [key, value] : joystick_map) { + for (const auto& joystick : value) { + if (joystick->IsJoyconRight()) { + if (!joycon_pairs.contains(joystick->GetPort())) { + continue; + } + const auto joystick2 = joycon_pairs.at(joystick->GetPort()); + + const std::string name = + fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); + devices.emplace_back(Common::ParamPackage{ + {"engine", "sdl"}, + {"display", std::move(name)}, + {"guid", joystick->GetGUID()}, + {"guid2", joystick2->GetGUID()}, + {"port", std::to_string(joystick->GetPort())}, + }); + } + } + } + return devices; +} +bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { + const auto joystick = + GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); + const auto process_amplitude = [](f32 amplitude) { + return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; + }; + const Input::VibrationStatus new_vibration{ + .low_amplitude = process_amplitude(vibration.low_amplitude), + .low_frequency = vibration.low_frequency, + .high_amplitude = process_amplitude(vibration.high_amplitude), + .high_frequency = vibration.high_frequency, + }; + + return joystick->RumblePlay(new_vibration); +} +Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, + s32 axis, float value) const { + Common::ParamPackage params({{"engine", "sdl"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("axis", axis); + params.Set("threshold", "0.5"); + params.Set("invert", value < 0 ? "-" : "+"); + return params; +} + +Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, + s32 button) const { + Common::ParamPackage params({{"engine", "sdl"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("button", button); + return params; +} + +Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, + u8 value) const { + Common::ParamPackage params({{"engine", "sdl"}}); + + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("hat", hat); + params.Set("direction", GetHatButtonName(value)); + return params; +} + +Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { + Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + return params; +} + +Common::ParamPackage SDLDriver::BuildParamPackageForBinding( + int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const { + switch (binding.bindType) { + case SDL_CONTROLLER_BINDTYPE_NONE: + break; + case SDL_CONTROLLER_BINDTYPE_AXIS: + return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); + case SDL_CONTROLLER_BINDTYPE_BUTTON: + return BuildButtonParamPackageForButton(port, guid, binding.value.button); + case SDL_CONTROLLER_BINDTYPE_HAT: + return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat, + static_cast(binding.value.hat.hat_mask)); + } + return {}; +} + +Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, + int axis_y, float offset_x, + float offset_y) const { + Common::ParamPackage params; + params.Set("engine", "sdl"); + params.Set("port", static_cast(identifier.port)); + params.Set("guid", identifier.guid.Format()); + params.Set("axis_x", axis_x); + params.Set("axis_y", axis_y); + params.Set("offset_x", offset_x); + params.Set("offset_y", offset_y); + params.Set("invert_x", "+"); + params.Set("invert_y", "+"); + return params; +} + +ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. + // We will add those afterwards + // This list also excludes Screenshot since theres not really a mapping for that + ButtonBindings switch_to_sdl_button; + + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + switch_to_sdl_button = GetNintendoButtonBinding(joystick); + } else { + switch_to_sdl_button = GetDefaultButtonBinding(); + } + + // Add the missing bindings for ZL/ZR + static constexpr ZButtonBindings switch_to_sdl_axis{{ + {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, + {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, + }}; + + // Parameters contain two joysticks return dual + if (params.Has("guid2")) { + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + + if (joystick2->GetSDLGameController() != nullptr) { + return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, + switch_to_sdl_axis); + } + } + + return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); +} + +ButtonBindings SDLDriver::GetDefaultButtonBinding() const { + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, + {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, + {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, + {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {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, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, + }; +} + +ButtonBindings SDLDriver::GetNintendoButtonBinding( + const std::shared_ptr& joystick) const { + // Default SL/SR mapping for pro controllers + auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + + if (joystick->IsJoyconLeft()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; + } + if (joystick->IsJoyconRight()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; + } + + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, + {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, + {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {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::Home, SDL_CONTROLLER_BUTTON_GUIDE}, + }; +} + +ButtonMapping SDLDriver::GetSingleControllerMapping( + const std::shared_ptr& joystick, const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { + ButtonMapping mapping; + mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); + + for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { + const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { + const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + + return mapping; +} + +ButtonMapping SDLDriver::GetDualControllerMapping(const std::shared_ptr& joystick, + const std::shared_ptr& joystick2, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { + ButtonMapping mapping; + mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); + auto* controller2 = joystick2->GetSDLGameController(); + + for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + + return mapping; +} + +bool SDLDriver::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { + switch (button) { + case Settings::NativeButton::DDown: + case Settings::NativeButton::DLeft: + case Settings::NativeButton::DRight: + case Settings::NativeButton::DUp: + case Settings::NativeButton::L: + case Settings::NativeButton::LStick: + case Settings::NativeButton::Minus: + case Settings::NativeButton::Screenshot: + case Settings::NativeButton::ZL: + return true; + default: + return false; + } +} + +AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + AnalogMapping mapping = {}; + const auto& binding_left_x = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); + const auto& binding_left_y = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + if (params.Has("guid2")) { + const auto identifier = joystick2->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_left_x.value.axis); + PreSetAxis(identifier, binding_left_y.value.axis); + const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis); + const auto left_offset_y = -GetAxis(identifier, binding_left_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(identifier, binding_left_x.value.axis, + binding_left_y.value.axis, + left_offset_x, left_offset_y)); + } else { + const auto identifier = joystick->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_left_x.value.axis); + PreSetAxis(identifier, binding_left_y.value.axis); + const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis); + const auto left_offset_y = -GetAxis(identifier, binding_left_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(identifier, binding_left_x.value.axis, + binding_left_y.value.axis, + left_offset_x, left_offset_y)); + } + const auto& binding_right_x = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); + const auto& binding_right_y = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); + const auto identifier = joystick->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_right_x.value.axis); + PreSetAxis(identifier, binding_right_y.value.axis); + const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis); + const auto right_offset_y = -GetAxis(identifier, binding_right_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, + BuildParamPackageForAnalog(identifier, binding_right_x.value.axis, + binding_right_y.value.axis, right_offset_x, + right_offset_y)); + return mapping; +} + +MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + MotionMapping mapping = {}; + joystick->EnableMotion(); + + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionRight, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } + if (params.Has("guid2")) { + joystick2->EnableMotion(); + if (joystick2->HasGyro() || joystick2->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); + } + } else { + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } + } + + return mapping; +} + +std::string SDLDriver::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + // TODO(German77): Find how to substitue the values for real button names + return fmt::format("Button {}", params.Get("button", 0)); + } + if (params.Has("hat")) { + return fmt::format("Hat {}", params.Get("direction", "")); + } + if (params.Has("axis")) { + return fmt::format("Axis {}", params.Get("axis", "")); + } + if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { + return fmt::format("Axis {},{},{}", params.Get("axis_x", ""), params.Get("axis_y", ""), + params.Get("axis_z", "")); + } + if (params.Has("motion")) { + return "SDL motion"; + } + + return "Bad SDL"; +} + +std::string SDLDriver::GetHatButtonName(u8 direction_value) const { + switch (direction_value) { + case SDL_HAT_UP: + return "up"; + case SDL_HAT_DOWN: + return "down"; + case SDL_HAT_LEFT: + return "left"; + case SDL_HAT_RIGHT: + return "right"; + default: + return {}; + } +} + +u8 SDLDriver::GetHatButtonId(const std::string direction_name) const { + Uint8 direction; + if (direction_name == "up") { + direction = SDL_HAT_UP; + } else if (direction_name == "down") { + direction = SDL_HAT_DOWN; + } else if (direction_name == "left") { + direction = SDL_HAT_LEFT; + } else if (direction_name == "right") { + direction = SDL_HAT_RIGHT; + } else { + direction = 0; + } + return direction; +} + +} // namespace InputCommon diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/drivers/sdl_driver.h similarity index 67% rename from src/input_common/sdl/sdl_impl.h rename to src/input_common/drivers/sdl_driver.h index 7a9ad6346..d8d350184 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/drivers/sdl_driver.h @@ -5,7 +5,6 @@ #pragma once #include -#include #include #include #include @@ -13,8 +12,7 @@ #include #include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "input_common/sdl/sdl.h" +#include "input_common/input_engine.h" union SDL_Event; using SDL_GameController = struct _SDL_GameController; @@ -26,21 +24,17 @@ using ButtonBindings = using ZButtonBindings = std::array, 2>; -namespace InputCommon::SDL { +namespace InputCommon { -class SDLAnalogFactory; -class SDLButtonFactory; -class SDLMotionFactory; -class SDLVibrationFactory; class SDLJoystick; -class SDLState : public State { +class SDLDriver : public InputCommon::InputEngine { public: /// Initializes and registers SDL device factories - SDLState(); + SDLDriver(const std::string& input_engine_); /// Unregisters SDL device factories and shut them down. - ~SDLState() override; + ~SDLDriver() override; /// Handle SDL_Events for joysticks from SDL_PollEvent void HandleGameControllerEvent(const SDL_Event& event); @@ -54,18 +48,18 @@ public: */ std::shared_ptr GetSDLJoystickByGUID(const std::string& guid, int port); - /// Get all DevicePoller that use the SDL backend for a specific device type - Pollers GetPollers(Polling::DeviceType type) override; - - /// Used by the Pollers during config - std::atomic polling = false; - Common::SPSCQueue event_queue; - - std::vector GetInputDevices() override; + std::vector GetInputDevices() const override; ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; + std::string GetUIName(const Common::ParamPackage& params) const override; + + std::string GetHatButtonName(u8 direction_value) const override; + u8 GetHatButtonId(const std::string direction_name) const override; + + bool SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) override; private: void InitJoystick(int joystick_index); @@ -74,6 +68,23 @@ private: /// Needs to be called before SDL_QuitSubSystem. void CloseJoysticks(); + Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, + float value = 0.1f) const; + Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, + s32 button) const; + + Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, + u8 value) const; + + Common::ParamPackage BuildMotionParam(int port, std::string guid) const; + + Common::ParamPackage BuildParamPackageForBinding( + int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const; + + Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, + int axis_y, float offset_x, + float offset_y) const; + /// Returns the default button bindings list for generic controllers ButtonBindings GetDefaultButtonBinding() const; @@ -101,14 +112,9 @@ private: std::unordered_map>> joystick_map; std::mutex joystick_map_mutex; - std::shared_ptr button_factory; - std::shared_ptr analog_factory; - std::shared_ptr vibration_factory; - std::shared_ptr motion_factory; - bool start_thread = false; std::atomic initialized = false; std::thread poll_thread; }; -} // namespace InputCommon::SDL +} // namespace InputCommon diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp deleted file mode 100644 index 644db3448..000000000 --- a/src/input_common/sdl/sdl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "input_common/sdl/sdl.h" -#ifdef HAVE_SDL2 -#include "input_common/sdl/sdl_impl.h" -#endif - -namespace InputCommon::SDL { - -std::unique_ptr Init() { -#ifdef HAVE_SDL2 - return std::make_unique(); -#else - return std::make_unique(); -#endif -} -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h deleted file mode 100644 index b5d41bba4..000000000 --- a/src/input_common/sdl/sdl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/param_package.h" -#include "input_common/main.h" - -namespace InputCommon::Polling { -class DevicePoller; -enum class DeviceType; -} // namespace InputCommon::Polling - -namespace InputCommon::SDL { - -class State { -public: - using Pollers = std::vector>; - - /// Unregisters SDL device factories and shut them down. - virtual ~State() = default; - - virtual Pollers GetPollers(Polling::DeviceType) { - return {}; - } - - virtual std::vector GetInputDevices() { - return {}; - } - - virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) { - return {}; - } - virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { - return {}; - } - virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) { - return {}; - } -}; - -class NullState : public State { -public: -}; - -std::unique_ptr Init(); - -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp deleted file mode 100644 index ecb00d428..000000000 --- a/src/input_common/sdl/sdl_impl.cpp +++ /dev/null @@ -1,1658 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common/logging/log.h" -#include "common/math_util.h" -#include "common/param_package.h" -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" -#include "input_common/sdl/sdl_impl.h" - -namespace InputCommon::SDL { - -namespace { -std::string GetGUID(SDL_Joystick* joystick) { - const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - char guid_str[33]; - SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); - return guid_str; -} - -/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); -} // Anonymous namespace - -static int SDLEventWatcher(void* user_data, SDL_Event* event) { - auto* const sdl_state = static_cast(user_data); - - // Don't handle the event if we are configuring - if (sdl_state->polling) { - sdl_state->event_queue.Push(*event); - } else { - sdl_state->HandleGameControllerEvent(*event); - } - - return 0; -} - -class SDLJoystick { -public: - SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, - SDL_GameController* game_controller) - : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, - sdl_controller{game_controller, &SDL_GameControllerClose} { - EnableMotion(); - } - - void EnableMotion() { - if (sdl_controller) { - SDL_GameController* controller = sdl_controller.get(); - if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); - has_accel = true; - } - if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); - has_gyro = true; - } - } - } - - void SetButton(int button, bool value) { - std::lock_guard lock{mutex}; - state.buttons.insert_or_assign(button, value); - } - - void PreSetButton(int button) { - if (!state.buttons.contains(button)) { - SetButton(button, false); - } - } - - void SetMotion(SDL_ControllerSensorEvent event) { - constexpr float gravity_constant = 9.80665f; - std::lock_guard lock{mutex}; - u64 time_difference = event.timestamp - last_motion_update; - last_motion_update = event.timestamp; - switch (event.sensor) { - case SDL_SENSOR_ACCEL: { - const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]}; - motion.SetAcceleration(acceleration / gravity_constant); - break; - } - case SDL_SENSOR_GYRO: { - const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]}; - motion.SetGyroscope(gyroscope / (Common::PI * 2)); - break; - } - } - - // Ignore duplicated timestamps - if (time_difference == 0) { - return; - } - - motion.SetGyroThreshold(0.0001f); - motion.UpdateRotation(time_difference * 1000); - motion.UpdateOrientation(time_difference * 1000); - } - - bool GetButton(int button) const { - std::lock_guard lock{mutex}; - return state.buttons.at(button); - } - - bool ToggleButton(int button) { - std::lock_guard lock{mutex}; - - if (!state.toggle_buttons.contains(button) || !state.lock_buttons.contains(button)) { - state.toggle_buttons.insert_or_assign(button, false); - state.lock_buttons.insert_or_assign(button, false); - } - - const bool button_state = state.toggle_buttons.at(button); - const bool button_lock = state.lock_buttons.at(button); - - if (button_lock) { - return button_state; - } - - state.lock_buttons.insert_or_assign(button, true); - - if (button_state) { - state.toggle_buttons.insert_or_assign(button, false); - } else { - state.toggle_buttons.insert_or_assign(button, true); - } - - return !button_state; - } - - bool UnlockButton(int button) { - std::lock_guard lock{mutex}; - if (!state.toggle_buttons.contains(button)) { - return false; - } - state.lock_buttons.insert_or_assign(button, false); - return state.toggle_buttons.at(button); - } - - void SetAxis(int axis, Sint16 value) { - std::lock_guard lock{mutex}; - state.axes.insert_or_assign(axis, value); - } - - void PreSetAxis(int axis) { - if (!state.axes.contains(axis)) { - SetAxis(axis, 0); - } - } - - float GetAxis(int axis, float range, float offset) const { - std::lock_guard lock{mutex}; - const float value = static_cast(state.axes.at(axis)) / 32767.0f; - const float offset_scale = (value + offset) > 0.0f ? 1.0f + offset : 1.0f - offset; - return (value + offset) / range / offset_scale; - } - - bool RumblePlay(u16 amp_low, u16 amp_high) { - constexpr u32 rumble_max_duration_ms = 1000; - - if (sdl_controller) { - return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, - rumble_max_duration_ms) != -1; - } else if (sdl_joystick) { - return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, - rumble_max_duration_ms) != -1; - } - - return false; - } - - std::tuple GetAnalog(int axis_x, int axis_y, float range, float offset_x, - float offset_y) const { - float x = GetAxis(axis_x, range, offset_x); - float y = GetAxis(axis_y, range, offset_y); - y = -y; // 3DS uses an y-axis inverse from SDL - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return std::make_tuple(x, y); - } - - bool HasGyro() const { - return has_gyro; - } - - bool HasAccel() const { - return has_accel; - } - - const MotionInput& GetMotion() const { - return motion; - } - - void SetHat(int hat, Uint8 direction) { - std::lock_guard lock{mutex}; - state.hats.insert_or_assign(hat, direction); - } - - bool GetHatDirection(int hat, Uint8 direction) const { - std::lock_guard lock{mutex}; - return (state.hats.at(hat) & direction) != 0; - } - /** - * The guid of the joystick - */ - const std::string& GetGUID() const { - return guid; - } - - /** - * The number of joystick from the same type that were connected before this joystick - */ - int GetPort() const { - return port; - } - - SDL_Joystick* GetSDLJoystick() const { - return sdl_joystick.get(); - } - - SDL_GameController* GetSDLGameController() const { - return sdl_controller.get(); - } - - void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) { - sdl_joystick.reset(joystick); - sdl_controller.reset(controller); - } - - bool IsJoyconLeft() const { - const std::string controller_name = GetControllerName(); - if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { - return true; - } - if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { - return true; - } - return false; - } - - bool IsJoyconRight() const { - const std::string controller_name = GetControllerName(); - if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { - return true; - } - if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { - return true; - } - return false; - } - - std::string GetControllerName() const { - if (sdl_controller) { - switch (SDL_GameControllerGetType(sdl_controller.get())) { - case SDL_CONTROLLER_TYPE_XBOX360: - return "XBox 360 Controller"; - case SDL_CONTROLLER_TYPE_XBOXONE: - return "XBox One Controller"; - default: - break; - } - const auto name = SDL_GameControllerName(sdl_controller.get()); - if (name) { - return name; - } - } - - if (sdl_joystick) { - const auto name = SDL_JoystickName(sdl_joystick.get()); - if (name) { - return name; - } - } - - return "Unknown"; - } - -private: - struct State { - std::unordered_map buttons; - std::unordered_map toggle_buttons{}; - std::unordered_map lock_buttons{}; - std::unordered_map axes; - std::unordered_map hats; - } state; - std::string guid; - int port; - std::unique_ptr sdl_joystick; - std::unique_ptr sdl_controller; - mutable std::mutex mutex; - - // Motion is initialized with the PID values - MotionInput motion{0.3f, 0.005f, 0.0f}; - u64 last_motion_update{}; - bool has_gyro{false}; - bool has_accel{false}; -}; - -std::shared_ptr SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { - std::lock_guard lock{joystick_map_mutex}; - const auto it = joystick_map.find(guid); - - if (it != joystick_map.end()) { - while (it->second.size() <= static_cast(port)) { - auto joystick = std::make_shared(guid, static_cast(it->second.size()), - nullptr, nullptr); - it->second.emplace_back(std::move(joystick)); - } - - return it->second[static_cast(port)]; - } - - auto joystick = std::make_shared(guid, 0, nullptr, nullptr); - - return joystick_map[guid].emplace_back(std::move(joystick)); -} - -std::shared_ptr SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { - auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - const auto map_it = joystick_map.find(guid); - - if (map_it == joystick_map.end()) { - return nullptr; - } - - const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (vec_it == map_it->second.end()) { - return nullptr; - } - - return *vec_it; -} - -void SDLState::InitJoystick(int joystick_index) { - SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); - SDL_GameController* sdl_gamecontroller = nullptr; - - if (SDL_IsGameController(joystick_index)) { - sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); - } - - if (!sdl_joystick) { - LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); - return; - } - - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - if (joystick_map.find(guid) == joystick_map.end()) { - auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); - joystick_map[guid].emplace_back(std::move(joystick)); - return; - } - - auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = - std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); - - if (joystick_it != joystick_guid_list.end()) { - (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); - return; - } - - const int port = static_cast(joystick_guid_list.size()); - auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); - joystick_guid_list.emplace_back(std::move(joystick)); -} - -void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - // This call to guid is safe since the joystick is guaranteed to be in the map - const auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (joystick_it != joystick_guid_list.end()) { - (*joystick_it)->SetSDLJoystick(nullptr, nullptr); - } -} - -void SDLState::HandleGameControllerEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_JOYBUTTONUP: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, false); - } - break; - } - case SDL_JOYBUTTONDOWN: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, true); - } - break; - } - case SDL_JOYHATMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { - joystick->SetHat(event.jhat.hat, event.jhat.value); - } - break; - } - case SDL_JOYAXISMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { - joystick->SetAxis(event.jaxis.axis, event.jaxis.value); - } - break; - } - case SDL_CONTROLLERSENSORUPDATE: { - if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { - joystick->SetMotion(event.csensor); - } - break; - } - case SDL_JOYDEVICEREMOVED: - LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); - CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); - break; - case SDL_JOYDEVICEADDED: - LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); - InitJoystick(event.jdevice.which); - break; - } -} - -void SDLState::CloseJoysticks() { - std::lock_guard lock{joystick_map_mutex}; - joystick_map.clear(); -} - -class SDLButton final : public Input::ButtonDevice { -public: - explicit SDLButton(std::shared_ptr joystick_, int button_, bool toggle_) - : joystick(std::move(joystick_)), button(button_), toggle(toggle_) {} - - bool GetStatus() const override { - const bool button_state = joystick->GetButton(button); - if (!toggle) { - return button_state; - } - - if (button_state) { - return joystick->ToggleButton(button); - } - return joystick->UnlockButton(button); - } - -private: - std::shared_ptr joystick; - int button; - bool toggle; -}; - -class SDLDirectionButton final : public Input::ButtonDevice { -public: - explicit SDLDirectionButton(std::shared_ptr joystick_, int hat_, Uint8 direction_) - : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} - - bool GetStatus() const override { - return joystick->GetHatDirection(hat, direction); - } - -private: - std::shared_ptr joystick; - int hat; - Uint8 direction; -}; - -class SDLAxisButton final : public Input::ButtonDevice { -public: - explicit SDLAxisButton(std::shared_ptr joystick_, int axis_, float threshold_, - bool trigger_if_greater_) - : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), - trigger_if_greater(trigger_if_greater_) {} - - bool GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); - if (trigger_if_greater) { - return axis_value > threshold; - } - return axis_value < threshold; - } - -private: - std::shared_ptr joystick; - int axis; - float threshold; - bool trigger_if_greater; -}; - -class SDLAnalog final : public Input::AnalogDevice { -public: - explicit SDLAnalog(std::shared_ptr joystick_, int axis_x_, int axis_y_, - bool invert_x_, bool invert_y_, float deadzone_, float range_, - float offset_x_, float offset_y_) - : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), - invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_), - offset_y(offset_y_) {} - - std::tuple GetStatus() const override { - auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y); - const float r = std::sqrt((x * x) + (y * y)); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - - if (r > deadzone) { - return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)); - } - return {}; - } - - std::tuple GetRawStatus() const override { - const float x = joystick->GetAxis(axis_x, range, offset_x); - const float y = joystick->GetAxis(axis_y, range, offset_y); - return {x, -y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { - const auto [x, y] = GetStatus(); - const float directional_deadzone = 0.5f; - switch (direction) { - case Input::AnalogDirection::RIGHT: - return x > directional_deadzone; - case Input::AnalogDirection::LEFT: - return x < -directional_deadzone; - case Input::AnalogDirection::UP: - return y > directional_deadzone; - case Input::AnalogDirection::DOWN: - return y < -directional_deadzone; - } - return false; - } - -private: - std::shared_ptr joystick; - const int axis_x; - const int axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const float offset_x; - const float offset_y; -}; - -class SDLVibration final : public Input::VibrationDevice { -public: - explicit SDLVibration(std::shared_ptr joystick_) - : joystick(std::move(joystick_)) {} - - u8 GetStatus() const override { - joystick->RumblePlay(1, 1); - return joystick->RumblePlay(0, 0); - } - - bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, - [[maybe_unused]] f32 freq_high) const override { - const auto process_amplitude = [](f32 amplitude) { - return static_cast((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF); - }; - - const auto processed_amp_low = process_amplitude(amp_low); - const auto processed_amp_high = process_amplitude(amp_high); - - return joystick->RumblePlay(processed_amp_low, processed_amp_high); - } - -private: - std::shared_ptr joystick; -}; - -class SDLMotion final : public Input::MotionDevice { -public: - explicit SDLMotion(std::shared_ptr joystick_) : joystick(std::move(joystick_)) {} - - Input::MotionStatus GetStatus() const override { - return joystick->GetMotion().GetMotion(); - } - -private: - std::shared_ptr joystick; -}; - -class SDLDirectionMotion final : public Input::MotionDevice { -public: - explicit SDLDirectionMotion(std::shared_ptr joystick_, int hat_, Uint8 direction_) - : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} - - Input::MotionStatus GetStatus() const override { - if (joystick->GetHatDirection(hat, direction)) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int hat; - Uint8 direction; -}; - -class SDLAxisMotion final : public Input::MotionDevice { -public: - explicit SDLAxisMotion(std::shared_ptr joystick_, int axis_, float threshold_, - bool trigger_if_greater_) - : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), - trigger_if_greater(trigger_if_greater_) {} - - Input::MotionStatus GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); - bool trigger = axis_value < threshold; - if (trigger_if_greater) { - trigger = axis_value > threshold; - } - - if (trigger) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int axis; - float threshold; - bool trigger_if_greater; -}; - -class SDLButtonMotion final : public Input::MotionDevice { -public: - explicit SDLButtonMotion(std::shared_ptr joystick_, int button_) - : joystick(std::move(joystick_)), button(button_) {} - - Input::MotionStatus GetStatus() const override { - if (joystick->GetButton(button)) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int button; -}; - -/// A button device factory that creates button devices from SDL joystick -class SDLButtonFactory final : public Input::Factory { -public: - explicit SDLButtonFactory(SDLState& state_) : state(state_) {} - - /** - * Creates a button device from a joystick button - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type to bind - * - "button"(optional): the index of the button to bind - * - "hat"(optional): the index of the hat to bind as direction buttons - * - "axis"(optional): the index of the axis to bind - * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", - * "down", "left" or "right" - * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is - * triggered if the axis value crosses - * - "direction"(only used for axis): "+" means the button is triggered when the axis - * value is greater than the threshold; "-" means the button is triggered when the axis - * value is smaller than the threshold - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - const auto toggle = params.Get("toggle", false); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - if (params.Has("hat")) { - const int hat = params.Get("hat", 0); - const std::string direction_name = params.Get("direction", ""); - Uint8 direction; - if (direction_name == "up") { - direction = SDL_HAT_UP; - } else if (direction_name == "down") { - direction = SDL_HAT_DOWN; - } else if (direction_name == "left") { - direction = SDL_HAT_LEFT; - } else if (direction_name == "right") { - direction = SDL_HAT_RIGHT; - } else { - direction = 0; - } - // This is necessary so accessing GetHat with hat won't crash - joystick->SetHat(hat, SDL_HAT_CENTERED); - return std::make_unique(joystick, hat, direction); - } - - if (params.Has("axis")) { - const int axis = params.Get("axis", 0); - // Convert range from (0.0, 1.0) to (-1.0, 1.0) - const float threshold = (params.Get("threshold", 0.5f) - 0.5f) * 2.0f; - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - // This is necessary so accessing GetAxis with axis won't crash - joystick->PreSetAxis(axis); - return std::make_unique(joystick, axis, threshold, trigger_if_greater); - } - - const int button = params.Get("button", 0); - // This is necessary so accessing GetButton with button won't crash - joystick->PreSetButton(button); - return std::make_unique(joystick, button, toggle); - } - -private: - SDLState& state; -}; - -/// An analog device factory that creates analog devices from SDL joystick -class SDLAnalogFactory final : public Input::Factory { -public: - explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} - /** - * Creates an analog device from joystick axes - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - const int axis_x = params.Get("axis_x", 0); - const int axis_y = params.Get("axis_y", 1); - const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - const float offset_x = std::clamp(params.Get("offset_x", 0.0f), -0.99f, 0.99f); - const float offset_y = std::clamp(params.Get("offset_y", 0.0f), -0.99f, 0.99f); - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - // This is necessary so accessing GetAxis with axis_x and axis_y won't crash - joystick->PreSetAxis(axis_x); - joystick->PreSetAxis(axis_y); - return std::make_unique(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, - range, offset_x, offset_y); - } - -private: - SDLState& state; -}; - -/// An vibration device factory that creates vibration devices from SDL joystick -class SDLVibrationFactory final : public Input::Factory { -public: - explicit SDLVibrationFactory(SDLState& state_) : state(state_) {} - /** - * Creates a vibration device from a joystick - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - return std::make_unique(state.GetSDLJoystickByGUID(guid, port)); - } - -private: - SDLState& state; -}; - -/// A motion device factory that creates motion devices from SDL joystick -class SDLMotionFactory final : public Input::Factory { -public: - explicit SDLMotionFactory(SDLState& state_) : state(state_) {} - /** - * Creates motion device from joystick axes - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - if (params.Has("motion")) { - return std::make_unique(joystick); - } - - if (params.Has("hat")) { - const int hat = params.Get("hat", 0); - const std::string direction_name = params.Get("direction", ""); - Uint8 direction; - if (direction_name == "up") { - direction = SDL_HAT_UP; - } else if (direction_name == "down") { - direction = SDL_HAT_DOWN; - } else if (direction_name == "left") { - direction = SDL_HAT_LEFT; - } else if (direction_name == "right") { - direction = SDL_HAT_RIGHT; - } else { - direction = 0; - } - // This is necessary so accessing GetHat with hat won't crash - joystick->SetHat(hat, SDL_HAT_CENTERED); - return std::make_unique(joystick, hat, direction); - } - - if (params.Has("axis")) { - const int axis = params.Get("axis", 0); - const float threshold = params.Get("threshold", 0.5f); - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - // This is necessary so accessing GetAxis with axis won't crash - joystick->PreSetAxis(axis); - return std::make_unique(joystick, axis, threshold, trigger_if_greater); - } - - const int button = params.Get("button", 0); - // This is necessary so accessing GetButton with button won't crash - joystick->PreSetButton(button); - return std::make_unique(joystick, button); - } - -private: - SDLState& state; -}; - -SDLState::SDLState() { - using namespace Input; - button_factory = std::make_shared(*this); - analog_factory = std::make_shared(*this); - vibration_factory = std::make_shared(*this); - motion_factory = std::make_shared(*this); - RegisterFactory("sdl", button_factory); - RegisterFactory("sdl", analog_factory); - RegisterFactory("sdl", vibration_factory); - RegisterFactory("sdl", motion_factory); - - if (!Settings::values.enable_raw_input) { - // Disable raw input. When enabled this setting causes SDL to die when a web applet opens - SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); - } - - // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); - - // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a - // GameController and not a generic one - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - - // Turn off Pro controller home led - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); - - // If the frontend is going to manage the event loop, then we don't start one here - start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; - if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { - LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); - return; - } - has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0; - if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { - LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); - } - - SDL_AddEventWatch(&SDLEventWatcher, this); - - initialized = true; - if (start_thread) { - poll_thread = std::thread([this] { - using namespace std::chrono_literals; - while (initialized) { - SDL_PumpEvents(); - std::this_thread::sleep_for(1ms); - } - }); - } - // Because the events for joystick connection happens before we have our event watcher added, we - // can just open all the joysticks right here - for (int i = 0; i < SDL_NumJoysticks(); ++i) { - InitJoystick(i); - } -} - -SDLState::~SDLState() { - using namespace Input; - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - - CloseJoysticks(); - SDL_DelEventWatch(&SDLEventWatcher, this); - - initialized = false; - if (start_thread) { - poll_thread.join(); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } -} - -std::vector SDLState::GetInputDevices() { - std::scoped_lock lock(joystick_map_mutex); - std::vector devices; - std::unordered_map> joycon_pairs; - for (const auto& [key, value] : joystick_map) { - for (const auto& joystick : value) { - if (!joystick->GetSDLJoystick()) { - continue; - } - std::string name = - fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); - devices.emplace_back(Common::ParamPackage{ - {"class", "sdl"}, - {"display", std::move(name)}, - {"guid", joystick->GetGUID()}, - {"port", std::to_string(joystick->GetPort())}, - }); - if (joystick->IsJoyconLeft()) { - joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); - } - } - } - - // Add dual controllers - for (const auto& [key, value] : joystick_map) { - for (const auto& joystick : value) { - if (joystick->IsJoyconRight()) { - if (!joycon_pairs.contains(joystick->GetPort())) { - continue; - } - const auto joystick2 = joycon_pairs.at(joystick->GetPort()); - - std::string name = - fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); - devices.emplace_back(Common::ParamPackage{ - {"class", "sdl"}, - {"display", std::move(name)}, - {"guid", joystick->GetGUID()}, - {"guid2", joystick2->GetGUID()}, - {"port", std::to_string(joystick->GetPort())}, - }); - } - } - } - return devices; -} - -namespace { -Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, - float value = 0.1f) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("axis", axis); - params.Set("threshold", "0.5"); - if (value > 0) { - params.Set("direction", "+"); - } else { - params.Set("direction", "-"); - } - return params; -} - -Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("button", button); - params.Set("toggle", false); - return params; -} - -Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) { - Common::ParamPackage params({{"engine", "sdl"}}); - - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("hat", hat); - switch (value) { - case SDL_HAT_UP: - params.Set("direction", "up"); - break; - case SDL_HAT_DOWN: - params.Set("direction", "down"); - break; - case SDL_HAT_LEFT: - params.Set("direction", "left"); - break; - case SDL_HAT_RIGHT: - params.Set("direction", "right"); - break; - default: - return {}; - } - return params; -} - -Common::ParamPackage BuildMotionParam(int port, std::string guid) { - Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - return params; -} - -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jaxis.axis), - event.jaxis.value); - } - break; - } - case SDL_JOYBUTTONUP: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) { - return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jbutton.button)); - } - break; - } - case SDL_JOYHATMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) { - return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jhat.hat), - static_cast(event.jhat.value)); - } - break; - } - } - return {}; -} - -Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jaxis.axis), - event.jaxis.value); - } - break; - } - case SDL_JOYBUTTONUP: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) { - return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jbutton.button)); - } - break; - } - case SDL_JOYHATMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) { - return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jhat.hat), - static_cast(event.jhat.value)); - } - break; - } - case SDL_CONTROLLERSENSORUPDATE: { - bool is_motion_shaking = false; - constexpr float gyro_threshold = 5.0f; - constexpr float accel_threshold = 11.0f; - if (event.csensor.sensor == SDL_SENSOR_ACCEL) { - const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], - -event.csensor.data[1]}; - if (acceleration.Length() > accel_threshold) { - is_motion_shaking = true; - } - } - - if (event.csensor.sensor == SDL_SENSOR_GYRO) { - const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], - event.csensor.data[1]}; - if (gyroscope.Length() > gyro_threshold) { - is_motion_shaking = true; - } - } - - if (!is_motion_shaking) { - break; - } - - if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { - return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); - } - break; - } - } - return {}; -} - -Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, - const SDL_GameControllerButtonBind& binding) { - switch (binding.bindType) { - case SDL_CONTROLLER_BINDTYPE_NONE: - break; - case SDL_CONTROLLER_BINDTYPE_AXIS: - return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); - case SDL_CONTROLLER_BINDTYPE_BUTTON: - return BuildButtonParamPackageForButton(port, guid, binding.value.button); - case SDL_CONTROLLER_BINDTYPE_HAT: - return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat, - binding.value.hat.hat_mask); - } - return {}; -} - -Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, - int axis_y, float offset_x, float offset_y) { - Common::ParamPackage params; - params.Set("engine", "sdl"); - params.Set("port", port); - params.Set("guid", guid); - params.Set("axis_x", axis_x); - params.Set("axis_y", axis_y); - params.Set("offset_x", offset_x); - params.Set("offset_y", offset_y); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - return params; -} -} // Anonymous namespace - -ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. - // We will add those afterwards - // This list also excludes Screenshot since theres not really a mapping for that - ButtonBindings switch_to_sdl_button; - - if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { - switch_to_sdl_button = GetNintendoButtonBinding(joystick); - } else { - switch_to_sdl_button = GetDefaultButtonBinding(); - } - - // Add the missing bindings for ZL/ZR - static constexpr ZButtonBindings switch_to_sdl_axis{{ - {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, - {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, - }}; - - // Parameters contain two joysticks return dual - if (params.Has("guid2")) { - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - - if (joystick2->GetSDLGameController() != nullptr) { - return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, - switch_to_sdl_axis); - } - } - - return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); -} - -ButtonBindings SDLState::GetDefaultButtonBinding() const { - return { - std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, - {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, - {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, - {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, - {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, - {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, - {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {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, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, - }; -} - -ButtonBindings SDLState::GetNintendoButtonBinding( - const std::shared_ptr& joystick) const { - // Default SL/SR mapping for pro controllers - auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; - auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - - if (joystick->IsJoyconLeft()) { - sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; - sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; - } - if (joystick->IsJoyconRight()) { - sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; - sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; - } - - return { - std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, - {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, - {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, - {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, - {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, - {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, - {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {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::Home, SDL_CONTROLLER_BUTTON_GUIDE}, - }; -} - -ButtonMapping SDLState::GetSingleControllerMapping( - const std::shared_ptr& joystick, const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const { - ButtonMapping mapping; - mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); - auto* controller = joystick->GetSDLGameController(); - - for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { - const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { - const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - - return mapping; -} - -ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr& joystick, - const std::shared_ptr& joystick2, - const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const { - ButtonMapping mapping; - mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); - auto* controller = joystick->GetSDLGameController(); - auto* controller2 = joystick2->GetSDLGameController(); - - for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { - if (IsButtonOnLeftSide(switch_button)) { - const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); - continue; - } - const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { - if (IsButtonOnLeftSide(switch_button)) { - const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); - continue; - } - const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - - return mapping; -} - -bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { - switch (button) { - case Settings::NativeButton::DDown: - case Settings::NativeButton::DLeft: - case Settings::NativeButton::DRight: - case Settings::NativeButton::DUp: - case Settings::NativeButton::L: - case Settings::NativeButton::LStick: - case Settings::NativeButton::Minus: - case Settings::NativeButton::Screenshot: - case Settings::NativeButton::ZL: - return true; - default: - return false; - } -} - -AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - AnalogMapping mapping = {}; - const auto& binding_left_x = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); - const auto& binding_left_y = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); - if (params.Has("guid2")) { - joystick2->PreSetAxis(binding_left_x.value.axis); - joystick2->PreSetAxis(binding_left_y.value.axis); - const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0); - const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0); - mapping.insert_or_assign( - Settings::NativeAnalog::LStick, - BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis, - left_offset_x, left_offset_y)); - } else { - joystick->PreSetAxis(binding_left_x.value.axis); - joystick->PreSetAxis(binding_left_y.value.axis); - const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0); - const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0); - mapping.insert_or_assign( - Settings::NativeAnalog::LStick, - BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis, - left_offset_x, left_offset_y)); - } - const auto& binding_right_x = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); - const auto& binding_right_y = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); - joystick->PreSetAxis(binding_right_x.value.axis); - joystick->PreSetAxis(binding_right_y.value.axis); - const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0); - const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0); - mapping.insert_or_assign(Settings::NativeAnalog::RStick, - BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_right_x.value.axis, - binding_right_y.value.axis, right_offset_x, - right_offset_y)); - return mapping; -} - -MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - MotionMapping mapping = {}; - joystick->EnableMotion(); - - if (joystick->HasGyro() || joystick->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionRight, - BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); - } - if (params.Has("guid2")) { - joystick2->EnableMotion(); - if (joystick2->HasGyro() || joystick2->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, - BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); - } - } else { - if (joystick->HasGyro() || joystick->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, - BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); - } - } - - return mapping; -} -namespace Polling { -class SDLPoller : public InputCommon::Polling::DevicePoller { -public: - explicit SDLPoller(SDLState& state_) : state(state_) {} - - void Start([[maybe_unused]] const std::string& device_id) override { - state.event_queue.Clear(); - state.polling = true; - } - - void Stop() override { - state.polling = false; - } - -protected: - SDLState& state; -}; - -class SDLButtonPoller final : public SDLPoller { -public: - explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - const auto package = FromEvent(event); - if (package) { - return *package; - } - } - return {}; - } - [[nodiscard]] std::optional FromEvent(SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: - if (!axis_memory.count(event.jaxis.which) || - !axis_memory[event.jaxis.which].count(event.jaxis.axis)) { - axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value; - axis_event_count[event.jaxis.which][event.jaxis.axis] = 1; - break; - } else { - axis_event_count[event.jaxis.which][event.jaxis.axis]++; - // The joystick and axis exist in our map if we take this branch, so no checks - // needed - if (std::abs( - (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) / - 32767.0) < 0.5) { - break; - } else { - if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 && - IsAxisAtPole(event.jaxis.value) && - IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) { - // If we have exactly two events and both are near a pole, this is - // likely a digital input masquerading as an analog axis; Instead of - // trying to look at the direction the axis travelled, assume the first - // event was press and the second was release; This should handle most - // digital axes while deferring to the direction of travel for analog - // axes - event.jaxis.value = static_cast( - std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis])); - } else { - // There are more than two events, so this is likely a true analog axis, - // check the direction it travelled - event.jaxis.value = static_cast(std::copysign( - 32767, - event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis])); - } - axis_memory.clear(); - axis_event_count.clear(); - } - } - [[fallthrough]]; - case SDL_JOYBUTTONUP: - case SDL_JOYHATMOTION: - return {SDLEventToButtonParamPackage(state, event)}; - } - return std::nullopt; - } - -private: - // Determine whether an axis value is close to an extreme or center - // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per - // axis, which is why the center must be considered a pole - bool IsAxisAtPole(int16_t value) const { - return std::abs(value) >= 32767 || std::abs(value) < 327; - } - std::unordered_map> axis_memory; - std::unordered_map> axis_event_count; -}; - -class SDLMotionPoller final : public SDLPoller { -public: - explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {} - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - const auto package = FromEvent(event); - if (package) { - return *package; - } - } - return {}; - } - [[nodiscard]] std::optional FromEvent(const SDL_Event& event) const { - switch (event.type) { - case SDL_JOYAXISMOTION: - if (std::abs(event.jaxis.value / 32767.0) < 0.5) { - break; - } - [[fallthrough]]; - case SDL_JOYBUTTONUP: - case SDL_JOYHATMOTION: - case SDL_CONTROLLERSENSORUPDATE: - return {SDLEventToMotionParamPackage(state, event)}; - } - return std::nullopt; - } -}; - -/** - * Attempts to match the press to a controller joy axis (left/right stick) and if a match - * isn't found, checks if the event matches anything from SDLButtonPoller and uses that - * instead - */ -class SDLAnalogPreferredPoller final : public SDLPoller { -public: - explicit SDLAnalogPreferredPoller(SDLState& state_) - : SDLPoller(state_), button_poller(state_) {} - - void Start(const std::string& device_id) override { - SDLPoller::Start(device_id); - // Reset stored axes - first_axis = -1; - } - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - if (event.type != SDL_JOYAXISMOTION) { - // Check for a button press - auto button_press = button_poller.FromEvent(event); - if (button_press) { - return *button_press; - } - continue; - } - const auto axis = event.jaxis.axis; - - // Filter out axis events that are below a threshold - if (std::abs(event.jaxis.value / 32767.0) < 0.5) { - continue; - } - - // Filter out axis events that are the same - if (first_axis == axis) { - continue; - } - - // In order to return a complete analog param, we need inputs for both axes. - // If the first axis isn't set we set the value then wait till next event - if (first_axis == -1) { - first_axis = axis; - continue; - } - - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - // Set offset to zero since the joystick is not on center - auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - first_axis, axis, 0, 0); - first_axis = -1; - return params; - } - } - return {}; - } - -private: - int first_axis = -1; - SDLButtonPoller button_poller; -}; -} // namespace Polling - -SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) { - Pollers pollers; - - switch (type) { - case InputCommon::Polling::DeviceType::AnalogPreferred: - pollers.emplace_back(std::make_unique(*this)); - break; - case InputCommon::Polling::DeviceType::Button: - pollers.emplace_back(std::make_unique(*this)); - break; - case InputCommon::Polling::DeviceType::Motion: - pollers.emplace_back(std::make_unique(*this)); - break; - } - - return pollers; -} - -} // namespace InputCommon::SDL From 6d108f0dcb5b388c3586f90426fc2c832a8bffc0 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:39:58 -0500 Subject: [PATCH 061/291] input_common: Remove obsolete files --- src/input_common/CMakeLists.txt | 4 - src/input_common/motion_from_button.cpp | 34 --- src/input_common/motion_from_button.h | 25 -- src/input_common/motion_input.cpp | 307 ------------------------ src/input_common/motion_input.h | 74 ------ 5 files changed, 444 deletions(-) delete mode 100644 src/input_common/motion_from_button.cpp delete mode 100644 src/input_common/motion_from_button.h delete mode 100644 src/input_common/motion_input.cpp delete mode 100644 src/input_common/motion_input.h diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 8cdcd315b..d4fa69a77 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -27,10 +27,6 @@ add_library(input_common STATIC input_poller.h main.cpp main.h - motion_from_button.cpp - motion_from_button.h - motion_input.cpp - motion_input.h ) if (MSVC) diff --git a/src/input_common/motion_from_button.cpp b/src/input_common/motion_from_button.cpp deleted file mode 100644 index 29045a673..000000000 --- a/src/input_common/motion_from_button.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "input_common/motion_from_button.h" -#include "input_common/motion_input.h" - -namespace InputCommon { - -class MotionKey final : public Input::MotionDevice { -public: - using Button = std::unique_ptr; - - explicit MotionKey(Button key_) : key(std::move(key_)) {} - - Input::MotionStatus GetStatus() const override { - - if (key->GetStatus()) { - return motion.GetRandomMotion(2, 6); - } - return motion.GetRandomMotion(0, 0); - } - -private: - Button key; - InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; -}; - -std::unique_ptr MotionFromButton::Create(const Common::ParamPackage& params) { - auto key = Input::CreateDevice(params.Serialize()); - return std::make_unique(std::move(key)); -} - -} // namespace InputCommon diff --git a/src/input_common/motion_from_button.h b/src/input_common/motion_from_button.h deleted file mode 100644 index a959046fb..000000000 --- a/src/input_common/motion_from_button.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/frontend/input.h" - -namespace InputCommon { - -/** - * An motion device factory that takes a keyboard button and uses it as a random - * motion device. - */ -class MotionFromButton final : public Input::Factory { -public: - /** - * Creates an motion device from button devices - * @param params contains parameters for creating the device: - * - "key": a serialized ParamPackage for creating a button device - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; -}; - -} // namespace InputCommon diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp deleted file mode 100644 index 1c9d561c0..000000000 --- a/src/input_common/motion_input.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included - -#include -#include "common/math_util.h" -#include "input_common/motion_input.h" - -namespace InputCommon { - -MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) : kp(new_kp), ki(new_ki), kd(new_kd) {} - -void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { - accel = acceleration; -} - -void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { - gyro = gyroscope - gyro_drift; - - // Auto adjust drift to minimize drift - if (!IsMoving(0.1f)) { - gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f); - } - - if (gyro.Length2() < gyro_threshold) { - gyro = {}; - } else { - only_accelerometer = false; - } -} - -void MotionInput::SetQuaternion(const Common::Quaternion& quaternion) { - quat = quaternion; -} - -void MotionInput::SetGyroDrift(const Common::Vec3f& drift) { - gyro_drift = drift; -} - -void MotionInput::SetGyroThreshold(f32 threshold) { - gyro_threshold = threshold; -} - -void MotionInput::EnableReset(bool reset) { - reset_enabled = reset; -} - -void MotionInput::ResetRotations() { - rotations = {}; -} - -bool MotionInput::IsMoving(f32 sensitivity) const { - return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f; -} - -bool MotionInput::IsCalibrated(f32 sensitivity) const { - return real_error.Length() < sensitivity; -} - -void MotionInput::UpdateRotation(u64 elapsed_time) { - const auto sample_period = static_cast(elapsed_time) / 1000000.0f; - if (sample_period > 0.1f) { - return; - } - rotations += gyro * sample_period; -} - -void MotionInput::UpdateOrientation(u64 elapsed_time) { - if (!IsCalibrated(0.1f)) { - ResetOrientation(); - } - // Short name local variable for readability - f32 q1 = quat.w; - f32 q2 = quat.xyz[0]; - f32 q3 = quat.xyz[1]; - f32 q4 = quat.xyz[2]; - const auto sample_period = static_cast(elapsed_time) / 1000000.0f; - - // Ignore invalid elapsed time - if (sample_period > 0.1f) { - return; - } - - const auto normal_accel = accel.Normalized(); - auto rad_gyro = gyro * Common::PI * 2; - const f32 swap = rad_gyro.x; - rad_gyro.x = rad_gyro.y; - rad_gyro.y = -swap; - rad_gyro.z = -rad_gyro.z; - - // Clear gyro values if there is no gyro present - if (only_accelerometer) { - rad_gyro.x = 0; - rad_gyro.y = 0; - rad_gyro.z = 0; - } - - // Ignore drift correction if acceleration is not reliable - if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) { - const f32 ax = -normal_accel.x; - const f32 ay = normal_accel.y; - const f32 az = -normal_accel.z; - - // Estimated direction of gravity - const f32 vx = 2.0f * (q2 * q4 - q1 * q3); - const f32 vy = 2.0f * (q1 * q2 + q3 * q4); - const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; - - // Error is cross product between estimated direction and measured direction of gravity - const Common::Vec3f new_real_error = { - az * vx - ax * vz, - ay * vz - az * vy, - ax * vy - ay * vx, - }; - - derivative_error = new_real_error - real_error; - real_error = new_real_error; - - // Prevent integral windup - if (ki != 0.0f && !IsCalibrated(0.05f)) { - integral_error += real_error; - } else { - integral_error = {}; - } - - // Apply feedback terms - if (!only_accelerometer) { - rad_gyro += kp * real_error; - rad_gyro += ki * integral_error; - rad_gyro += kd * derivative_error; - } else { - // Give more weight to accelerometer values to compensate for the lack of gyro - rad_gyro += 35.0f * kp * real_error; - rad_gyro += 10.0f * ki * integral_error; - rad_gyro += 10.0f * kd * derivative_error; - - // Emulate gyro values for games that need them - gyro.x = -rad_gyro.y; - gyro.y = rad_gyro.x; - gyro.z = -rad_gyro.z; - UpdateRotation(elapsed_time); - } - } - - const f32 gx = rad_gyro.y; - const f32 gy = rad_gyro.x; - const f32 gz = rad_gyro.z; - - // Integrate rate of change of quaternion - const f32 pa = q2; - const f32 pb = q3; - const f32 pc = q4; - q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period); - q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period); - q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period); - q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period); - - quat.w = q1; - quat.xyz[0] = q2; - quat.xyz[1] = q3; - quat.xyz[2] = q4; - quat = quat.Normalized(); -} - -std::array MotionInput::GetOrientation() const { - const Common::Quaternion quad{ - .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w}, - .w = -quat.xyz[2], - }; - const std::array matrix4x4 = quad.ToMatrix(); - - return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]), - Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]), - Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])}; -} - -Common::Vec3f MotionInput::GetAcceleration() const { - return accel; -} - -Common::Vec3f MotionInput::GetGyroscope() const { - return gyro; -} - -Common::Quaternion MotionInput::GetQuaternion() const { - return quat; -} - -Common::Vec3f MotionInput::GetRotations() const { - return rotations; -} - -Input::MotionStatus MotionInput::GetMotion() const { - const Common::Vec3f gyroscope = GetGyroscope(); - const Common::Vec3f accelerometer = GetAcceleration(); - const Common::Vec3f rotation = GetRotations(); - const std::array orientation = GetOrientation(); - const Common::Quaternion quaternion = GetQuaternion(); - return {accelerometer, gyroscope, rotation, orientation, quaternion}; -} - -Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const { - std::random_device device; - std::mt19937 gen(device()); - std::uniform_int_distribution distribution(-1000, 1000); - const Common::Vec3f gyroscope{ - static_cast(distribution(gen)) * 0.001f, - static_cast(distribution(gen)) * 0.001f, - static_cast(distribution(gen)) * 0.001f, - }; - const Common::Vec3f accelerometer{ - static_cast(distribution(gen)) * 0.001f, - static_cast(distribution(gen)) * 0.001f, - static_cast(distribution(gen)) * 0.001f, - }; - constexpr Common::Vec3f rotation; - constexpr std::array orientation{ - Common::Vec3f{1.0f, 0.0f, 0.0f}, - Common::Vec3f{0.0f, 1.0f, 0.0f}, - Common::Vec3f{0.0f, 0.0f, 1.0f}, - }; - constexpr Common::Quaternion quaternion{ - {0.0f, 0.0f, 0.0f}, - 1.0f, - }; - return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation, - quaternion}; -} - -void MotionInput::ResetOrientation() { - if (!reset_enabled || only_accelerometer) { - return; - } - if (!IsMoving(0.5f) && accel.z <= -0.9f) { - ++reset_counter; - if (reset_counter > 900) { - quat.w = 0; - quat.xyz[0] = 0; - quat.xyz[1] = 0; - quat.xyz[2] = -1; - SetOrientationFromAccelerometer(); - integral_error = {}; - reset_counter = 0; - } - } else { - reset_counter = 0; - } -} - -void MotionInput::SetOrientationFromAccelerometer() { - int iterations = 0; - const f32 sample_period = 0.015f; - - const auto normal_accel = accel.Normalized(); - - while (!IsCalibrated(0.01f) && ++iterations < 100) { - // Short name local variable for readability - f32 q1 = quat.w; - f32 q2 = quat.xyz[0]; - f32 q3 = quat.xyz[1]; - f32 q4 = quat.xyz[2]; - - Common::Vec3f rad_gyro; - const f32 ax = -normal_accel.x; - const f32 ay = normal_accel.y; - const f32 az = -normal_accel.z; - - // Estimated direction of gravity - const f32 vx = 2.0f * (q2 * q4 - q1 * q3); - const f32 vy = 2.0f * (q1 * q2 + q3 * q4); - const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; - - // Error is cross product between estimated direction and measured direction of gravity - const Common::Vec3f new_real_error = { - az * vx - ax * vz, - ay * vz - az * vy, - ax * vy - ay * vx, - }; - - derivative_error = new_real_error - real_error; - real_error = new_real_error; - - rad_gyro += 10.0f * kp * real_error; - rad_gyro += 5.0f * ki * integral_error; - rad_gyro += 10.0f * kd * derivative_error; - - const f32 gx = rad_gyro.y; - const f32 gy = rad_gyro.x; - const f32 gz = rad_gyro.z; - - // Integrate rate of change of quaternion - const f32 pa = q2; - const f32 pb = q3; - const f32 pc = q4; - q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period); - q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period); - q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period); - q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period); - - quat.w = q1; - quat.xyz[0] = q2; - quat.xyz[1] = q3; - quat.xyz[2] = q4; - quat = quat.Normalized(); - } -} -} // namespace InputCommon diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h deleted file mode 100644 index efe74cf19..000000000 --- a/src/input_common/motion_input.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included - -#pragma once - -#include "common/common_types.h" -#include "common/quaternion.h" -#include "common/vector_math.h" -#include "core/frontend/input.h" - -namespace InputCommon { - -class MotionInput { -public: - explicit MotionInput(f32 new_kp, f32 new_ki, f32 new_kd); - - MotionInput(const MotionInput&) = default; - MotionInput& operator=(const MotionInput&) = default; - - MotionInput(MotionInput&&) = default; - MotionInput& operator=(MotionInput&&) = default; - - void SetAcceleration(const Common::Vec3f& acceleration); - void SetGyroscope(const Common::Vec3f& gyroscope); - void SetQuaternion(const Common::Quaternion& quaternion); - void SetGyroDrift(const Common::Vec3f& drift); - void SetGyroThreshold(f32 threshold); - - void EnableReset(bool reset); - void ResetRotations(); - - void UpdateRotation(u64 elapsed_time); - void UpdateOrientation(u64 elapsed_time); - - [[nodiscard]] std::array GetOrientation() const; - [[nodiscard]] Common::Vec3f GetAcceleration() const; - [[nodiscard]] Common::Vec3f GetGyroscope() const; - [[nodiscard]] Common::Vec3f GetRotations() const; - [[nodiscard]] Common::Quaternion GetQuaternion() const; - [[nodiscard]] Input::MotionStatus GetMotion() const; - [[nodiscard]] Input::MotionStatus GetRandomMotion(int accel_magnitude, - int gyro_magnitude) const; - - [[nodiscard]] bool IsMoving(f32 sensitivity) const; - [[nodiscard]] bool IsCalibrated(f32 sensitivity) const; - -private: - void ResetOrientation(); - void SetOrientationFromAccelerometer(); - - // PID constants - f32 kp; - f32 ki; - f32 kd; - - // PID errors - Common::Vec3f real_error; - Common::Vec3f integral_error; - Common::Vec3f derivative_error; - - Common::Quaternion quat{{0.0f, 0.0f, -1.0f}, 0.0f}; - Common::Vec3f rotations; - Common::Vec3f accel; - Common::Vec3f gyro; - Common::Vec3f gyro_drift; - - f32 gyro_threshold = 0.0f; - u32 reset_counter = 0; - bool reset_enabled = true; - bool only_accelerometer = true; -}; - -} // namespace InputCommon From 29ae42f3e2c297898d88858861f7d860ce9fc2f3 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:43:13 -0500 Subject: [PATCH 062/291] input_common: Rewrite main and add the new drivers --- src/input_common/main.cpp | 292 ++++++++++++++++++++++++++++++++++++-- src/input_common/main.h | 89 +++++++----- 2 files changed, 331 insertions(+), 50 deletions(-) diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index da501b6cc..46ca6b76c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,54 +4,265 @@ #include #include +#include "common/input.h" #include "common/param_package.h" -#include "common/settings.h" +#include "input_common/drivers/gc_adapter.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/drivers/tas_input.h" +#include "input_common/drivers/touch_screen.h" +#include "input_common/drivers/udp_client.h" +#include "input_common/helpers/stick_from_buttons.h" +#include "input_common/helpers/touch_from_buttons.h" +#include "input_common/input_engine.h" +#include "input_common/input_mapping.h" +#include "input_common/input_poller.h" #include "input_common/main.h" #ifdef HAVE_SDL2 -#include "input_common/sdl/sdl.h" +#include "input_common/drivers/sdl_driver.h" #endif namespace InputCommon { struct InputSubsystem::Impl { void Initialize() { + mapping_factory = std::make_shared(); + MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }}; + + keyboard = std::make_shared("keyboard"); + keyboard->SetMappingCallback(mapping_callback); + keyboard_factory = std::make_shared(keyboard); + Input::RegisterFactory(keyboard->GetEngineName(), keyboard_factory); + + mouse = std::make_shared("mouse"); + mouse->SetMappingCallback(mapping_callback); + mouse_factory = std::make_shared(mouse); + Input::RegisterFactory(mouse->GetEngineName(), mouse_factory); + + touch_screen = std::make_shared("touch"); + touch_screen_factory = std::make_shared(touch_screen); + Input::RegisterFactory(touch_screen->GetEngineName(), + touch_screen_factory); + + gcadapter = std::make_shared("gcpad"); + gcadapter->SetMappingCallback(mapping_callback); + gcadapter_factory = std::make_shared(gcadapter); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_factory); + + udp_client = std::make_shared("cemuhookudp"); + udp_client->SetMappingCallback(mapping_callback); + udp_client_factory = std::make_shared(udp_client); + Input::RegisterFactory(udp_client->GetEngineName(), udp_client_factory); + + tas_input = std::make_shared("tas"); + tas_input->SetMappingCallback(mapping_callback); + tas_input_factory = std::make_shared(tas_input); + Input::RegisterFactory(tas_input->GetEngineName(), tas_input_factory); + +#ifdef HAVE_SDL2 + sdl = std::make_shared("sdl"); + sdl->SetMappingCallback(mapping_callback); + sdl_factory = std::make_shared(sdl); + Input::RegisterFactory(sdl->GetEngineName(), sdl_factory); +#endif + + Input::RegisterFactory("touch_from_button", + std::make_shared()); + Input::RegisterFactory("analog_from_button", + std::make_shared()); } void Shutdown() { + Input::UnregisterFactory(keyboard->GetEngineName()); + keyboard.reset(); + + Input::UnregisterFactory(mouse->GetEngineName()); + mouse.reset(); + + Input::UnregisterFactory(touch_screen->GetEngineName()); + touch_screen.reset(); + + Input::UnregisterFactory(gcadapter->GetEngineName()); + gcadapter.reset(); + + Input::UnregisterFactory(udp_client->GetEngineName()); + udp_client.reset(); + + Input::UnregisterFactory(tas_input->GetEngineName()); + tas_input.reset(); + +#ifdef HAVE_SDL2 + Input::UnregisterFactory(sdl->GetEngineName()); + sdl.reset(); +#endif + + Input::UnregisterFactory("touch_from_button"); + Input::UnregisterFactory("analog_from_button"); } [[nodiscard]] std::vector GetInputDevices() const { std::vector devices = { - Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, - Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, + Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, }; - return {}; + + auto keyboard_devices = keyboard->GetInputDevices(); + devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); + auto mouse_devices = mouse->GetInputDevices(); + devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); + auto gcadapter_devices = gcadapter->GetInputDevices(); + devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); + auto tas_input_devices = tas_input->GetInputDevices(); + devices.insert(devices.end(), tas_input_devices.begin(), tas_input_devices.end()); +#ifdef HAVE_SDL2 + auto sdl_devices = sdl->GetInputDevices(); + devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); +#endif + + return devices; } [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetAnalogMappingForDevice(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetAnalogMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetAnalogMappingForDevice(params); + } +#endif return {}; } [[nodiscard]] ButtonMapping GetButtonMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetButtonMappingForDevice(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetButtonMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetButtonMappingForDevice(params); + } +#endif return {}; } [[nodiscard]] MotionMapping GetMotionMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetMotionMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetMotionMappingForDevice(params); + } +#endif return {}; } + std::string GetButtonName(const Common::ParamPackage& params) const { + if (!params.Has("engine") || params.Get("engine", "") == "any") { + return "Unknown"; + } + const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return mouse->GetUIName(params); + } + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetUIName(params); + } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetUIName(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetUIName(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetUIName(params); + } +#endif + return "Bad engine"; + } + + bool IsController(const Common::ParamPackage& params) { + const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return true; + } + if (engine == gcadapter->GetEngineName()) { + return true; + } + if (engine == tas_input->GetEngineName()) { + return true; + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return true; + } +#endif + return false; + } + + void BeginConfiguration() { + keyboard->BeginConfiguration(); + mouse->BeginConfiguration(); + gcadapter->BeginConfiguration(); + udp_client->BeginConfiguration(); +#ifdef HAVE_SDL2 + sdl->BeginConfiguration(); +#endif + } + + void EndConfiguration() { + keyboard->EndConfiguration(); + mouse->EndConfiguration(); + gcadapter->EndConfiguration(); + udp_client->EndConfiguration(); +#ifdef HAVE_SDL2 + sdl->EndConfiguration(); +#endif + } + + void RegisterInput(MappingData data) { + mapping_factory->RegisterInput(data); + } + + std::shared_ptr mapping_factory; + std::shared_ptr keyboard; + std::shared_ptr keyboard_factory; + std::shared_ptr mouse; + std::shared_ptr mouse_factory; + std::shared_ptr gcadapter; + std::shared_ptr gcadapter_factory; + std::shared_ptr touch_screen; + std::shared_ptr touch_screen_factory; + std::shared_ptr udp_client; + std::shared_ptr udp_client_factory; + std::shared_ptr tas_input; + std::shared_ptr tas_input_factory; +#ifdef HAVE_SDL2 + std::shared_ptr sdl; + std::shared_ptr sdl_factory; +#endif }; InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} @@ -66,6 +277,38 @@ void InputSubsystem::Shutdown() { impl->Shutdown(); } +Keyboard* InputSubsystem::GetKeyboard() { + return impl->keyboard.get(); +} + +const Keyboard* InputSubsystem::GetKeyboard() const { + return impl->keyboard.get(); +} + +Mouse* InputSubsystem::GetMouse() { + return impl->mouse.get(); +} + +const Mouse* InputSubsystem::GetMouse() const { + return impl->mouse.get(); +} + +TouchScreen* InputSubsystem::GetTouchScreen() { + return impl->touch_screen.get(); +} + +const TouchScreen* InputSubsystem::GetTouchScreen() const { + return impl->touch_screen.get(); +} + +TasInput::Tas* InputSubsystem::GetTas() { + return impl->tas_input.get(); +} + +const TasInput::Tas* InputSubsystem::GetTas() const { + return impl->tas_input.get(); +} + std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } @@ -82,12 +325,37 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka return impl->GetMotionMappingForDevice(device); } -void InputSubsystem::ReloadInputDevices() { +std::string InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { + const std::string toggle = params.Get("toggle", false) ? "~" : ""; + const std::string inverted = params.Get("inverted", false) ? "!" : ""; + const std::string button_name = impl->GetButtonName(params); + std::string axis_direction = ""; + if (params.Has("axis")) { + axis_direction = params.Get("invert", "+"); + } + return fmt::format("{}{}{}{}", toggle, inverted, button_name, axis_direction); } -std::vector> InputSubsystem::GetPollers([ - [maybe_unused]] Polling::DeviceType type) const { - return {}; +bool InputSubsystem::IsController(const Common::ParamPackage& params) const { + return impl->IsController(params); +} + +void InputSubsystem::ReloadInputDevices() { + impl->udp_client.get()->ReloadSockets(); +} + +void InputSubsystem::BeginMapping(Polling::InputType type) { + impl->BeginConfiguration(); + impl->mapping_factory->BeginMapping(type); +} + +const Common::ParamPackage InputSubsystem::GetNextInput() const { + return impl->mapping_factory->GetNextInput(); +} + +void InputSubsystem::StopMapping() const { + impl->EndConfiguration(); + impl->mapping_factory->StopMapping(); } std::string GenerateKeyboardParam(int key_code) { diff --git a/src/input_common/main.h b/src/input_common/main.h index b504ebe54..a4a24d076 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -25,47 +25,26 @@ namespace Settings::NativeMotion { enum Values : int; } -namespace MouseInput { +namespace InputCommon { +class Keyboard; class Mouse; -} +class TouchScreen; +struct MappingData; +} // namespace InputCommon -namespace TasInput { +namespace InputCommon::TasInput { class Tas; -} +} // namespace InputCommon::TasInput namespace InputCommon { namespace Polling { - -enum class DeviceType { Button, AnalogPreferred, Motion }; - /// Type of input desired for mapping purposes enum class InputType { None, Button, Stick, Motion, Touch }; - -/** - * A class that can be used to get inputs from an input device like controllers without having to - * poll the device's status yourself - */ -class DevicePoller { -public: - virtual ~DevicePoller() = default; - /// Setup and start polling for inputs, should be called before GetNextInput - /// If a device_id is provided, events should be filtered to only include events from this - /// device id - virtual void Start(const std::string& device_id = "") = 0; - /// Stop polling - virtual void Stop() = 0; - /** - * Every call to this function returns the next input recorded since calling Start - * @return A ParamPackage of the recorded input, which can be used to create an InputDevice. - * If there has been no input, the package is empty - */ - virtual Common::ParamPackage GetNextInput() = 0; -}; } // namespace Polling /** * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default - * mapping for the device. This is currently only implemented for the SDL backend devices. + * mapping for the device. */ using AnalogMapping = std::unordered_map; using ButtonMapping = std::unordered_map; @@ -88,10 +67,34 @@ public: /// Unregisters all built-in input device factories and shuts them down. void Shutdown(); + /// Retrieves the underlying keyboard device. + [[nodiscard]] Keyboard* GetKeyboard(); + + /// Retrieves the underlying keyboard device. + [[nodiscard]] const Keyboard* GetKeyboard() const; + + /// Retrieves the underlying mouse device. + [[nodiscard]] Mouse* GetMouse(); + + /// Retrieves the underlying mouse device. + [[nodiscard]] const Mouse* GetMouse() const; + + /// Retrieves the underlying touch screen device. + [[nodiscard]] TouchScreen* GetTouchScreen(); + + /// Retrieves the underlying touch screen device. + [[nodiscard]] const TouchScreen* GetTouchScreen() const; + + /// Retrieves the underlying tas input device. + [[nodiscard]] TasInput::Tas* GetTas(); + + /// Retrieves the underlying tas input device. + [[nodiscard]] const TasInput::Tas* GetTas() const; + /** * Returns all available input devices that this Factory can create a new device with. - * Each returned ParamPackage should have a `display` field used for display, a class field for - * backends to determine if this backend is meant to service the request and any other + * Each returned ParamPackage should have a `display` field used for display, a `engine` field + * for backends to determine if this backend is meant to service the request and any other * information needed to identify this in the backend later. */ [[nodiscard]] std::vector GetInputDevices() const; @@ -105,23 +108,33 @@ public: /// Retrieves the motion mappings for the given device. [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; - /// Reloads the input devices + /// Returns a string contaning the name of the button from the input engine. + [[nodiscard]] std::string GetButtonName(const Common::ParamPackage& params) const; + + /// Returns true if device is a controller. + [[nodiscard]] bool IsController(const Common::ParamPackage& params) const; + + /// Reloads the input devices. void ReloadInputDevices(); - /// Get all DevicePoller from all backends for a specific device type - [[nodiscard]] std::vector> GetPollers( - Polling::DeviceType type) const; + /// Start polling from all backends for a desired input type. + void BeginMapping(Polling::InputType type); + + /// Returns an input event with mapping information. + [[nodiscard]] const Common::ParamPackage GetNextInput() const; + + /// Stop polling from all backends. + void StopMapping() const; private: struct Impl; std::unique_ptr impl; }; -/// Generates a serialized param package for creating a keyboard button device +/// Generates a serialized param package for creating a keyboard button device. std::string GenerateKeyboardParam(int key_code); -/// Generates a serialized param package for creating an analog device taking input from keyboard +/// Generates a serialized param package for creating an analog device taking input from keyboard. std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); - } // namespace InputCommon From 737d305f6324d28a7fde882077fb7e9a0e66311f Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:39:08 -0500 Subject: [PATCH 063/291] yuzu: Use new input on main and bootmanager --- src/yuzu/bootmanager.cpp | 87 +++++++++++++++++++--------------------- src/yuzu/bootmanager.h | 9 ++--- src/yuzu/main.cpp | 25 ++++++------ 3 files changed, 56 insertions(+), 65 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 8a0ea90f9..726f789b7 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -27,12 +27,15 @@ #include "common/assert.h" #include "common/microprofile.h" +#include "common/param_package.h" #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.h" -#include "input_common/keyboard.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/drivers/touch_screen.h" #include "input_common/main.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" @@ -294,7 +297,6 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); input_subsystem->Initialize(); - this->setMouseTracking(true); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); @@ -392,34 +394,34 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - // input_subsystem->GetKeyboard()->PressKey(event->key()); + input_subsystem->GetKeyboard()->PressKey(event->key()); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - // input_subsystem->GetKeyboard()->ReleaseKey(event->key()); + input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } -//MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { -// switch (button) { -// case Qt::LeftButton: -// return MouseInput::MouseButton::Left; -// case Qt::RightButton: -// return MouseInput::MouseButton::Right; -// case Qt::MiddleButton: -// return MouseInput::MouseButton::Wheel; -// case Qt::BackButton: -// return MouseInput::MouseButton::Backward; -// case Qt::ForwardButton: -// return MouseInput::MouseButton::Forward; -// case Qt::TaskButton: -// return MouseInput::MouseButton::Task; -// default: -// return MouseInput::MouseButton::Extra; -// } -//} +InputCommon::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { + switch (button) { + case Qt::LeftButton: + return InputCommon::MouseButton::Left; + case Qt::RightButton: + return InputCommon::MouseButton::Right; + case Qt::MiddleButton: + return InputCommon::MouseButton::Wheel; + case Qt::BackButton: + return InputCommon::MouseButton::Backward; + case Qt::ForwardButton: + return InputCommon::MouseButton::Forward; + case Qt::TaskButton: + return InputCommon::MouseButton::Task; + default: + return InputCommon::MouseButton::Extra; + } +} void GRenderWindow::mousePressEvent(QMouseEvent* event) { // Touch input is handled in TouchBeginEvent @@ -430,12 +432,9 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { // coordinates and map them to the current render area const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); - //const auto button = QtButtonToMouseButton(event->button()); - //input_subsystem->GetMouse()->PressButton(x, y, button); - - if (event->button() == Qt::LeftButton) { - this->TouchPressed(x, y, 0); - } + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); + const auto button = QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, button); emit MouseActivity(); } @@ -449,10 +448,10 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { // coordinates and map them to the current render area const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); const int center_x = width() / 2; const int center_y = height() / 2; - //input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y); - this->TouchMoved(x, y, 0); + input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); if (Settings::values.mouse_panning) { QCursor::setPos(mapToGlobal({center_x, center_y})); @@ -467,12 +466,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { return; } - //const auto button = QtButtonToMouseButton(event->button()); - //input_subsystem->GetMouse()->ReleaseButton(button); - - if (event->button() == Qt::LeftButton) { - this->TouchReleased(0); - } + const auto button = QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->ReleaseButton(button); } void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { @@ -495,7 +490,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (!TouchExist(touch_ids[id], touch_points)) { touch_ids[id] = 0; - this->TouchReleased(id + 1); + input_subsystem->GetTouchScreen()->TouchReleased(id); } } } @@ -504,28 +499,28 @@ void GRenderWindow::TouchEndEvent() { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] != 0) { touch_ids[id] = 0; - this->TouchReleased(id + 1); + input_subsystem->GetTouchScreen()->TouchReleased(id); } } } -bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { +void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] == 0) { touch_ids[id] = touch_point.id() + 1; const auto [x, y] = ScaleTouch(touch_point.pos()); - this->TouchPressed(x, y, id + 1); - return true; + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); + input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id); } } - return false; } bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] == static_cast(touch_point.id() + 1)) { const auto [x, y] = ScaleTouch(touch_point.pos()); - this->TouchMoved(x, y, id + 1); + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); + input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id); return true; } } @@ -556,9 +551,9 @@ bool GRenderWindow::event(QEvent* event) { void GRenderWindow::focusOutEvent(QFocusEvent* event) { QWidget::focusOutEvent(event); - //input_subsystem->GetKeyboard()->ReleaseAllKeys(); - //input_subsystem->GetMouse()->ReleaseAllButtons(); - this->TouchReleased(0); + input_subsystem->GetKeyboard()->ReleaseAllKeys(); + input_subsystem->GetMouse()->ReleaseAllButtons(); + input_subsystem->GetTouchScreen()->ReleaseAllTouch(); } void GRenderWindow::resizeEvent(QResizeEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index f0784046b..95594f81c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -30,11 +30,8 @@ class System; namespace InputCommon { class InputSubsystem; -} - -namespace MouseInput { enum class MouseButton; -} +} // namespace InputCommon namespace VideoCore { enum class LoadCallbackStage; @@ -165,7 +162,7 @@ public: void keyReleaseEvent(QKeyEvent* event) override; /// Converts a Qt mouse button into MouseInput mouse button - // static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); + static InputCommon::MouseButton QtButtonToMouseButton(Qt::MouseButton button); void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; @@ -214,7 +211,7 @@ private: void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); - bool TouchStart(const QTouchEvent::TouchPoint& touch_point); + void TouchStart(const QTouchEvent::TouchPoint& touch_point); bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); bool TouchExist(std::size_t id, const QList& touch_points) const; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 663760a1e..7f36f6e2f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -106,8 +106,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/loader/loader.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" +#include "input_common/drivers/tas_input.h" #include "input_common/main.h" -#include "input_common/tas/tas_input.h" #include "ui_main.h" #include "util/overlay_dialog.h" #include "video_core/gpu.h" @@ -838,7 +838,6 @@ void GMainWindow::InitializeWidgets() { controller_type = Settings::ControllerType::ProController; ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system); configure_dialog.ApplyConfiguration(); - controller_dialog->refreshConfiguration(); } Settings::values.use_docked_mode.SetValue(!is_docked); @@ -922,7 +921,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(this, input_subsystem.get()); + controller_dialog = new ControllerDialog(this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -2708,7 +2707,6 @@ void GMainWindow::OnConfigure() { ShowTelemetryCallout(); } - controller_dialog->refreshConfiguration(); InitializeHotkeys(); if (UISettings::values.theme != old_theme) { @@ -2969,15 +2967,15 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie } QString GMainWindow::GetTasStateDescription() const { - //auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); - //switch (tas_status) { - //case TasInput::TasState::Running: - // return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); - //case TasInput::TasState::Recording: - // return tr("TAS state: Recording %1").arg(total_tas_frames); - //case TasInput::TasState::Stopped: - // return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); - //default: + auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); + switch (tas_status) { + case InputCommon::TasInput::TasState::Running: + return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); + case InputCommon::TasInput::TasState::Recording: + return tr("TAS state: Recording %1").arg(total_tas_frames); + case InputCommon::TasInput::TasState::Stopped: + return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); + default: return tr("TAS State: Invalid"); } } @@ -3371,6 +3369,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); hotkey_registry.SaveHotkeys(); + Core::System::GetInstance().HIDCore().UnloadInputDevices(); // Shutdown session if the emu thread is active... if (emu_thread != nullptr) { From 14b949a0da6aa600d873c88f1836921f4d9a7919 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:40:00 -0500 Subject: [PATCH 064/291] yuzu_cmd: Use new input --- src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 72 +++++++++---------- src/yuzu_cmd/emu_window/emu_window_sdl2.h | 11 ++- .../emu_window/emu_window_sdl2_gl.cpp | 1 - 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 87fce0c23..57f807826 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -9,10 +9,10 @@ #include "common/settings.h" #include "core/core.h" #include "core/perf_stats.h" -#include "input_common/keyboard.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/drivers/touch_screen.h" #include "input_common/main.h" -#include "input_common/mouse/mouse_input.h" -#include "input_common/sdl/sdl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/yuzu_icon.h" @@ -32,42 +32,32 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { } void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { - TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); - - input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); + input_subsystem->GetMouse()->MouseMove(x, y, 0, 0, 0, 0); } -MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { +InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { switch (button) { case SDL_BUTTON_LEFT: - return MouseInput::MouseButton::Left; + return InputCommon::MouseButton::Left; case SDL_BUTTON_RIGHT: - return MouseInput::MouseButton::Right; + return InputCommon::MouseButton::Right; case SDL_BUTTON_MIDDLE: - return MouseInput::MouseButton::Wheel; + return InputCommon::MouseButton::Wheel; case SDL_BUTTON_X1: - return MouseInput::MouseButton::Backward; + return InputCommon::MouseButton::Backward; case SDL_BUTTON_X2: - return MouseInput::MouseButton::Forward; + return InputCommon::MouseButton::Forward; default: - return MouseInput::MouseButton::Undefined; + return InputCommon::MouseButton::Undefined; } } void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { const auto mouse_button = SDLButtonToMouseButton(button); - if (button == SDL_BUTTON_LEFT) { - if (state == SDL_PRESSED) { - TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); - } else { - TouchReleased(0); - } + if (state == SDL_PRESSED) { + input_subsystem->GetMouse()->PressButton(x, y, 0, 0, mouse_button); } else { - if (state == SDL_PRESSED) { - input_subsystem->GetMouse()->PressButton(x, y, mouse_button); - } else { - input_subsystem->GetMouse()->ReleaseButton(mouse_button); - } + input_subsystem->GetMouse()->ReleaseButton(mouse_button); } } @@ -82,29 +72,35 @@ std::pair EmuWindow_SDL2::TouchToPixelPos(float touch_x, flo static_cast(std::max(std::round(touch_y), 0.0f))}; } -void EmuWindow_SDL2::OnFingerDown(float x, float y) { - // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind - // This isn't critical because the best we can do when we have that is to average them, like the - // 3DS does - +void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) { + int width, height; + SDL_GetWindowSize(render_window, &width, &height); const auto [px, py] = TouchToPixelPos(x, y); - TouchPressed(px, py, 0); + const float fx = px * 1.0f / width; + const float fy = py * 1.0f / height; + + input_subsystem->GetTouchScreen()->TouchPressed(fx, fy, id); } -void EmuWindow_SDL2::OnFingerMotion(float x, float y) { +void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) { + int width, height; + SDL_GetWindowSize(render_window, &width, &height); const auto [px, py] = TouchToPixelPos(x, y); - TouchMoved(px, py, 0); + const float fx = px * 1.0f / width; + const float fy = py * 1.0f / height; + + input_subsystem->GetTouchScreen()->TouchMoved(fx, fy, id); } void EmuWindow_SDL2::OnFingerUp() { - TouchReleased(0); + input_subsystem->GetTouchScreen()->TouchReleased(0); } void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { if (state == SDL_PRESSED) { - input_subsystem->GetKeyboard()->PressKey(key); + input_subsystem->GetKeyboard()->PressKey(static_cast(key)); } else if (state == SDL_RELEASED) { - input_subsystem->GetKeyboard()->ReleaseKey(key); + input_subsystem->GetKeyboard()->ReleaseKey(static_cast(key)); } } @@ -205,10 +201,12 @@ void EmuWindow_SDL2::WaitEvent() { } break; case SDL_FINGERDOWN: - OnFingerDown(event.tfinger.x, event.tfinger.y); + OnFingerDown(event.tfinger.x, event.tfinger.y, + static_cast(event.tfinger.touchId)); break; case SDL_FINGERMOTION: - OnFingerMotion(event.tfinger.x, event.tfinger.y); + OnFingerMotion(event.tfinger.x, event.tfinger.y, + static_cast(event.tfinger.touchId)); break; case SDL_FINGERUP: OnFingerUp(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 4810f8775..0af002693 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h @@ -16,11 +16,8 @@ class System; namespace InputCommon { class InputSubsystem; -} - -namespace MouseInput { enum class MouseButton; -} +} // namespace InputCommon class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { public: @@ -47,7 +44,7 @@ protected: void OnMouseMotion(s32 x, s32 y); /// Converts a SDL mouse button into MouseInput mouse button - MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const; + InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const; /// Called by WaitEvent when a mouse button is pressed or released void OnMouseButton(u32 button, u8 state, s32 x, s32 y); @@ -56,10 +53,10 @@ protected: std::pair TouchToPixelPos(float touch_x, float touch_y) const; /// Called by WaitEvent when a finger starts touching the touchscreen - void OnFingerDown(float x, float y); + void OnFingerDown(float x, float y, std::size_t id); /// Called by WaitEvent when a finger moves while touching the touchscreen - void OnFingerMotion(float x, float y); + void OnFingerMotion(float x, float y, std::size_t id); /// Called by WaitEvent when a finger stops touching the touchscreen void OnFingerUp(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index a075ad08a..70db865ec 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp @@ -17,7 +17,6 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "input_common/keyboard.h" #include "input_common/main.h" #include "video_core/renderer_base.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" From c3f54ff2329d79bdbb273678b5123cf0b1cd090c Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:43:16 -0500 Subject: [PATCH 065/291] core/hid: Add emulated controllers --- src/core/CMakeLists.txt | 8 + src/core/hid/emulated_console.cpp | 208 ++++++++ src/core/hid/emulated_console.h | 142 +++++ src/core/hid/emulated_controller.cpp | 745 +++++++++++++++++++++++++++ src/core/hid/emulated_controller.h | 232 +++++++++ src/core/hid/emulated_devices.cpp | 349 +++++++++++++ src/core/hid/emulated_devices.h | 137 +++++ src/core/hid/hid_core.cpp | 144 ++++++ src/core/hid/hid_core.h | 60 +++ 9 files changed, 2025 insertions(+) create mode 100644 src/core/hid/emulated_console.cpp create mode 100644 src/core/hid/emulated_console.h create mode 100644 src/core/hid/emulated_controller.cpp create mode 100644 src/core/hid/emulated_controller.h create mode 100644 src/core/hid/emulated_devices.cpp create mode 100644 src/core/hid/emulated_devices.h create mode 100644 src/core/hid/hid_core.cpp create mode 100644 src/core/hid/hid_core.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eddf455c0..09163fab9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -135,6 +135,14 @@ add_library(core STATIC frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h + hid/emulated_console.cpp + hid/emulated_console.h + hid/emulated_controller.cpp + hid/emulated_controller.h + hid/emulated_devices.cpp + hid/emulated_devices.h + hid/hid_core.cpp + hid/hid_core.h hid/hid_types.h hid/input_converter.cpp hid/input_converter.h diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp new file mode 100644 index 000000000..c65d05041 --- /dev/null +++ b/src/core/hid/emulated_console.cpp @@ -0,0 +1,208 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include + +#include "core/hid/emulated_console.h" +#include "core/hid/input_converter.h" + +namespace Core::HID { +EmulatedConsole::EmulatedConsole() {} + +EmulatedConsole::~EmulatedConsole() = default; + +void EmulatedConsole::ReloadFromSettings() { + // Using first motion device from player 1. No need to assign a special config at the moment + const auto& player = Settings::values.players.GetValue()[0]; + motion_params = Common::ParamPackage(player.motions[0]); + + ReloadInput(); +} + +void EmulatedConsole::ReloadInput() { + motion_devices = Input::CreateDevice(motion_params); + if (motion_devices) { + Input::InputCallback motion_callback{ + [this](Input::CallbackStatus callback) { SetMotion(callback); }}; + motion_devices->SetCallback(motion_callback); + } + + // TODO: Fix this mess + std::size_t index = 0; + const std::string mouse_device_string = + fmt::format("engine:mouse,axis_x:10,axis_y:11,button:{}", index); + touch_devices[index] = Input::CreateDeviceFromString(mouse_device_string); + Input::InputCallback trigger_callbackk{ + [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; + touch_devices[index]->SetCallback(trigger_callbackk); + + index++; + const auto button_index = + static_cast(Settings::values.touch_from_button_map_index.GetValue()); + const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons; + for (const auto& config_entry : touch_buttons) { + Common::ParamPackage params{config_entry}; + Common::ParamPackage touch_button_params; + const int x = params.Get("x", 0); + const int y = params.Get("y", 0); + params.Erase("x"); + params.Erase("y"); + touch_button_params.Set("engine", "touch_from_button"); + touch_button_params.Set("button", params.Serialize()); + touch_button_params.Set("x", x); + touch_button_params.Set("y", y); + touch_button_params.Set("touch_id", static_cast(index)); + LOG_ERROR(Common, "{} ", touch_button_params.Serialize()); + touch_devices[index] = + Input::CreateDeviceFromString(touch_button_params.Serialize()); + if (!touch_devices[index]) { + continue; + } + + Input::InputCallback trigger_callback{ + [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; + touch_devices[index]->SetCallback(trigger_callback); + index++; + } +} + +void EmulatedConsole::UnloadInput() { + motion_devices.reset(); + for (auto& touch : touch_devices) { + touch.reset(); + } +} + +void EmulatedConsole::EnableConfiguration() { + is_configuring = true; + SaveCurrentConfig(); +} + +void EmulatedConsole::DisableConfiguration() { + is_configuring = false; +} + +bool EmulatedConsole::IsConfiguring() const { + return is_configuring; +} + +void EmulatedConsole::SaveCurrentConfig() { + if (!is_configuring) { + return; + } +} + +void EmulatedConsole::RestoreConfig() { + if (!is_configuring) { + return; + } + ReloadFromSettings(); +} + +Common::ParamPackage EmulatedConsole::GetMotionParam() const { + return motion_params; +} + +void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { + motion_params = param; + ReloadInput(); +} + +void EmulatedConsole::SetMotion(Input::CallbackStatus callback) { + std::lock_guard lock{mutex}; + auto& raw_status = console.motion_values.raw_status; + auto& emulated = console.motion_values.emulated; + + raw_status = TransformToMotion(callback); + emulated.SetAcceleration(Common::Vec3f{ + raw_status.accel.x.value, + raw_status.accel.y.value, + raw_status.accel.z.value, + }); + emulated.SetGyroscope(Common::Vec3f{ + raw_status.gyro.x.value, + raw_status.gyro.y.value, + raw_status.gyro.z.value, + }); + emulated.UpdateRotation(raw_status.delta_timestamp); + emulated.UpdateOrientation(raw_status.delta_timestamp); + + if (is_configuring) { + TriggerOnChange(ConsoleTriggerType::Motion); + return; + } + + auto& motion = console.motion_state; + motion.accel = emulated.GetAcceleration(); + motion.gyro = emulated.GetGyroscope(); + motion.rotation = emulated.GetGyroscope(); + motion.orientation = emulated.GetOrientation(); + motion.quaternion = emulated.GetQuaternion(); + motion.is_at_rest = emulated.IsMoving(motion_sensitivity); + + TriggerOnChange(ConsoleTriggerType::Motion); +} + +void EmulatedConsole::SetTouch(Input::CallbackStatus callback, [[maybe_unused]] std::size_t index) { + if (index >= console.touch_values.size()) { + return; + } + std::lock_guard lock{mutex}; + + console.touch_values[index] = TransformToTouch(callback); + + if (is_configuring) { + TriggerOnChange(ConsoleTriggerType::Touch); + return; + } + + console.touch_state[index] = { + .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, + .id = console.touch_values[index].id, + .pressed = console.touch_values[index].pressed.value, + }; + + TriggerOnChange(ConsoleTriggerType::Touch); +} + +ConsoleMotionValues EmulatedConsole::GetMotionValues() const { + return console.motion_values; +} + +TouchValues EmulatedConsole::GetTouchValues() const { + return console.touch_values; +} + +ConsoleMotion EmulatedConsole::GetMotion() const { + return console.motion_state; +} + +TouchFingerState EmulatedConsole::GetTouch() const { + return console.touch_state; +} + +void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { + for (const std::pair poller_pair : callback_list) { + const ConsoleUpdateCallback& poller = poller_pair.second; + if (poller.on_change) { + poller.on_change(type); + } + } +} + +int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { + std::lock_guard lock{mutex}; + callback_list.insert_or_assign(last_callback_key, update_callback); + return last_callback_key++; +} + +void EmulatedConsole::DeleteCallback(int key) { + std::lock_guard lock{mutex}; + if (!callback_list.contains(key)) { + LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); + return; + } + callback_list.erase(key); +} +} // namespace Core::HID diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h new file mode 100644 index 000000000..d9e275042 --- /dev/null +++ b/src/core/hid/emulated_console.h @@ -0,0 +1,142 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/input.h" +#include "common/param_package.h" +#include "common/point.h" +#include "common/quaternion.h" +#include "common/settings.h" +#include "common/vector_math.h" +#include "core/hid/hid_types.h" +#include "core/hid/motion_input.h" + +namespace Core::HID { + +struct ConsoleMotionInfo { + Input::MotionStatus raw_status; + MotionInput emulated{}; +}; + +using ConsoleMotionDevices = std::unique_ptr; +using TouchDevices = std::array, 16>; + +using ConsoleMotionParams = Common::ParamPackage; +using TouchParams = std::array; + +using ConsoleMotionValues = ConsoleMotionInfo; +using TouchValues = std::array; + +struct TouchFinger { + u64_le last_touch{}; + Common::Point position{}; + u32_le id{}; + bool pressed{}; + Core::HID::TouchAttribute attribute{}; +}; + +struct ConsoleMotion { + bool is_at_rest{}; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + Common::Vec3f rotation{}; + std::array orientation{}; + Common::Quaternion quaternion{}; +}; + +using TouchFingerState = std::array; + +struct ConsoleStatus { + // Data from input_common + ConsoleMotionValues motion_values{}; + TouchValues touch_values{}; + + // Data for Nintendo devices; + ConsoleMotion motion_state{}; + TouchFingerState touch_state{}; +}; + +enum class ConsoleTriggerType { + Motion, + Touch, + All, +}; + +struct ConsoleUpdateCallback { + std::function on_change; +}; + +class EmulatedConsole { +public: + /** + * TODO: Write description + * + * @param npad_id_type + */ + explicit EmulatedConsole(); + ~EmulatedConsole(); + + YUZU_NON_COPYABLE(EmulatedConsole); + YUZU_NON_MOVEABLE(EmulatedConsole); + + void ReloadFromSettings(); + void ReloadInput(); + void UnloadInput(); + + void EnableConfiguration(); + void DisableConfiguration(); + bool IsConfiguring() const; + void SaveCurrentConfig(); + void RestoreConfig(); + + Common::ParamPackage GetMotionParam() const; + + void SetMotionParam(Common::ParamPackage param); + + ConsoleMotionValues GetMotionValues() const; + TouchValues GetTouchValues() const; + + ConsoleMotion GetMotion() const; + TouchFingerState GetTouch() const; + + int SetCallback(ConsoleUpdateCallback update_callback); + void DeleteCallback(int key); + +private: + /** + * Sets the status of a button. Applies toggle properties to the output. + * + * @param A CallbackStatus and a button index number + */ + void SetMotion(Input::CallbackStatus callback); + void SetTouch(Input::CallbackStatus callback, std::size_t index); + + /** + * Triggers a callback that something has changed + * + * @param Input type of the trigger + */ + void TriggerOnChange(ConsoleTriggerType type); + + bool is_configuring{false}; + f32 motion_sensitivity{0.01f}; + + ConsoleMotionParams motion_params; + TouchParams touch_params; + + ConsoleMotionDevices motion_devices; + TouchDevices touch_devices; + + mutable std::mutex mutex; + std::unordered_map callback_list; + int last_callback_key = 0; + ConsoleStatus console; +}; + +} // namespace Core::HID diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp new file mode 100644 index 000000000..4eb5d99bc --- /dev/null +++ b/src/core/hid/emulated_controller.cpp @@ -0,0 +1,745 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include + +#include "core/hid/emulated_controller.h" +#include "core/hid/input_converter.h" + +namespace Core::HID { +constexpr s32 HID_JOYSTICK_MAX = 0x7fff; +constexpr s32 HID_TRIGGER_MAX = 0x7fff; + +EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {} + +EmulatedController::~EmulatedController() = default; + +NpadType EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { + switch (type) { + case Settings::ControllerType::ProController: + return NpadType::ProController; + case Settings::ControllerType::DualJoyconDetached: + return NpadType::JoyconDual; + case Settings::ControllerType::LeftJoycon: + return NpadType::JoyconLeft; + case Settings::ControllerType::RightJoycon: + return NpadType::JoyconRight; + case Settings::ControllerType::Handheld: + return NpadType::Handheld; + case Settings::ControllerType::GameCube: + return NpadType::GameCube; + default: + return NpadType::ProController; + } +} + +Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type) { + switch (type) { + case NpadType::ProController: + return Settings::ControllerType::ProController; + case NpadType::JoyconDual: + return Settings::ControllerType::DualJoyconDetached; + case NpadType::JoyconLeft: + return Settings::ControllerType::LeftJoycon; + case NpadType::JoyconRight: + return Settings::ControllerType::RightJoycon; + case NpadType::Handheld: + return Settings::ControllerType::Handheld; + case NpadType::GameCube: + return Settings::ControllerType::GameCube; + default: + return Settings::ControllerType::ProController; + } +} + +void EmulatedController::ReloadFromSettings() { + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + + for (std::size_t index = 0; index < player.buttons.size(); ++index) { + button_params[index] = Common::ParamPackage(player.buttons[index]); + } + for (std::size_t index = 0; index < player.analogs.size(); ++index) { + stick_params[index] = Common::ParamPackage(player.analogs[index]); + } + for (std::size_t index = 0; index < player.motions.size(); ++index) { + motion_params[index] = Common::ParamPackage(player.motions[index]); + } + ReloadInput(); +} + +void EmulatedController::ReloadInput() { + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + const auto left_side = button_params[Settings::NativeButton::ZL]; + const auto right_side = button_params[Settings::NativeButton::ZR]; + + std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, + button_params.begin() + Settings::NativeButton::BUTTON_NS_END, + button_devices.begin(), Input::CreateDevice); + std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + stick_params.begin() + Settings::NativeAnalog::STICK_HID_END, + stick_devices.begin(), Input::CreateDevice); + std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, + motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, + motion_devices.begin(), Input::CreateDevice); + + trigger_devices[0] = + Input::CreateDevice(button_params[Settings::NativeButton::ZL]); + trigger_devices[1] = + Input::CreateDevice(button_params[Settings::NativeButton::ZR]); + + controller.colors_state.left = { + .body = player.body_color_left, + .button = player.button_color_left, + }; + + controller.colors_state.right = { + .body = player.body_color_right, + .button = player.button_color_right, + }; + + controller.colors_state.fullkey = controller.colors_state.left; + + battery_devices[0] = Input::CreateDevice(left_side); + battery_devices[1] = Input::CreateDevice(right_side); + + for (std::size_t index = 0; index < button_devices.size(); ++index) { + if (!button_devices[index]) { + continue; + } + Input::InputCallback button_callback{ + [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + button_devices[index]->SetCallback(button_callback); + } + + for (std::size_t index = 0; index < stick_devices.size(); ++index) { + if (!stick_devices[index]) { + continue; + } + Input::InputCallback stick_callback{ + [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + stick_devices[index]->SetCallback(stick_callback); + } + + for (std::size_t index = 0; index < trigger_devices.size(); ++index) { + if (!trigger_devices[index]) { + continue; + } + Input::InputCallback trigger_callback{ + [this, index](Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + trigger_devices[index]->SetCallback(trigger_callback); + } + + for (std::size_t index = 0; index < battery_devices.size(); ++index) { + if (!battery_devices[index]) { + continue; + } + Input::InputCallback battery_callback{ + [this, index](Input::CallbackStatus callback) { SetBattery(callback, index); }}; + battery_devices[index]->SetCallback(battery_callback); + } + + for (std::size_t index = 0; index < motion_devices.size(); ++index) { + if (!motion_devices[index]) { + continue; + } + Input::InputCallback motion_callback{ + [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; + motion_devices[index]->SetCallback(motion_callback); + } + + SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + + if (player.connected) { + Connect(); + } else { + Disconnect(); + } +} + +void EmulatedController::UnloadInput() { + for (auto& button : button_devices) { + button.reset(); + } + for (auto& stick : stick_devices) { + stick.reset(); + } + for (auto& motion : motion_devices) { + motion.reset(); + } + for (auto& trigger : trigger_devices) { + trigger.reset(); + } + for (auto& battery : battery_devices) { + battery.reset(); + } +} + +void EmulatedController::EnableConfiguration() { + is_configuring = true; + SaveCurrentConfig(); +} + +void EmulatedController::DisableConfiguration() { + is_configuring = false; +} + +bool EmulatedController::IsConfiguring() const { + return is_configuring; +} + +void EmulatedController::SaveCurrentConfig() { + if (!is_configuring) { + return; + } + + const auto player_index = NpadIdTypeToIndex(npad_id_type); + auto& player = Settings::values.players.GetValue()[player_index]; + + for (std::size_t index = 0; index < player.buttons.size(); ++index) { + player.buttons[index] = button_params[index].Serialize(); + } + for (std::size_t index = 0; index < player.analogs.size(); ++index) { + player.analogs[index] = stick_params[index].Serialize(); + } + for (std::size_t index = 0; index < player.motions.size(); ++index) { + player.motions[index] = motion_params[index].Serialize(); + } +} + +void EmulatedController::RestoreConfig() { + if (!is_configuring) { + return; + } + ReloadFromSettings(); +} + +std::vector EmulatedController::GetMappedDevices() const { + std::vector devices; + for (const auto& param : button_params) { + if (!param.Has("engine")) { + continue; + } + const auto devices_it = std::find_if( + devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { + return param.Get("engine", "") == param_.Get("engine", "") && + param.Get("guid", "") == param_.Get("guid", "") && + param.Get("port", "") == param_.Get("port", ""); + }); + if (devices_it != devices.end()) { + continue; + } + Common::ParamPackage device{}; + device.Set("engine", param.Get("engine", "")); + device.Set("guid", param.Get("guid", "")); + device.Set("port", param.Get("port", "")); + devices.push_back(device); + } + + for (const auto& param : stick_params) { + if (!param.Has("engine")) { + continue; + } + if (param.Get("engine", "") == "analog_from_button") { + continue; + } + const auto devices_it = std::find_if( + devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { + return param.Get("engine", "") == param_.Get("engine", "") && + param.Get("guid", "") == param_.Get("guid", "") && + param.Get("port", "") == param_.Get("port", ""); + }); + if (devices_it != devices.end()) { + continue; + } + Common::ParamPackage device{}; + device.Set("engine", param.Get("engine", "")); + device.Set("guid", param.Get("guid", "")); + device.Set("port", param.Get("port", "")); + devices.push_back(device); + } + return devices; +} + +Common::ParamPackage EmulatedController::GetButtonParam(std::size_t index) const { + if (index >= button_params.size()) { + return {}; + } + return button_params[index]; +} + +Common::ParamPackage EmulatedController::GetStickParam(std::size_t index) const { + if (index >= stick_params.size()) { + return {}; + } + return stick_params[index]; +} + +Common::ParamPackage EmulatedController::GetMotionParam(std::size_t index) const { + if (index >= motion_params.size()) { + return {}; + } + return motion_params[index]; +} + +void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage param) { + if (index >= button_params.size()) { + return; + } + button_params[index] = param; + ReloadInput(); +} + +void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage param) { + if (index >= stick_params.size()) { + return; + } + stick_params[index] = param; + ReloadInput(); +} + +void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage param) { + if (index >= motion_params.size()) { + return; + } + motion_params[index] = param; + ReloadInput(); +} + +void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t index) { + if (index >= controller.button_values.size()) { + return; + } + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = controller.button_values[index]; + current_status.toggle = new_status.toggle; + + // Update button status with current + if (!current_status.toggle) { + current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } + } + + if (!value_changed) { + return; + } + + if (is_configuring) { + controller.npad_button_state.raw = NpadButton::None; + controller.debug_pad_button_state.raw = 0; + TriggerOnChange(ControllerTriggerType::Button); + return; + } + + switch (index) { + case Settings::NativeButton::A: + controller.npad_button_state.a.Assign(current_status.value); + controller.debug_pad_button_state.a.Assign(current_status.value); + break; + case Settings::NativeButton::B: + controller.npad_button_state.b.Assign(current_status.value); + controller.debug_pad_button_state.b.Assign(current_status.value); + break; + case Settings::NativeButton::X: + controller.npad_button_state.x.Assign(current_status.value); + controller.debug_pad_button_state.x.Assign(current_status.value); + break; + case Settings::NativeButton::Y: + controller.npad_button_state.y.Assign(current_status.value); + controller.debug_pad_button_state.y.Assign(current_status.value); + break; + case Settings::NativeButton::LStick: + controller.npad_button_state.stick_l.Assign(current_status.value); + break; + case Settings::NativeButton::RStick: + controller.npad_button_state.stick_r.Assign(current_status.value); + break; + case Settings::NativeButton::L: + controller.npad_button_state.l.Assign(current_status.value); + controller.debug_pad_button_state.l.Assign(current_status.value); + break; + case Settings::NativeButton::R: + controller.npad_button_state.r.Assign(current_status.value); + controller.debug_pad_button_state.r.Assign(current_status.value); + break; + case Settings::NativeButton::ZL: + controller.npad_button_state.zl.Assign(current_status.value); + controller.debug_pad_button_state.zl.Assign(current_status.value); + break; + case Settings::NativeButton::ZR: + controller.npad_button_state.zr.Assign(current_status.value); + controller.debug_pad_button_state.zr.Assign(current_status.value); + break; + case Settings::NativeButton::Plus: + controller.npad_button_state.plus.Assign(current_status.value); + controller.debug_pad_button_state.plus.Assign(current_status.value); + break; + case Settings::NativeButton::Minus: + controller.npad_button_state.minus.Assign(current_status.value); + controller.debug_pad_button_state.minus.Assign(current_status.value); + break; + case Settings::NativeButton::DLeft: + controller.npad_button_state.left.Assign(current_status.value); + controller.debug_pad_button_state.d_left.Assign(current_status.value); + break; + case Settings::NativeButton::DUp: + controller.npad_button_state.up.Assign(current_status.value); + controller.debug_pad_button_state.d_up.Assign(current_status.value); + break; + case Settings::NativeButton::DRight: + controller.npad_button_state.right.Assign(current_status.value); + controller.debug_pad_button_state.d_right.Assign(current_status.value); + break; + case Settings::NativeButton::DDown: + 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: + controller.npad_button_state.left_sl.Assign(current_status.value); + controller.npad_button_state.right_sl.Assign(current_status.value); + break; + case Settings::NativeButton::SR: + controller.npad_button_state.left_sr.Assign(current_status.value); + controller.npad_button_state.right_sr.Assign(current_status.value); + break; + case Settings::NativeButton::Home: + case Settings::NativeButton::Screenshot: + break; + } + TriggerOnChange(ControllerTriggerType::Button); +} + +void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) { + if (index >= controller.stick_values.size()) { + return; + } + std::lock_guard lock{mutex}; + controller.stick_values[index] = TransformToStick(callback); + + if (is_configuring) { + controller.analog_stick_state.left = {}; + controller.analog_stick_state.right = {}; + TriggerOnChange(ControllerTriggerType::Stick); + return; + } + + const AnalogStickState stick{ + .x = static_cast(controller.stick_values[index].x.value * HID_JOYSTICK_MAX), + .y = static_cast(controller.stick_values[index].y.value * HID_JOYSTICK_MAX), + }; + + switch (index) { + case Settings::NativeAnalog::LStick: + controller.analog_stick_state.left = stick; + controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left); + controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up); + controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right); + controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down); + break; + case Settings::NativeAnalog::RStick: + controller.analog_stick_state.right = stick; + controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left); + controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up); + controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right); + controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down); + break; + } + + TriggerOnChange(ControllerTriggerType::Stick); +} + +void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) { + if (index >= controller.trigger_values.size()) { + return; + } + std::lock_guard lock{mutex}; + controller.trigger_values[index] = TransformToTrigger(callback); + + if (is_configuring) { + controller.gc_trigger_state.left = 0; + controller.gc_trigger_state.right = 0; + TriggerOnChange(ControllerTriggerType::Trigger); + return; + } + + const auto trigger = controller.trigger_values[index]; + + switch (index) { + case Settings::NativeTrigger::LTrigger: + controller.gc_trigger_state.left = static_cast(trigger.analog.value * HID_TRIGGER_MAX); + controller.npad_button_state.zl.Assign(trigger.pressed); + break; + case Settings::NativeTrigger::RTrigger: + controller.gc_trigger_state.right = + static_cast(trigger.analog.value * HID_TRIGGER_MAX); + controller.npad_button_state.zr.Assign(trigger.pressed); + break; + } + + TriggerOnChange(ControllerTriggerType::Trigger); +} + +void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) { + if (index >= controller.motion_values.size()) { + return; + } + std::lock_guard lock{mutex}; + auto& raw_status = controller.motion_values[index].raw_status; + auto& emulated = controller.motion_values[index].emulated; + + raw_status = TransformToMotion(callback); + emulated.SetAcceleration(Common::Vec3f{ + raw_status.accel.x.value, + raw_status.accel.y.value, + raw_status.accel.z.value, + }); + emulated.SetGyroscope(Common::Vec3f{ + raw_status.gyro.x.value, + raw_status.gyro.y.value, + raw_status.gyro.z.value, + }); + emulated.UpdateRotation(raw_status.delta_timestamp); + emulated.UpdateOrientation(raw_status.delta_timestamp); + + if (is_configuring) { + TriggerOnChange(ControllerTriggerType::Motion); + return; + } + + auto& motion = controller.motion_state[index]; + motion.accel = emulated.GetAcceleration(); + motion.gyro = emulated.GetGyroscope(); + motion.rotation = emulated.GetGyroscope(); + motion.orientation = emulated.GetOrientation(); + motion.is_at_rest = emulated.IsMoving(motion_sensitivity); + + TriggerOnChange(ControllerTriggerType::Motion); +} + +void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) { + if (index >= controller.battery_values.size()) { + return; + } + std::lock_guard lock{mutex}; + controller.battery_values[index] = TransformToBattery(callback); + + if (is_configuring) { + TriggerOnChange(ControllerTriggerType::Battery); + return; + } + + bool is_charging = false; + bool is_powered = false; + BatteryLevel battery_level = 0; + switch (controller.battery_values[index]) { + case Input::BatteryLevel::Charging: + is_charging = true; + is_powered = true; + battery_level = 6; + break; + case Input::BatteryLevel::Medium: + battery_level = 6; + break; + case Input::BatteryLevel::Low: + battery_level = 4; + break; + case Input::BatteryLevel::Critical: + battery_level = 2; + break; + case Input::BatteryLevel::Empty: + battery_level = 0; + break; + case Input::BatteryLevel::Full: + default: + is_powered = true; + battery_level = 8; + break; + } + + switch (index) { + case 0: + controller.battery_state.left = { + .is_powered = is_powered, + .is_charging = is_charging, + .battery_level = battery_level, + }; + break; + case 1: + controller.battery_state.right = { + .is_powered = is_powered, + .is_charging = is_charging, + .battery_level = battery_level, + }; + break; + case 2: + controller.battery_state.dual = { + .is_powered = is_powered, + .is_charging = is_charging, + .battery_level = battery_level, + }; + break; + } + TriggerOnChange(ControllerTriggerType::Battery); +} + +bool EmulatedController::SetVibration([[maybe_unused]] std::size_t device_index, + [[maybe_unused]] VibrationValue vibration) { + return false; +} + +int EmulatedController::TestVibration(std::size_t device_index) { + return 1; +} + +void EmulatedController::Connect() { + std::lock_guard lock{mutex}; + if (is_connected) { + LOG_WARNING(Service_HID, "Tried to turn on a connected controller {}", npad_id_type); + return; + } + is_connected = true; + TriggerOnChange(ControllerTriggerType::Connected); +} + +void EmulatedController::Disconnect() { + std::lock_guard lock{mutex}; + if (!is_connected) { + LOG_WARNING(Service_HID, "Tried to turn off a disconnected controller {}", npad_id_type); + return; + } + is_connected = false; + TriggerOnChange(ControllerTriggerType::Disconnected); +} + +bool EmulatedController::IsConnected() const { + return is_connected; +} + +bool EmulatedController::IsVibrationEnabled() const { + return is_vibration_enabled; +} + +NpadIdType EmulatedController::GetNpadIdType() const { + return npad_id_type; +} + +NpadType EmulatedController::GetNpadType() const { + return npad_type; +} + +void EmulatedController::SetNpadType(NpadType npad_type_) { + std::lock_guard lock{mutex}; + if (npad_type == npad_type_) { + return; + } + npad_type = npad_type_; + TriggerOnChange(ControllerTriggerType::Type); +} + +ButtonValues EmulatedController::GetButtonsValues() const { + return controller.button_values; +} + +SticksValues EmulatedController::GetSticksValues() const { + return controller.stick_values; +} + +TriggerValues EmulatedController::GetTriggersValues() const { + return controller.trigger_values; +} + +ControllerMotionValues EmulatedController::GetMotionValues() const { + return controller.motion_values; +} + +ColorValues EmulatedController::GetColorsValues() const { + return controller.color_values; +} + +BatteryValues EmulatedController::GetBatteryValues() const { + return controller.battery_values; +} + +NpadButtonState EmulatedController::GetNpadButtons() const { + if (is_configuring) { + return {}; + } + return controller.npad_button_state; +} + +DebugPadButton EmulatedController::GetDebugPadButtons() const { + if (is_configuring) { + return {}; + } + return controller.debug_pad_button_state; +} + +AnalogSticks EmulatedController::GetSticks() const { + if (is_configuring) { + return {}; + } + return controller.analog_stick_state; +} + +NpadGcTriggerState EmulatedController::GetTriggers() const { + if (is_configuring) { + return {}; + } + return controller.gc_trigger_state; +} + +MotionState EmulatedController::GetMotions() const { + return controller.motion_state; +} + +ControllerColors EmulatedController::GetColors() const { + return controller.colors_state; +} + +BatteryLevelState EmulatedController::GetBattery() const { + return controller.battery_state; +} + +void EmulatedController::TriggerOnChange(ControllerTriggerType type) { + for (const std::pair poller_pair : callback_list) { + const ControllerUpdateCallback& poller = poller_pair.second; + if (poller.on_change) { + poller.on_change(type); + } + } +} + +int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { + std::lock_guard lock{mutex}; + callback_list.insert_or_assign(last_callback_key, update_callback); + return last_callback_key++; +} + +void EmulatedController::DeleteCallback(int key) { + std::lock_guard lock{mutex}; + if (!callback_list.contains(key)) { + LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); + return; + } + callback_list.erase(key); +} +} // namespace Core::HID diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h new file mode 100644 index 000000000..94db9b00b --- /dev/null +++ b/src/core/hid/emulated_controller.h @@ -0,0 +1,232 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/input.h" +#include "common/param_package.h" +#include "common/point.h" +#include "common/quaternion.h" +#include "common/settings.h" +#include "common/vector_math.h" +#include "core/hid/hid_types.h" +#include "core/hid/motion_input.h" + +namespace Core::HID { + +struct ControllerMotionInfo { + Input::MotionStatus raw_status; + MotionInput emulated{}; +}; + +using ButtonDevices = + std::array, Settings::NativeButton::NumButtons>; +using StickDevices = + std::array, Settings::NativeAnalog::NumAnalogs>; +using ControllerMotionDevices = + std::array, Settings::NativeMotion::NumMotions>; +using TriggerDevices = + std::array, Settings::NativeTrigger::NumTriggers>; +using BatteryDevices = std::array, 2>; + +using ButtonParams = std::array; +using StickParams = std::array; +using ControllerMotionParams = std::array; +using TriggerParams = std::array; +using BatteryParams = std::array; + +using ButtonValues = std::array; +using SticksValues = std::array; +using TriggerValues = std::array; +using ControllerMotionValues = std::array; +using ColorValues = std::array; +using BatteryValues = std::array; +using VibrationValues = std::array; + +struct AnalogSticks { + AnalogStickState left; + AnalogStickState right; +}; + +struct ControllerColors { + NpadControllerColor fullkey; + NpadControllerColor left; + NpadControllerColor right; +}; + +struct BatteryLevelState { + NpadPowerInfo dual; + NpadPowerInfo left; + NpadPowerInfo right; +}; + +struct ControllerMotion { + bool is_at_rest; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + Common::Vec3f rotation{}; + std::array orientation{}; +}; + +using MotionState = std::array; + +struct ControllerStatus { + // Data from input_common + ButtonValues button_values{}; + SticksValues stick_values{}; + ControllerMotionValues motion_values{}; + TriggerValues trigger_values{}; + ColorValues color_values{}; + BatteryValues battery_values{}; + VibrationValues vibration_values{}; + + // Data for Nintendo devices + NpadButtonState npad_button_state{}; + DebugPadButton debug_pad_button_state{}; + AnalogSticks analog_stick_state{}; + MotionState motion_state{}; + NpadGcTriggerState gc_trigger_state{}; + ControllerColors colors_state{}; + BatteryLevelState battery_state{}; +}; +enum class ControllerTriggerType { + Button, + Stick, + Trigger, + Motion, + Color, + Battery, + Vibration, + Connected, + Disconnected, + Type, + All, +}; + +struct ControllerUpdateCallback { + std::function on_change; +}; + +class EmulatedController { +public: + /** + * TODO: Write description + * + * @param npad_id_type + */ + explicit EmulatedController(NpadIdType npad_id_type_); + ~EmulatedController(); + + YUZU_NON_COPYABLE(EmulatedController); + YUZU_NON_MOVEABLE(EmulatedController); + + static NpadType MapSettingsTypeToNPad(Settings::ControllerType type); + static Settings::ControllerType MapNPadToSettingsType(NpadType type); + + /// Gets the NpadIdType for this controller. + NpadIdType GetNpadIdType() const; + + /// Sets the NpadType for this controller. + void SetNpadType(NpadType npad_type_); + + /// Gets the NpadType for this controller. + NpadType GetNpadType() const; + + void Connect(); + void Disconnect(); + + bool IsConnected() const; + bool IsVibrationEnabled() const; + + void ReloadFromSettings(); + void ReloadInput(); + void UnloadInput(); + + void EnableConfiguration(); + void DisableConfiguration(); + bool IsConfiguring() const; + void SaveCurrentConfig(); + void RestoreConfig(); + + std::vector GetMappedDevices() const; + + Common::ParamPackage GetButtonParam(std::size_t index) const; + Common::ParamPackage GetStickParam(std::size_t index) const; + Common::ParamPackage GetMotionParam(std::size_t index) const; + + void SetButtonParam(std::size_t index, Common::ParamPackage param); + void SetStickParam(std::size_t index, Common::ParamPackage param); + void SetMotionParam(std::size_t index, Common::ParamPackage param); + + ButtonValues GetButtonsValues() const; + SticksValues GetSticksValues() const; + TriggerValues GetTriggersValues() const; + ControllerMotionValues GetMotionValues() const; + ColorValues GetColorsValues() const; + BatteryValues GetBatteryValues() const; + + NpadButtonState GetNpadButtons() const; + DebugPadButton GetDebugPadButtons() const; + AnalogSticks GetSticks() const; + NpadGcTriggerState GetTriggers() const; + MotionState GetMotions() const; + ControllerColors GetColors() const; + BatteryLevelState GetBattery() const; + + bool SetVibration(std::size_t device_index, VibrationValue vibration); + int TestVibration(std::size_t device_index); + + int SetCallback(ControllerUpdateCallback update_callback); + void DeleteCallback(int key); + +private: + /** + * Sets the status of a button. Applies toggle properties to the output. + * + * @param A CallbackStatus and a button index number + */ + void SetButton(Input::CallbackStatus callback, std::size_t index); + void SetStick(Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Input::CallbackStatus callback, std::size_t index); + void SetMotion(Input::CallbackStatus callback, std::size_t index); + void SetBattery(Input::CallbackStatus callback, std::size_t index); + + /** + * Triggers a callback that something has changed + * + * @param Input type of the trigger + */ + void TriggerOnChange(ControllerTriggerType type); + + NpadIdType npad_id_type; + NpadType npad_type{NpadType::None}; + bool is_connected{false}; + bool is_configuring{false}; + bool is_vibration_enabled{true}; + f32 motion_sensitivity{0.01f}; + + ButtonParams button_params; + StickParams stick_params; + ControllerMotionParams motion_params; + TriggerParams trigger_params; + BatteryParams battery_params; + + ButtonDevices button_devices; + StickDevices stick_devices; + ControllerMotionDevices motion_devices; + TriggerDevices trigger_devices; + BatteryDevices battery_devices; + // VibrationDevices vibration_devices; + + mutable std::mutex mutex; + std::unordered_map callback_list; + int last_callback_key = 0; + ControllerStatus controller; +}; + +} // namespace Core::HID diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp new file mode 100644 index 000000000..3caf90714 --- /dev/null +++ b/src/core/hid/emulated_devices.cpp @@ -0,0 +1,349 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include + +#include "core/hid/emulated_devices.h" +#include "core/hid/input_converter.h" + +namespace Core::HID { + +EmulatedDevices::EmulatedDevices() {} + +EmulatedDevices::~EmulatedDevices() = default; + +void EmulatedDevices::ReloadFromSettings() { + const auto& mouse = Settings::values.mouse_buttons; + + for (std::size_t index = 0; index < mouse.size(); ++index) { + mouse_button_params[index] = Common::ParamPackage(mouse[index]); + } + ReloadInput(); +} + +void EmulatedDevices::ReloadInput() { + std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, + mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, + mouse_button_devices.begin(), Input::CreateDevice); + + std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), + keyboard_devices.begin(), Input::CreateDeviceFromString); + + std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), + keyboard_modifier_devices.begin(), + Input::CreateDeviceFromString); + + for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { + if (!mouse_button_devices[index]) { + continue; + } + Input::InputCallback button_callback{ + [this, index](Input::CallbackStatus callback) { SetMouseButton(callback, index); }}; + mouse_button_devices[index]->SetCallback(button_callback); + } + + for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { + if (!keyboard_devices[index]) { + continue; + } + Input::InputCallback button_callback{ + [this, index](Input::CallbackStatus callback) { SetKeyboardButton(callback, index); }}; + keyboard_devices[index]->SetCallback(button_callback); + } + + for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) { + if (!keyboard_modifier_devices[index]) { + continue; + } + Input::InputCallback button_callback{[this, index](Input::CallbackStatus callback) { + SetKeyboardModifier(callback, index); + }}; + keyboard_modifier_devices[index]->SetCallback(button_callback); + } +} + +void EmulatedDevices::UnloadInput() { + for (auto& button : mouse_button_devices) { + button.reset(); + } + for (auto& button : keyboard_devices) { + button.reset(); + } + for (auto& button : keyboard_modifier_devices) { + button.reset(); + } +} + +void EmulatedDevices::EnableConfiguration() { + is_configuring = true; + SaveCurrentConfig(); +} + +void EmulatedDevices::DisableConfiguration() { + is_configuring = false; +} + +bool EmulatedDevices::IsConfiguring() const { + return is_configuring; +} + +void EmulatedDevices::SaveCurrentConfig() { + if (!is_configuring) { + return; + } + + auto& mouse = Settings::values.mouse_buttons; + + for (std::size_t index = 0; index < mouse.size(); ++index) { + mouse[index] = mouse_button_params[index].Serialize(); + } +} + +void EmulatedDevices::RestoreConfig() { + if (!is_configuring) { + return; + } + ReloadFromSettings(); +} + +Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const { + if (index >= mouse_button_params.size()) { + return {}; + } + return mouse_button_params[index]; +} + +void EmulatedDevices::SetButtonParam(std::size_t index, Common::ParamPackage param) { + if (index >= mouse_button_params.size()) { + return; + } + mouse_button_params[index] = param; + ReloadInput(); +} + +void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::size_t index) { + if (index >= device_status.keyboard_values.size()) { + return; + } + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = device_status.keyboard_values[index]; + current_status.toggle = new_status.toggle; + + // Update button status with current + if (!current_status.toggle) { + current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } + } + + if (!value_changed) { + return; + } + + if (is_configuring) { + TriggerOnChange(DeviceTriggerType::Keyboard); + return; + } + + // TODO(german77): Do this properly + // switch (index) { + // case Settings::NativeKeyboard::A: + // interface_status.keyboard_state.a.Assign(current_status.value); + // break; + // .... + //} + + TriggerOnChange(DeviceTriggerType::Keyboard); +} + +void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) { + if (index >= device_status.keyboard_moddifier_values.size()) { + return; + } + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = device_status.keyboard_moddifier_values[index]; + current_status.toggle = new_status.toggle; + + // Update button status with current + if (!current_status.toggle) { + current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } + } + + if (!value_changed) { + return; + } + + if (is_configuring) { + TriggerOnChange(DeviceTriggerType::KeyboardModdifier); + return; + } + + switch (index) { + case Settings::NativeKeyboard::LeftControl: + case Settings::NativeKeyboard::RightControl: + device_status.keyboard_moddifier_state.control.Assign(current_status.value); + break; + case Settings::NativeKeyboard::LeftShift: + case Settings::NativeKeyboard::RightShift: + device_status.keyboard_moddifier_state.shift.Assign(current_status.value); + break; + case Settings::NativeKeyboard::LeftAlt: + device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value); + break; + case Settings::NativeKeyboard::RightAlt: + device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value); + break; + case Settings::NativeKeyboard::CapsLock: + device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value); + break; + case Settings::NativeKeyboard::ScrollLock: + device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value); + break; + case Settings::NativeKeyboard::NumLock: + device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value); + break; + } + + TriggerOnChange(DeviceTriggerType::KeyboardModdifier); +} + +void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t index) { + if (index >= device_status.mouse_button_values.size()) { + return; + } + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = device_status.mouse_button_values[index]; + current_status.toggle = new_status.toggle; + + // Update button status with current + if (!current_status.toggle) { + current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } + } + + if (!value_changed) { + return; + } + + if (is_configuring) { + TriggerOnChange(DeviceTriggerType::Mouse); + return; + } + + switch (index) { + case Settings::NativeMouseButton::Left: + device_status.mouse_button_state.left.Assign(current_status.value); + break; + case Settings::NativeMouseButton::Right: + device_status.mouse_button_state.right.Assign(current_status.value); + break; + case Settings::NativeMouseButton::Middle: + device_status.mouse_button_state.middle.Assign(current_status.value); + break; + case Settings::NativeMouseButton::Forward: + device_status.mouse_button_state.forward.Assign(current_status.value); + break; + case Settings::NativeMouseButton::Back: + device_status.mouse_button_state.back.Assign(current_status.value); + break; + } + + TriggerOnChange(DeviceTriggerType::Mouse); +} + +MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { + return device_status.mouse_button_values; +} + +KeyboardKey EmulatedDevices::GetKeyboard() const { + return device_status.keyboard_state; +} + +KeyboardModifier EmulatedDevices::GetKeyboardModifier() const { + return device_status.keyboard_moddifier_state; +} + +MouseButton EmulatedDevices::GetMouseButtons() const { + return device_status.mouse_button_state; +} + +MousePosition EmulatedDevices::GetMousePosition() const { + return device_status.mouse_position_state; +} + +void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { + for (const std::pair poller_pair : callback_list) { + const InterfaceUpdateCallback& poller = poller_pair.second; + if (poller.on_change) { + poller.on_change(type); + } + } +} + +int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { + std::lock_guard lock{mutex}; + callback_list.insert_or_assign(last_callback_key, update_callback); + return last_callback_key++; +} + +void EmulatedDevices::DeleteCallback(int key) { + std::lock_guard lock{mutex}; + if (!callback_list.contains(key)) { + LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); + return; + } + callback_list.erase(key); +} +} // namespace Core::HID diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h new file mode 100644 index 000000000..6f728eff5 --- /dev/null +++ b/src/core/hid/emulated_devices.h @@ -0,0 +1,137 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/input.h" +#include "common/param_package.h" +#include "common/settings.h" +#include "core/hid/hid_types.h" +#include "core/hid/motion_input.h" + +namespace Core::HID { + +using KeyboardDevices = + std::array, Settings::NativeKeyboard::NumKeyboardKeys>; +using KeyboardModifierDevices = + std::array, Settings::NativeKeyboard::NumKeyboardMods>; +using MouseButtonDevices = + std::array, Settings::NativeMouseButton::NumMouseButtons>; + +using MouseButtonParams = + std::array; + +using KeyboardValues = std::array; +using KeyboardModifierValues = + std::array; +using MouseButtonValues = + std::array; + +struct MousePosition { + s32 x; + s32 y; + s32 delta_wheel_x; + s32 delta_wheel_y; +}; + +struct DeviceStatus { + // Data from input_common + KeyboardValues keyboard_values{}; + KeyboardModifierValues keyboard_moddifier_values{}; + MouseButtonValues mouse_button_values{}; + + // Data for Nintendo devices + KeyboardKey keyboard_state{}; + KeyboardModifier keyboard_moddifier_state{}; + MouseButton mouse_button_state{}; + MousePosition mouse_position_state{}; +}; + +enum class DeviceTriggerType { + Keyboard, + KeyboardModdifier, + Mouse, +}; + +struct InterfaceUpdateCallback { + std::function on_change; +}; + +class EmulatedDevices { +public: + /** + * TODO: Write description + * + * @param npad_id_type + */ + explicit EmulatedDevices(); + ~EmulatedDevices(); + + YUZU_NON_COPYABLE(EmulatedDevices); + YUZU_NON_MOVEABLE(EmulatedDevices); + + void ReloadFromSettings(); + void ReloadInput(); + void UnloadInput(); + + void EnableConfiguration(); + void DisableConfiguration(); + bool IsConfiguring() const; + void SaveCurrentConfig(); + void RestoreConfig(); + + std::vector GetMappedDevices() const; + + Common::ParamPackage GetMouseButtonParam(std::size_t index) const; + + void SetButtonParam(std::size_t index, Common::ParamPackage param); + + KeyboardValues GetKeyboardValues() const; + KeyboardModifierValues GetKeyboardModdifierValues() const; + MouseButtonValues GetMouseButtonsValues() const; + + KeyboardKey GetKeyboard() const; + KeyboardModifier GetKeyboardModifier() const; + MouseButton GetMouseButtons() const; + MousePosition GetMousePosition() const; + + int SetCallback(InterfaceUpdateCallback update_callback); + void DeleteCallback(int key); + +private: + /** + * Sets the status of a button. Applies toggle properties to the output. + * + * @param A CallbackStatus and a button index number + */ + void SetKeyboardButton(Input::CallbackStatus callback, std::size_t index); + void SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index); + void SetMouseButton(Input::CallbackStatus callback, std::size_t index); + + /** + * Triggers a callback that something has changed + * + * @param Input type of the trigger + */ + void TriggerOnChange(DeviceTriggerType type); + + bool is_configuring{false}; + + MouseButtonParams mouse_button_params; + + KeyboardDevices keyboard_devices; + KeyboardModifierDevices keyboard_modifier_devices; + MouseButtonDevices mouse_button_devices; + + mutable std::mutex mutex; + std::unordered_map callback_list; + int last_callback_key = 0; + DeviceStatus device_status; +}; + +} // namespace Core::HID diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp new file mode 100644 index 000000000..ee76db110 --- /dev/null +++ b/src/core/hid/hid_core.cpp @@ -0,0 +1,144 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/hid/hid_core.h" + +namespace Core::HID { + +HIDCore::HIDCore() + : player_1{std::make_unique(NpadIdType::Player1)}, + player_2{std::make_unique(NpadIdType::Player2)}, + player_3{std::make_unique(NpadIdType::Player3)}, + player_4{std::make_unique(NpadIdType::Player4)}, + player_5{std::make_unique(NpadIdType::Player5)}, + player_6{std::make_unique(NpadIdType::Player6)}, + player_7{std::make_unique(NpadIdType::Player7)}, + player_8{std::make_unique(NpadIdType::Player8)}, + other{std::make_unique(NpadIdType::Other)}, + handheld{std::make_unique(NpadIdType::Handheld)}, + console{std::make_unique()}, devices{std::make_unique()} {} + +HIDCore::~HIDCore() = default; + +EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) { + switch (npad_id_type) { + case NpadIdType::Player1: + return player_1.get(); + case NpadIdType::Player2: + return player_2.get(); + case NpadIdType::Player3: + return player_3.get(); + case NpadIdType::Player4: + return player_4.get(); + case NpadIdType::Player5: + return player_5.get(); + case NpadIdType::Player6: + return player_6.get(); + case NpadIdType::Player7: + return player_7.get(); + case NpadIdType::Player8: + return player_8.get(); + case NpadIdType::Other: + return other.get(); + case NpadIdType::Handheld: + return handheld.get(); + case NpadIdType::Invalid: + default: + UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type); + return nullptr; + } +} + +const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) const { + switch (npad_id_type) { + case NpadIdType::Player1: + return player_1.get(); + case NpadIdType::Player2: + return player_2.get(); + case NpadIdType::Player3: + return player_3.get(); + case NpadIdType::Player4: + return player_4.get(); + case NpadIdType::Player5: + return player_5.get(); + case NpadIdType::Player6: + return player_6.get(); + case NpadIdType::Player7: + return player_7.get(); + case NpadIdType::Player8: + return player_8.get(); + case NpadIdType::Other: + return other.get(); + case NpadIdType::Handheld: + return handheld.get(); + case NpadIdType::Invalid: + default: + UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type); + return nullptr; + } +} +EmulatedConsole* HIDCore::GetEmulatedConsole() { + return console.get(); +} + +const EmulatedConsole* HIDCore::GetEmulatedConsole() const { + return console.get(); +} + +EmulatedDevices* HIDCore::GetEmulatedDevices() { + return devices.get(); +} + +const EmulatedDevices* HIDCore::GetEmulatedDevices() const { + return devices.get(); +} + +EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) { + return GetEmulatedController(IndexToNpadIdType(index)); +} + +const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const { + return GetEmulatedController(IndexToNpadIdType(index)); +} + +void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) { + supported_style_tag.raw = style_tag.raw; +} + +NpadStyleTag HIDCore::GetSupportedStyleTag() const { + return supported_style_tag; +} + +void HIDCore::ReloadInputDevices() { + player_1->ReloadFromSettings(); + player_2->ReloadFromSettings(); + player_3->ReloadFromSettings(); + player_4->ReloadFromSettings(); + player_5->ReloadFromSettings(); + player_6->ReloadFromSettings(); + player_7->ReloadFromSettings(); + player_8->ReloadFromSettings(); + other->ReloadFromSettings(); + handheld->ReloadFromSettings(); + console->ReloadFromSettings(); + devices->ReloadFromSettings(); +} + +void HIDCore::UnloadInputDevices() { + player_1->UnloadInput(); + player_2->UnloadInput(); + player_3->UnloadInput(); + player_4->UnloadInput(); + player_5->UnloadInput(); + player_6->UnloadInput(); + player_7->UnloadInput(); + player_8->UnloadInput(); + other->UnloadInput(); + handheld->UnloadInput(); + console->UnloadInput(); + devices->UnloadInput(); +} + +} // namespace Core::HID diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h new file mode 100644 index 000000000..f11f48b61 --- /dev/null +++ b/src/core/hid/hid_core.h @@ -0,0 +1,60 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "core/hid/emulated_console.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/emulated_devices.h" + +namespace Core::HID { + +class HIDCore { +public: + explicit HIDCore(); + ~HIDCore(); + + YUZU_NON_COPYABLE(HIDCore); + YUZU_NON_MOVEABLE(HIDCore); + + EmulatedController* GetEmulatedController(NpadIdType npad_id_type); + const EmulatedController* GetEmulatedController(NpadIdType npad_id_type) const; + + EmulatedController* GetEmulatedControllerByIndex(std::size_t index); + const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const; + + EmulatedConsole* GetEmulatedConsole(); + const EmulatedConsole* GetEmulatedConsole() const; + + EmulatedDevices* GetEmulatedDevices(); + const EmulatedDevices* GetEmulatedDevices() const; + + void SetSupportedStyleTag(NpadStyleTag style_tag); + NpadStyleTag GetSupportedStyleTag() const; + + // Reloads all input devices from settings + void ReloadInputDevices(); + + // Removes all callbacks from input common + void UnloadInputDevices(); + +private: + std::unique_ptr player_1; + std::unique_ptr player_2; + std::unique_ptr player_3; + std::unique_ptr player_4; + std::unique_ptr player_5; + std::unique_ptr player_6; + std::unique_ptr player_7; + std::unique_ptr player_8; + std::unique_ptr other; + std::unique_ptr handheld; + std::unique_ptr console; + std::unique_ptr devices; + NpadStyleTag supported_style_tag; +}; + +} // namespace Core::HID From 967cca10ff5721cc942f557c3e0a20c07f5aa45e Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:44:34 -0500 Subject: [PATCH 066/291] core: Register HID --- src/core/core.cpp | 14 +++++++++++--- src/core/core.h | 10 ++++++++++ src/yuzu/main.cpp | 5 ++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 07448fd29..473ab9f81 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -27,6 +27,7 @@ #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" #include "core/hardware_interrupt_manager.h" +#include "core/hid/hid_core.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" @@ -126,7 +127,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, memory{system}, + : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} SystemResultStatus Run() { @@ -391,6 +392,7 @@ struct System::Impl { std::unique_ptr interrupt_manager; std::unique_ptr device_memory; Core::Memory::Memory memory; + Core::HID::HIDCore hid_core; CpuManager cpu_manager; std::atomic_bool is_powered_on{}; bool exit_lock = false; @@ -615,6 +617,14 @@ const Kernel::KernelCore& System::Kernel() const { return impl->kernel; } +HID::HIDCore& System::HIDCore() { + return impl->hid_core; +} + +const HID::HIDCore& System::HIDCore() const { + return impl->hid_core; +} + Timing::CoreTiming& System::CoreTiming() { return impl->core_timing; } @@ -825,8 +835,6 @@ void System::ApplySettings() { if (IsPoweredOn()) { Renderer().RefreshBaseSettings(); } - - Service::HID::ReloadInputDevices(); } } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 01bc0a2c7..5a031efb0 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -89,6 +89,10 @@ namespace Core::Hardware { class InterruptManager; } +namespace Core::HID { +class HIDCore; +} + namespace Core { class ARM_Interface; @@ -285,6 +289,12 @@ public: /// Provides a constant reference to the kernel instance. [[nodiscard]] const Kernel::KernelCore& Kernel() const; + /// Gets a mutable reference to the HID interface + [[nodiscard]] HID::HIDCore& HIDCore(); + + /// Gets an immutable reference to the HID interface. + [[nodiscard]] const HID::HIDCore& HIDCore() const; + /// Provides a reference to the internal PerfStats instance. [[nodiscard]] Core::PerfStats& GetPerfStats(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7f36f6e2f..19cb5313f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -26,6 +26,7 @@ #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/software_keyboard.h" +#include "core/hid/hid_core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -227,6 +228,8 @@ GMainWindow::GMainWindow() ConnectMenuEvents(); ConnectWidgetEvents(); + Core::System::GetInstance().HIDCore().ReloadInputDevices(); + const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); const auto build_id = std::string(Common::g_build_id); @@ -2969,7 +2972,7 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie QString GMainWindow::GetTasStateDescription() const { auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); switch (tas_status) { - case InputCommon::TasInput::TasState::Running: + case InputCommon::TasInput::TasState::Running : return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); case InputCommon::TasInput::TasState::Recording: return tr("TAS state: Recording %1").arg(total_tas_frames); From c405a19b73fa1e084918a2d39336363cd0f8b567 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:47:45 -0500 Subject: [PATCH 067/291] yuzu: Update frontend --- src/yuzu/configuration/config.cpp | 1 - src/yuzu/configuration/configure_input.cpp | 16 +- src/yuzu/configuration/configure_input.h | 3 +- .../configuration/configure_input_player.cpp | 928 +++++++----------- .../configuration/configure_input_player.h | 49 +- .../configuration/configure_input_player.ui | 10 - .../configure_input_player_widget.cpp | 597 ++++++----- .../configure_input_player_widget.h | 133 +-- .../configuration/configure_motion_touch.cpp | 4 +- .../configure_mouse_advanced.cpp | 57 +- .../configuration/configure_mouse_advanced.h | 8 +- .../configure_touch_from_button.cpp | 27 +- .../configure_touch_from_button.h | 5 - 13 files changed, 825 insertions(+), 1013 deletions(-) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 2b670ddfd..56af07507 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -11,7 +11,6 @@ #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" #include "input_common/main.h" -#include "input_common/udp/client.h" #include "yuzu/configuration/config.h" namespace FS = Common::FS; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 1599299db..61513865f 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -73,7 +73,7 @@ ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) ConfigureInput::~ConfigureInput() = default; -void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, +void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Core::System& system, std::size_t max_players) { player_controllers = { new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(), @@ -184,22 +184,8 @@ QList ConfigureInput::GetSubTabs() const { void ConfigureInput::ApplyConfiguration() { for (auto* controller : player_controllers) { controller->ApplyConfiguration(); - controller->TryDisconnectSelectedController(); } - // This emulates a delay between disconnecting and reconnecting controllers as some games - // do not respond to a change in controller type if it was instantaneous. - using namespace std::chrono_literals; - std::this_thread::sleep_for(150ms); - - for (auto* controller : player_controllers) { - controller->TryConnectSelectedController(); - } - - // This emulates a delay between disconnecting and reconnecting controllers as some games - // do not respond to a change in controller type if it was instantaneous. - std::this_thread::sleep_for(150ms); - advanced->ApplyConfiguration(); const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 4cafa3dab..6e5edad58 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -42,7 +42,8 @@ public: ~ConfigureInput() override; /// Initializes the input dialog with the given input subsystem. - void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8); + void Initialize(InputCommon::InputSubsystem* input_subsystem_, Core::System& system, + std::size_t max_players = 8); /// Save all button configurations to settings file. void ApplyConfiguration(); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 09f0b219b..adc9706f1 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -13,9 +13,11 @@ #include #include "common/param_package.h" #include "core/core.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" #include "input_common/main.h" #include "ui_configure_input_player.h" #include "yuzu/bootmanager.h" @@ -26,8 +28,6 @@ #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" -using namespace Service::HID; - const std::array ConfigureInputPlayer::analog_sub_buttons{{ "up", @@ -40,31 +40,8 @@ namespace { constexpr std::size_t HANDHELD_INDEX = 8; -void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, - bool connected, Core::System& system) { - if (!system.IsPoweredOn()) { - return; - } - Service::SM::ServiceManager& sm = system.ServiceManager(); - - auto& npad = sm.GetService("hid")->GetAppletResource()->GetController( - HidController::NPad); - - npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); -} - QString GetKeyName(int key_code) { switch (key_code) { - case Qt::LeftButton: - return QObject::tr("Click 0"); - case Qt::RightButton: - return QObject::tr("Click 1"); - case Qt::MiddleButton: - return QObject::tr("Click 2"); - case Qt::BackButton: - return QObject::tr("Click 3"); - case Qt::ForwardButton: - return QObject::tr("Click 4"); case Qt::Key_Shift: return QObject::tr("Shift"); case Qt::Key_Control: @@ -94,95 +71,26 @@ void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackag } analog_param.Set(button_name, input_param.Serialize()); } +} // namespace -QString ButtonToText(const Common::ParamPackage& param) { +QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } + // Retrieve the names from Qt if (param.Get("engine", "") == "keyboard") { const QString button_str = GetKeyName(param.Get("code", 0)); const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); return QObject::tr("%1%2").arg(toggle, button_str); } - if (param.Get("engine", "") == "gcpad") { - if (param.Has("axis")) { - const QString axis_str = QString::fromStdString(param.Get("axis", "")); - const QString direction_str = QString::fromStdString(param.Get("direction", "")); - - return QObject::tr("GC Axis %1%2").arg(axis_str, direction_str); - } - if (param.Has("button")) { - const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); - return QObject::tr("GC Button %1").arg(button_str); - } - return GetKeyName(param.Get("code", 0)); - } - - if (param.Get("engine", "") == "tas") { - if (param.Has("axis")) { - const QString axis_str = QString::fromStdString(param.Get("axis", "")); - - return QObject::tr("TAS Axis %1").arg(axis_str); - } - if (param.Has("button")) { - const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); - return QObject::tr("TAS Btn %1").arg(button_str); - } - return GetKeyName(param.Get("code", 0)); - } - - if (param.Get("engine", "") == "cemuhookudp") { - if (param.Has("pad_index")) { - const QString motion_str = QString::fromStdString(param.Get("pad_index", "")); - return QObject::tr("Motion %1").arg(motion_str); - } - return GetKeyName(param.Get("code", 0)); - } - - if (param.Get("engine", "") == "sdl") { - if (param.Has("hat")) { - const QString hat_str = QString::fromStdString(param.Get("hat", "")); - const QString direction_str = QString::fromStdString(param.Get("direction", "")); - - return QObject::tr("Hat %1 %2").arg(hat_str, direction_str); - } - - if (param.Has("axis")) { - const QString axis_str = QString::fromStdString(param.Get("axis", "")); - const QString direction_str = QString::fromStdString(param.Get("direction", "")); - - return QObject::tr("Axis %1%2").arg(axis_str, direction_str); - } - - if (param.Has("button")) { - const QString button_str = QString::fromStdString(param.Get("button", "")); - const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); - - return QObject::tr("%1Button %2").arg(toggle, button_str); - } - - if (param.Has("motion")) { - return QObject::tr("SDL Motion"); - } - - return {}; - } - - if (param.Get("engine", "") == "mouse") { - if (param.Has("button")) { - const QString button_str = QString::number(int(param.Get("button", 0))); - const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); - return QObject::tr("%1Click %2").arg(toggle, button_str); - } - return GetKeyName(param.Get("code", 0)); - } - - return QObject::tr("[unknown]"); + std::string button_name = input_subsystem->GetButtonName(param); + return QString::fromStdString(button_name); } -QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { +QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, + const std::string& dir) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } @@ -191,39 +99,39 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); } + if (!param.Has("axis_x") || !param.Has("axis_y")) { + return QObject::tr("[unknown]"); + } + const auto engine_str = param.Get("engine", ""); const QString axis_x_str = QString::fromStdString(param.Get("axis_x", "")); const QString axis_y_str = QString::fromStdString(param.Get("axis_y", "")); const bool invert_x = param.Get("invert_x", "+") == "-"; const bool invert_y = param.Get("invert_y", "+") == "-"; - if (engine_str == "sdl" || engine_str == "gcpad" || engine_str == "mouse" || - engine_str == "tas") { - if (dir == "modifier") { - return QObject::tr("[unused]"); - } - if (dir == "left") { - const QString invert_x_str = QString::fromStdString(invert_x ? "+" : "-"); - return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); - } - if (dir == "right") { - const QString invert_x_str = QString::fromStdString(invert_x ? "-" : "+"); - return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); - } - if (dir == "up") { - const QString invert_y_str = QString::fromStdString(invert_y ? "-" : "+"); - return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); - } - if (dir == "down") { - const QString invert_y_str = QString::fromStdString(invert_y ? "+" : "-"); - return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); - } - - return {}; + if (dir == "modifier") { + return QObject::tr("[unused]"); } + + if (dir == "left") { + const QString invert_x_str = QString::fromStdString(invert_x ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "right") { + const QString invert_x_str = QString::fromStdString(invert_x ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "up") { + const QString invert_y_str = QString::fromStdString(invert_y ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } + if (dir == "down") { + const QString invert_y_str = QString::fromStdString(invert_y ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } + return QObject::tr("[unknown]"); } -} // namespace ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, @@ -234,6 +142,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_), timeout_timer(std::make_unique()), poll_timer(std::make_unique()), bottom_row(bottom_row), system{system_} { + + emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index); + emulated_controller->EnableConfiguration(); ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); @@ -275,31 +186,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; - const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id, - Common::ParamPackage* param, int default_val, - InputCommon::Polling::DeviceType type) { - connect(button, &QPushButton::clicked, [=, this] { - HandleClick( - button, button_id, - [=, this](Common::ParamPackage params) { - // Workaround for ZL & ZR for analog triggers like on XBOX - // controllers. Analog triggers (from controllers like the XBOX - // controller) would not work due to a different range of their - // signals (from 0 to 255 on analog triggers instead of -32768 to - // 32768 on analog joysticks). The SDL driver misinterprets analog - // triggers as analog joysticks. - // TODO: reinterpret the signal range for analog triggers to map the - // values correctly. This is required for the correct emulation of - // the analog triggers of the GameCube controller. - if (button == ui->buttonZL || button == ui->buttonZR) { - params.Set("direction", "+"); - params.Set("threshold", "0.5"); - } - *param = std::move(params); - }, - type); - }); - }; + ui->controllerFrame->SetController(emulated_controller); for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { auto* const button = button_map[button_id]; @@ -308,34 +195,52 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id], - Config::default_buttons[button_id], - InputCommon::Polling::DeviceType::Button); + connect(button, &QPushButton::clicked, [=, this] { + HandleClick( + button, button_id, + [=, this](Common::ParamPackage params) { + emulated_controller->SetButtonParam(button_id, params); + }, + InputCommon::Polling::InputType::Button); + }); button->setContextMenuPolicy(Qt::CustomContextMenu); connect(button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; + Common::ParamPackage param = emulated_controller->GetButtonParam(button_id); context_menu.addAction(tr("Clear"), [&] { - buttons_param[button_id].Clear(); + emulated_controller->SetButtonParam(button_id, {}); button_map[button_id]->setText(tr("[not set]")); }); - if (buttons_param[button_id].Has("toggle")) { + if (param.Has("button") || param.Has("hat")) { context_menu.addAction(tr("Toggle button"), [&] { - const bool toggle_value = - !buttons_param[button_id].Get("toggle", false); - buttons_param[button_id].Set("toggle", toggle_value); - button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); + const bool toggle_value = !param.Get("toggle", false); + param.Set("toggle", toggle_value); + button_map[button_id]->setText(ButtonToText(param)); + emulated_controller->SetButtonParam(button_id, param); + }); + context_menu.addAction(tr("Invert button"), [&] { + const bool toggle_value = !param.Get("inverted", false); + param.Set("inverted", toggle_value); + button_map[button_id]->setText(ButtonToText(param)); + emulated_controller->SetButtonParam(button_id, param); }); } - if (buttons_param[button_id].Has("threshold")) { + if (param.Has("axis")) { + context_menu.addAction(tr("Invert axis"), [&] { + const bool toggle_value = !(param.Get("invert", "+") == "-"); + param.Set("invert", toggle_value ? "-" : "+"); + button_map[button_id]->setText(ButtonToText(param)); + emulated_controller->SetButtonParam(button_id, param); + }); context_menu.addAction(tr("Set threshold"), [&] { - const int button_threshold = static_cast( - buttons_param[button_id].Get("threshold", 0.5f) * 100.0f); + const int button_threshold = + static_cast(param.Get("threshold", 0.5f) * 100.0f); const int new_threshold = QInputDialog::getInt( this, tr("Set threshold"), tr("Choose a value between 0% and 100%"), button_threshold, 0, 100); - buttons_param[button_id].Set("threshold", new_threshold / 100.0f); + param.Set("threshold", new_threshold / 100.0f); if (button_id == Settings::NativeButton::ZL) { ui->sliderZLThreshold->setValue(new_threshold); @@ -343,11 +248,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (button_id == Settings::NativeButton::ZR) { ui->sliderZRThreshold->setValue(new_threshold); } + emulated_controller->SetButtonParam(button_id, param); }); } - context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); } @@ -357,9 +261,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id], - Config::default_motions[motion_id], - InputCommon::Polling::DeviceType::Motion); + connect(button, &QPushButton::clicked, [=, this] { + HandleClick( + button, motion_id, + [=, this](Common::ParamPackage params) { + emulated_controller->SetMotionParam(motion_id, params); + }, + InputCommon::Polling::InputType::Motion); + }); button->setContextMenuPolicy(Qt::CustomContextMenu); @@ -367,7 +276,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i [=, this](const QPoint& menu_location) { QMenu context_menu; context_menu.addAction(tr("Clear"), [&] { - motions_param[motion_id].Clear(); + emulated_controller->SetMotionParam(motion_id, {}); motion_map[motion_id]->setText(tr("[not set]")); }); context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location)); @@ -375,16 +284,22 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] { - if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { + Common::ParamPackage param = + emulated_controller->GetButtonParam(Settings::NativeButton::ZL); + if (param.Has("threshold")) { const auto slider_value = ui->sliderZLThreshold->value(); - buttons_param[Settings::NativeButton::ZL].Set("threshold", slider_value / 100.0f); + param.Set("threshold", slider_value / 100.0f); + emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param); } }); connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] { - if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { + Common::ParamPackage param = + emulated_controller->GetButtonParam(Settings::NativeButton::ZR); + if (param.Has("threshold")) { const auto slider_value = ui->sliderZRThreshold->value(); - buttons_param[Settings::NativeButton::ZR].Set("threshold", slider_value / 100.0f); + param.Set("threshold", slider_value / 100.0f); + emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param); } }); @@ -412,45 +327,45 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i HandleClick( analog_map_buttons[analog_id][sub_button_id], analog_id, [=, this](const Common::ParamPackage& params) { - SetAnalogParam(params, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); + SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]); + emulated_controller->SetStickParam(analog_id, param); }, - InputCommon::Polling::DeviceType::AnalogPreferred); + InputCommon::Polling::InputType::Stick); }); analog_button->setContextMenuPolicy(Qt::CustomContextMenu); - connect( - analog_button, &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - analogs_param[analog_id].Clear(); - analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); + connect(analog_button, &QPushButton::customContextMenuRequested, + [=, this](const QPoint& menu_location) { + QMenu context_menu; + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); + context_menu.addAction(tr("Clear"), [&] { + emulated_controller->SetStickParam(analog_id, {}); + analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); + }); + context_menu.addAction(tr("Invert axis"), [&] { + if (sub_button_id == 2 || sub_button_id == 3) { + const bool invert_value = param.Get("invert_x", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + param.Set("invert_x", invert_str); + emulated_controller->SetStickParam(analog_id, param); + } + if (sub_button_id == 0 || sub_button_id == 1) { + const bool invert_value = param.Get("invert_y", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + param.Set("invert_y", invert_str); + emulated_controller->SetStickParam(analog_id, param); + } + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; + ++sub_button_id) { + analog_map_buttons[analog_id][sub_button_id]->setText( + AnalogToText(param, analog_sub_buttons[sub_button_id])); + } + }); + context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( + menu_location)); }); - context_menu.addAction(tr("Invert axis"), [&] { - if (sub_button_id == 2 || sub_button_id == 3) { - const bool invert_value = - analogs_param[analog_id].Get("invert_x", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - analogs_param[analog_id].Set("invert_x", invert_str); - } - if (sub_button_id == 0 || sub_button_id == 1) { - const bool invert_value = - analogs_param[analog_id].Get("invert_y", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - analogs_param[analog_id].Set("invert_y", invert_str); - } - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; - ++sub_button_id) { - analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( - analogs_param[analog_id], analog_sub_buttons[sub_button_id])); - } - }); - context_menu.exec( - analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location)); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); - }); } // Handle clicks for the modifier buttons as well. @@ -458,9 +373,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i HandleClick( analog_map_modifier_button[analog_id], analog_id, [=, this](const Common::ParamPackage& params) { - analogs_param[analog_id].Set("modifier", params.Serialize()); + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); + param.Set("modifier", params.Serialize()); + emulated_controller->SetStickParam(analog_id, param); }, - InputCommon::Polling::DeviceType::Button); + InputCommon::Polling::InputType::Button); }); analog_map_modifier_button[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu); @@ -468,18 +385,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); context_menu.addAction(tr("Clear"), [&] { - analogs_param[analog_id].Set("modifier", ""); + param.Set("modifier", ""); analog_map_modifier_button[analog_id]->setText(tr("[not set]")); + emulated_controller->SetStickParam(analog_id, param); }); context_menu.addAction(tr("Toggle button"), [&] { Common::ParamPackage modifier_param = - Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")}; + Common::ParamPackage{param.Get("modifier", "")}; const bool toggle_value = !modifier_param.Get("toggle", false); modifier_param.Set("toggle", toggle_value); - analogs_param[analog_id].Set("modifier", modifier_param.Serialize()); + param.Set("modifier", modifier_param.Serialize()); analog_map_modifier_button[analog_id]->setText( ButtonToText(modifier_param)); + emulated_controller->SetStickParam(analog_id, param); }); context_menu.exec( analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); @@ -487,37 +407,39 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(analog_map_range_spinbox[analog_id], qOverload(&QSpinBox::valueChanged), [=, this] { + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); - analogs_param[analog_id].Set("range", spinbox_value / 100.0f); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); + param.Set("range", spinbox_value / 100.0f); + emulated_controller->SetStickParam(analog_id, param); }); connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); - analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); + param.Set("deadzone", slider_value / 100.0f); + emulated_controller->SetStickParam(analog_id, param); }); connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto slider_value = analog_map_modifier_slider[analog_id]->value(); analog_map_modifier_label[analog_id]->setText( tr("Modifier Range: %1%").arg(slider_value)); - analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); + param.Set("modifier_scale", slider_value / 100.0f); + emulated_controller->SetStickParam(analog_id, param); }); } // Player Connected checkbox - connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { - emit Connected(checked); - ui->controllerFrame->SetConnectedStatus(checked); - }); + connect(ui->groupConnectedController, &QGroupBox::toggled, + [this](bool checked) { emit Connected(checked); }); if (player_index == 0) { connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int index) { emit HandheldStateChanged(GetControllerTypeFromIndex(index) == - Settings::ControllerType::Handheld); + Core::HID::NpadType::Handheld); }); } @@ -534,13 +456,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i SetConnectableControllers(); } - UpdateControllerIcon(); UpdateControllerAvailableButtons(); UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int) { - UpdateControllerIcon(); UpdateControllerAvailableButtons(); UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); @@ -560,13 +480,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this] { - Common::ParamPackage params; - for (auto& poller : device_pollers) { - params = poller->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; - } + const auto& params = input_subsystem->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; } }); @@ -582,110 +499,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i &ConfigureInputPlayer::SaveProfile); LoadConfiguration(); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); - ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked()); } -ConfigureInputPlayer::~ConfigureInputPlayer() = default; +ConfigureInputPlayer::~ConfigureInputPlayer() { + emulated_controller->DisableConfiguration(); +}; void ConfigureInputPlayer::ApplyConfiguration() { - auto& player = Settings::values.players.GetValue()[player_index]; - auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons; - auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs; - - std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); - std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); - - if (debug) { - return; - } - - auto& motions = player.motions; - - std::transform(motions_param.begin(), motions_param.end(), motions.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); - - // Apply configuration for handheld - if (player_index == 0) { - auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; - const auto handheld_connected = handheld.connected; - handheld = player; - handheld.connected = handheld_connected; - } -} - -void ConfigureInputPlayer::TryConnectSelectedController() { - auto& player = Settings::values.players.GetValue()[player_index]; - - const auto controller_type = - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); - const auto player_connected = ui->groupConnectedController->isChecked() && - controller_type != Settings::ControllerType::Handheld; - - // Connect Handheld depending on Player 1's controller configuration. - if (player_index == 0) { - auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; - const auto handheld_connected = ui->groupConnectedController->isChecked() && - controller_type == Settings::ControllerType::Handheld; - // Connect only if handheld is going from disconnected to connected - if (!handheld.connected && handheld_connected) { - UpdateController(controller_type, HANDHELD_INDEX, true, system); - } - handheld.connected = handheld_connected; - } - - if (player.controller_type == controller_type && player.connected == player_connected) { - // Set vibration devices in the event that the input device has changed. - ConfigureVibration::SetVibrationDevices(player_index); - return; - } - - player.controller_type = controller_type; - player.connected = player_connected; - - ConfigureVibration::SetVibrationDevices(player_index); - - if (!player.connected) { - return; - } - - UpdateController(controller_type, player_index, true, system); -} - -void ConfigureInputPlayer::TryDisconnectSelectedController() { - const auto& player = Settings::values.players.GetValue()[player_index]; - - const auto controller_type = - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); - const auto player_connected = ui->groupConnectedController->isChecked() && - controller_type != Settings::ControllerType::Handheld; - - // Disconnect Handheld depending on Player 1's controller configuration. - if (player_index == 0 && player.controller_type == Settings::ControllerType::Handheld) { - const auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; - const auto handheld_connected = ui->groupConnectedController->isChecked() && - controller_type == Settings::ControllerType::Handheld; - // Disconnect only if handheld is going from connected to disconnected - if (handheld.connected && !handheld_connected) { - UpdateController(controller_type, HANDHELD_INDEX, false, system); - } - return; - } - - // Do not do anything if the controller configuration has not changed. - if (player.controller_type == controller_type && player.connected == player_connected) { - return; - } - - // Do not disconnect if the controller is already disconnected - if (!player.connected) { - return; - } - - // Disconnect the controller first. - UpdateController(controller_type, player_index, false, system); + emulated_controller->SaveCurrentConfig(); } void ConfigureInputPlayer::showEvent(QShowEvent* event) { @@ -710,34 +531,11 @@ void ConfigureInputPlayer::RetranslateUI() { } void ConfigureInputPlayer::LoadConfiguration() { - auto& player = Settings::values.players.GetValue()[player_index]; - if (debug) { - std::transform(Settings::values.debug_pad_buttons.begin(), - Settings::values.debug_pad_buttons.end(), buttons_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - std::transform(Settings::values.debug_pad_analogs.begin(), - Settings::values.debug_pad_analogs.end(), analogs_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - } else { - std::transform(player.buttons.begin(), player.buttons.end(), buttons_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - std::transform(player.motions.begin(), player.motions.end(), motions_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - } - UpdateUI(); UpdateInputDeviceCombobox(); - - if (debug) { - return; - } - - ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type)); - ui->groupConnectedController->setChecked( - player.connected || - (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); + const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType()); + ui->comboControllerType->setCurrentIndex(comboBoxIndex); + ui->groupConnectedController->setChecked(emulated_controller->IsConnected()); } void ConfigureInputPlayer::ConnectPlayer(bool connected) { @@ -751,48 +549,63 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { return; } - // Find the first button that isn't empty. - const auto button_param = - std::find_if(buttons_param.begin(), buttons_param.end(), - [](const Common::ParamPackage param) { return param.Has("engine"); }); - const bool buttons_empty = button_param == buttons_param.end(); - - const auto current_engine = button_param->Get("engine", ""); - const auto current_guid = button_param->Get("guid", ""); - const auto current_port = button_param->Get("port", ""); - - const bool is_keyboard_mouse = current_engine == "keyboard" || current_engine == "mouse"; - + const auto devices = emulated_controller->GetMappedDevices(); UpdateInputDevices(); - if (buttons_empty) { + if (devices.empty()) { return; } - const bool all_one_device = - std::all_of(buttons_param.begin(), buttons_param.end(), - [current_engine, current_guid, current_port, - is_keyboard_mouse](const Common::ParamPackage param) { - if (is_keyboard_mouse) { - return !param.Has("engine") || param.Get("engine", "") == "keyboard" || - param.Get("engine", "") == "mouse"; - } - return !param.Has("engine") || (param.Get("engine", "") == current_engine && - param.Get("guid", "") == current_guid && - param.Get("port", "") == current_port); - }); + if (devices.size() > 2) { + ui->comboDevices->setCurrentIndex(0); + return; + } - if (all_one_device) { - if (is_keyboard_mouse) { - ui->comboDevices->setCurrentIndex(1); - return; - } + const auto first_engine = devices[0].Get("engine", ""); + const auto first_guid = devices[0].Get("guid", ""); + const auto first_port = devices[0].Get("port", ""); + + if (devices.size() == 1) { + const auto devices_it = + std::find_if(input_devices.begin(), input_devices.end(), + [first_engine, first_guid, first_port](const Common::ParamPackage param) { + return param.Get("engine", "") == first_engine && + param.Get("guid", "") == first_guid && + param.Get("port", "") == first_port; + }); + const int device_index = + devices_it != input_devices.end() + ? static_cast(std::distance(input_devices.begin(), devices_it)) + : 0; + ui->comboDevices->setCurrentIndex(device_index); + return; + } + + const auto second_engine = devices[1].Get("engine", ""); + const auto second_guid = devices[1].Get("guid", ""); + const auto second_port = devices[1].Get("port", ""); + + const bool is_keyboard_mouse = (first_engine == "keyboard" || first_engine == "mouse") && + (second_engine == "keyboard" || second_engine == "mouse"); + + if (is_keyboard_mouse) { + ui->comboDevices->setCurrentIndex(2); + return; + } + + const bool is_engine_equal = first_engine == second_engine; + const bool is_port_equal = first_port == second_port; + + if (is_engine_equal && is_port_equal) { const auto devices_it = std::find_if( input_devices.begin(), input_devices.end(), - [current_engine, current_guid, current_port](const Common::ParamPackage param) { - return param.Get("class", "") == current_engine && - param.Get("guid", "") == current_guid && - param.Get("port", "") == current_port; + [first_engine, first_guid, second_guid, first_port](const Common::ParamPackage param) { + const bool is_guid_valid = + (param.Get("guid", "") == first_guid && + param.Get("guid2", "") == second_guid) || + (param.Get("guid", "") == second_guid && param.Get("guid2", "") == first_guid); + return param.Get("engine", "") == first_engine && is_guid_valid && + param.Get("port", "") == first_port; }); const int device_index = devices_it != input_devices.end() @@ -814,8 +627,7 @@ void ConfigureInputPlayer::ClearAll() { if (button == nullptr) { continue; } - - buttons_param[button_id].Clear(); + emulated_controller->SetButtonParam(button_id, {}); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { @@ -824,8 +636,7 @@ void ConfigureInputPlayer::ClearAll() { if (analog_button == nullptr) { continue; } - - analogs_param[analog_id].Clear(); + emulated_controller->SetStickParam(analog_id, {}); } } @@ -834,8 +645,7 @@ void ConfigureInputPlayer::ClearAll() { if (motion_button == nullptr) { continue; } - - motions_param[motion_id].Clear(); + emulated_controller->SetMotionParam(motion_id, {}); } UpdateUI(); @@ -844,26 +654,31 @@ void ConfigureInputPlayer::ClearAll() { void ConfigureInputPlayer::UpdateUI() { for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) { - button_map[button]->setText(ButtonToText(buttons_param[button])); + const Common::ParamPackage param = emulated_controller->GetButtonParam(button); + button_map[button]->setText(ButtonToText(param)); } - if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { - const int button_threshold = static_cast( - buttons_param[Settings::NativeButton::ZL].Get("threshold", 0.5f) * 100.0f); + const Common::ParamPackage ZL_param = + emulated_controller->GetButtonParam(Settings::NativeButton::ZL); + if (ZL_param.Has("threshold")) { + const int button_threshold = static_cast(ZL_param.Get("threshold", 0.5f) * 100.0f); ui->sliderZLThreshold->setValue(button_threshold); } - if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { - const int button_threshold = static_cast( - buttons_param[Settings::NativeButton::ZR].Get("threshold", 0.5f) * 100.0f); + const Common::ParamPackage ZR_param = + emulated_controller->GetButtonParam(Settings::NativeButton::ZR); + if (ZR_param.Has("threshold")) { + const int button_threshold = static_cast(ZR_param.Get("threshold", 0.5f) * 100.0f); ui->sliderZRThreshold->setValue(button_threshold); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id])); + const Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id); + motion_map[motion_id]->setText(ButtonToText(param)); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { + const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; @@ -871,12 +686,11 @@ void ConfigureInputPlayer::UpdateUI() { continue; } - analog_button->setText( - AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); + analog_button->setText(AnalogToText(param, analog_sub_buttons[sub_button_id])); } analog_map_modifier_button[analog_id]->setText( - ButtonToText(Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")})); + ButtonToText(Common::ParamPackage{param.Get("modifier", "")})); const auto deadzone_label = analog_map_deadzone_label[analog_id]; const auto deadzone_slider = analog_map_deadzone_slider[analog_id]; @@ -887,26 +701,14 @@ void ConfigureInputPlayer::UpdateUI() { const auto range_spinbox = analog_map_range_spinbox[analog_id]; int slider_value; - auto& param = analogs_param[analog_id]; - const bool is_controller = - param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad" || - param.Get("engine", "") == "mouse" || param.Get("engine", "") == "tas"; + const bool is_controller = input_subsystem->IsController(param); if (is_controller) { - if (!param.Has("deadzone")) { - param.Set("deadzone", 0.1f); - } - slider_value = static_cast(param.Get("deadzone", 0.1f) * 100); + slider_value = static_cast(param.Get("deadzone", 0.15f) * 100); deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value)); deadzone_slider->setValue(slider_value); - if (!param.Has("range")) { - param.Set("range", 1.0f); - } range_spinbox->setValue(static_cast(param.Get("range", 1.0f) * 100)); } else { - if (!param.Has("modifier_scale")) { - param.Set("modifier_scale", 0.5f); - } slider_value = static_cast(param.Get("modifier_scale", 0.5f) * 100); modifier_label->setText(tr("Modifier Range: %1%").arg(slider_value)); modifier_slider->setValue(slider_value); @@ -918,49 +720,48 @@ void ConfigureInputPlayer::UpdateUI() { modifier_label->setVisible(!is_controller); modifier_slider->setVisible(!is_controller); range_groupbox->setVisible(is_controller); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); } } void ConfigureInputPlayer::SetConnectableControllers() { const auto add_controllers = [this](bool enable_all, - Controller_NPad::NpadStyleSet npad_style_set = {}) { + Core::HID::NpadStyleTag npad_style_set = {}) { index_controller_type_pairs.clear(); ui->comboControllerType->clear(); if (enable_all || npad_style_set.fullkey == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::ProController); + Core::HID::NpadType::ProController); ui->comboControllerType->addItem(tr("Pro Controller")); } if (enable_all || npad_style_set.joycon_dual == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::DualJoyconDetached); + Core::HID::NpadType::JoyconDual); ui->comboControllerType->addItem(tr("Dual Joycons")); } if (enable_all || npad_style_set.joycon_left == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::LeftJoycon); + Core::HID::NpadType::JoyconLeft); ui->comboControllerType->addItem(tr("Left Joycon")); } if (enable_all || npad_style_set.joycon_right == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::RightJoycon); + Core::HID::NpadType::JoyconRight); ui->comboControllerType->addItem(tr("Right Joycon")); } if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::Handheld); + Core::HID::NpadType::Handheld); ui->comboControllerType->addItem(tr("Handheld")); } if (enable_all || npad_style_set.gamecube == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Settings::ControllerType::GameCube); + Core::HID::NpadType::GameCube); ui->comboControllerType->addItem(tr("GameCube Controller")); } }; @@ -970,27 +771,22 @@ void ConfigureInputPlayer::SetConnectableControllers() { return; } - Service::SM::ServiceManager& sm = system.ServiceManager(); - - auto& npad = sm.GetService("hid")->GetAppletResource()->GetController( - HidController::NPad); - - add_controllers(false, npad.GetSupportedStyleSet()); + add_controllers(false, system.HIDCore().GetSupportedStyleTag()); } -Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { +Core::HID::NpadType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [index](const auto& pair) { return pair.first == index; }); if (it == index_controller_type_pairs.end()) { - return Settings::ControllerType::ProController; + return Core::HID::NpadType::ProController; } return it->second; } -int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const { +int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadType type) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [type](const auto& pair) { return pair.second == type; }); @@ -1005,52 +801,15 @@ int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType ty void ConfigureInputPlayer::UpdateInputDevices() { input_devices = input_subsystem->GetInputDevices(); ui->comboDevices->clear(); - for (auto& device : input_devices) { - const std::string display = device.Get("display", "Unknown"); - ui->comboDevices->addItem(QString::fromStdString(display), {}); - if (display == "TAS") { - device.Set("pad", static_cast(player_index)); - } + for (auto device : input_devices) { + ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); } } -void ConfigureInputPlayer::UpdateControllerIcon() { - // We aren't using Qt's built in theme support here since we aren't drawing an icon (and its - // "nonstandard" to use an image through the icon support) - const QString stylesheet = [this] { - switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { - case Settings::ControllerType::ProController: - return QStringLiteral("image: url(:/controller/pro_controller%0)"); - case Settings::ControllerType::DualJoyconDetached: - return QStringLiteral("image: url(:/controller/dual_joycon%0)"); - case Settings::ControllerType::LeftJoycon: - return QStringLiteral("image: url(:/controller/single_joycon_left_vertical%0)"); - case Settings::ControllerType::RightJoycon: - return QStringLiteral("image: url(:/controller/single_joycon_right_vertical%0)"); - case Settings::ControllerType::Handheld: - return QStringLiteral("image: url(:/controller/handheld%0)"); - default: - return QString{}; - } - }(); - - const QString theme = [] { - if (QIcon::themeName().contains(QStringLiteral("dark"))) { - return QStringLiteral("_dark"); - } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { - return QStringLiteral("_midnight"); - } else { - return QString{}; - } - }(); - ui->controllerFrame->SetControllerType( - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); -} - void ConfigureInputPlayer::UpdateControllerAvailableButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Settings::ControllerType::ProController; + layout = Core::HID::NpadType::ProController; } // List of all the widgets that will be hidden by any of the following layouts that need @@ -1075,15 +834,15 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { std::vector layout_hidden; switch (layout) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::DualJoyconDetached: - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadType::Handheld: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, }; break; - case Settings::ControllerType::LeftJoycon: + case Core::HID::NpadType::JoyconLeft: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget2, ui->buttonShoulderButtonsRight, @@ -1091,7 +850,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomRight, }; break; - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget, ui->buttonShoulderButtonsLeft, @@ -1099,7 +858,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomLeft, }; break; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, @@ -1107,6 +866,8 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->buttonMiscButtonsScreenshotGroup, }; break; + default: + break; } for (auto* widget : layout_hidden) { @@ -1117,13 +878,12 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { void ConfigureInputPlayer::UpdateControllerEnabledButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Settings::ControllerType::ProController; + layout = Core::HID::NpadType::ProController; } // List of all the widgets that will be disabled by any of the following layouts that need // "enabled" after the controller type changes - const std::array layout_enable = { - ui->buttonHome, + const std::array layout_enable = { ui->buttonLStickPressedGroup, ui->groupRStickPressed, ui->buttonShoulderButtonsButtonLGroup, @@ -1135,17 +895,13 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { std::vector layout_disable; switch (layout) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::DualJoyconDetached: - case Settings::ControllerType::Handheld: - case Settings::ControllerType::LeftJoycon: - case Settings::ControllerType::RightJoycon: - // TODO(wwylele): enable this when we actually emulate it - layout_disable = { - ui->buttonHome, - }; + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadType::Handheld: + case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadType::JoyconRight: break; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: layout_disable = { ui->buttonHome, ui->buttonLStickPressedGroup, @@ -1153,6 +909,8 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { ui->buttonShoulderButtonsButtonLGroup, }; break; + default: + break; } for (auto* widget : layout_disable) { @@ -1170,24 +928,24 @@ void ConfigureInputPlayer::UpdateMotionButtons() { // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::LeftJoycon: - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadType::Handheld: // Show "Motion 1" and hide "Motion 2". ui->buttonMotionLeftGroup->show(); ui->buttonMotionRightGroup->hide(); break; - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: // Show "Motion 2" and hide "Motion 1". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->show(); break; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: // Hide both "Motion 1/2". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->hide(); break; - case Settings::ControllerType::DualJoyconDetached: + case Core::HID::NpadType::JoyconDual: default: // Show both "Motion 1/2". ui->buttonMotionLeftGroup->show(); @@ -1199,15 +957,15 @@ void ConfigureInputPlayer::UpdateMotionButtons() { void ConfigureInputPlayer::UpdateControllerButtonNames() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Settings::ControllerType::ProController; + layout = Core::HID::NpadType::ProController; } switch (layout) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::DualJoyconDetached: - case Settings::ControllerType::Handheld: - case Settings::ControllerType::LeftJoycon: - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadType::Handheld: + case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadType::JoyconRight: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Plus")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("ZL")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("ZR")); @@ -1215,7 +973,7 @@ void ConfigureInputPlayer::UpdateControllerButtonNames() { ui->LStick->setTitle(tr("Left Stick")); ui->RStick->setTitle(tr("Right Stick")); break; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Start / Pause")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("L")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("R")); @@ -1223,6 +981,8 @@ void ConfigureInputPlayer::UpdateControllerButtonNames() { ui->LStick->setTitle(tr("Control Stick")); ui->RStick->setTitle(tr("C-Stick")); break; + default: + break; } } @@ -1231,26 +991,93 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { return; } + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { + const auto* const button = button_map[button_id]; + if (button == nullptr) { + continue; + } + emulated_controller->SetButtonParam(button_id, {}); + } + + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { + const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; + if (analog_button == nullptr) { + continue; + } + emulated_controller->SetStickParam(analog_id, {}); + } + } + + for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { + const auto* const motion_button = motion_map[motion_id]; + if (motion_button == nullptr) { + continue; + } + emulated_controller->SetMotionParam(motion_id, {}); + } + + // Reset keyboard bindings if (ui->comboDevices->currentIndex() == 1) { - // Reset keyboard bindings for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; + emulated_controller->SetButtonParam( + button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( + Config::default_buttons[button_id])}); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { + Common::ParamPackage analog_param{}; for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( Config::default_analogs[analog_id][sub_button_id])}; - SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); + SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); } - analogs_param[analog_id].Set("modifier", InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[analog_id])); + analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( + Config::default_stick_mod[analog_id])); + emulated_controller->SetStickParam(analog_id, analog_param); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - motions_param[motion_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])}; + emulated_controller->SetMotionParam( + motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( + Config::default_motions[motion_id])}); + } + + UpdateUI(); + return; + } + + // Reset keyboard with mouse bindings + if (ui->comboDevices->currentIndex() == 2) { + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { + emulated_controller->SetButtonParam( + button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( + Config::default_buttons[button_id])}); + } + + Common::ParamPackage left_analog_param{}; + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { + Common::ParamPackage params{InputCommon::GenerateKeyboardParam( + Config::default_analogs[Settings::NativeAnalog::LStick][sub_button_id])}; + SetAnalogParam(params, left_analog_param, analog_sub_buttons[sub_button_id]); + } + left_analog_param.Set("modifier", + InputCommon::GenerateKeyboardParam( + Config::default_stick_mod[Settings::NativeAnalog::LStick])); + emulated_controller->SetStickParam(Settings::NativeAnalog::LStick, left_analog_param); + + Common::ParamPackage right_analog_param{}; + right_analog_param.Set("engine", "mouse"); + right_analog_param.Set("port", 0); + right_analog_param.Set("axis_x", 0); + right_analog_param.Set("axis_y", 1); + emulated_controller->SetStickParam(Settings::NativeAnalog::RStick, + std::move(right_analog_param)); + + for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { + emulated_controller->SetMotionParam( + motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( + Config::default_motions[motion_id])}); } UpdateUI(); @@ -1262,14 +1089,17 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); - for (std::size_t i = 0; i < buttons_param.size(); ++i) { - buttons_param[i] = button_mapping[static_cast(i)]; + for (std::size_t i = 0; i < button_mapping.size(); ++i) { + emulated_controller->SetButtonParam( + i, button_mapping[static_cast(i)]); } - for (std::size_t i = 0; i < analogs_param.size(); ++i) { - analogs_param[i] = analog_mapping[static_cast(i)]; + for (std::size_t i = 0; i < analog_mapping.size(); ++i) { + emulated_controller->SetStickParam( + i, analog_mapping[static_cast(i)]); } - for (std::size_t i = 0; i < motions_param.size(); ++i) { - motions_param[i] = motion_mapping[static_cast(i)]; + for (std::size_t i = 0; i < motion_mapping.size(); ++i) { + emulated_controller->SetMotionParam( + i, motion_mapping[static_cast(i)]); } UpdateUI(); @@ -1278,7 +1108,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { void ConfigureInputPlayer::HandleClick( QPushButton* button, std::size_t button_id, std::function new_input_setter, - InputCommon::Polling::DeviceType type) { + InputCommon::Polling::InputType type) { if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { button->setText(tr("Shake!")); } else { @@ -1286,25 +1116,16 @@ void ConfigureInputPlayer::HandleClick( } button->setFocus(); - // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a - // controller, then they don't want keyboard/mouse input - want_keyboard_mouse = ui->comboDevices->currentIndex() < 2; - input_setter = new_input_setter; - device_pollers = input_subsystem->GetPollers(type); - - for (auto& poller : device_pollers) { - poller->Start(); - } + input_subsystem->BeginMapping(type); QWidget::grabMouse(); QWidget::grabKeyboard(); - - if (type == InputCommon::Polling::DeviceType::Button) { + if (type == InputCommon::Polling::InputType::Button) { ui->controllerFrame->BeginMappingButton(button_id); - } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { + } else if (type == InputCommon::Polling::InputType::Stick) { ui->controllerFrame->BeginMappingAnalog(button_id); } @@ -1315,14 +1136,11 @@ void ConfigureInputPlayer::HandleClick( void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { timeout_timer->stop(); poll_timer->stop(); - for (auto& poller : device_pollers) { - poller->Stop(); - } + input_subsystem->StopMapping(); QWidget::releaseMouse(); QWidget::releaseKeyboard(); - if (!abort) { (*input_setter)(params); } @@ -1340,13 +1158,14 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) } // Keyboard/Mouse - if (ui->comboDevices->currentIndex() == 1) { + if (ui->comboDevices->currentIndex() == 2) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; } const auto current_input_device = input_devices[ui->comboDevices->currentIndex()]; - return params.Get("engine", "") == current_input_device.Get("class", "") && - params.Get("guid", "") == current_input_device.Get("guid", "") && + return params.Get("engine", "") == current_input_device.Get("engine", "") && + (params.Get("guid", "") == current_input_device.Get("guid", "") || + params.Get("guid", "") == current_input_device.Get("guid2", "")) && params.Get("port", "") == current_input_device.Get("port", ""); } @@ -1355,25 +1174,18 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { return; } - //const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); + const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { + event->ignore(); if (!input_setter || !event) { return; } - if (event->key() != Qt::Key_Escape) { - if (want_keyboard_mouse) { - SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, - false); - } else { - // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling - return; - } + input_subsystem->GetKeyboard()->PressKey(event->key()); } - - SetPollingResult({}, true); } void ConfigureInputPlayer::CreateProfile() { diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 39b44b8a5..02d6920f1 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -38,14 +38,22 @@ class InputSubsystem; } namespace InputCommon::Polling { -class DevicePoller; -enum class DeviceType; +enum class InputType; } // namespace InputCommon::Polling namespace Ui { class ConfigureInputPlayer; } +namespace Core { +class System; +} + +namespace Core::HID { +class EmulatedController; +enum class NpadType : u8; +} // namespace Core::HID + class ConfigureInputPlayer : public QWidget { Q_OBJECT @@ -59,18 +67,6 @@ public: /// Save all button configurations to settings file. void ApplyConfiguration(); - /** - * Attempts to connect the currently selected controller in the HID backend. - * This function will not do anything if it is not connected in the frontend. - */ - void TryConnectSelectedController(); - - /** - * Attempts to disconnect the currently selected controller in the HID backend. - * This function will not do anything if the configuration has not changed. - */ - void TryDisconnectSelectedController(); - /// Set the connection state checkbox (used to sync state). void ConnectPlayer(bool connected); @@ -104,6 +100,10 @@ protected: void showEvent(QShowEvent* event) override; private: + QString ButtonToText(const Common::ParamPackage& param); + + QString AnalogToText(const Common::ParamPackage& param, const std::string& dir); + void changeEvent(QEvent* event) override; void RetranslateUI(); @@ -113,7 +113,7 @@ private: /// Called when the button was pressed. void HandleClick(QPushButton* button, std::size_t button_id, std::function new_input_setter, - InputCommon::Polling::DeviceType type); + InputCommon::Polling::InputType type); /// Finish polling and configure input using the input_setter. void SetPollingResult(const Common::ParamPackage& params, bool abort); @@ -134,17 +134,14 @@ private: void SetConnectableControllers(); /// Gets the Controller Type for a given controller combobox index. - Settings::ControllerType GetControllerTypeFromIndex(int index) const; + Core::HID::NpadType GetControllerTypeFromIndex(int index) const; /// Gets the controller combobox index for a given Controller Type. - int GetIndexFromControllerType(Settings::ControllerType type) const; + int GetIndexFromControllerType(Core::HID::NpadType type) const; /// Update the available input devices. void UpdateInputDevices(); - /// Update the current controller icon. - void UpdateControllerIcon(); - /// Hides and disables controller settings based on the current controller type. void UpdateControllerAvailableButtons(); @@ -185,7 +182,7 @@ private: std::unique_ptr poll_timer; /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. - std::vector> index_controller_type_pairs; + std::vector> index_controller_type_pairs; static constexpr int PLAYER_COUNT = 8; std::array player_connected_checkbox; @@ -193,9 +190,7 @@ private: /// This will be the the setting function when an input is awaiting configuration. std::optional> input_setter; - std::array buttons_param; - std::array analogs_param; - std::array motions_param; + Core::HID::EmulatedController* emulated_controller; static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; @@ -221,15 +216,9 @@ private: static const std::array analog_sub_buttons; - std::vector> device_pollers; - /// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once. bool map_analog_stick_accepted{}; - /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, - /// keyboard events are ignored. - bool want_keyboard_mouse{}; - /// List of physical devices users can map with. If a SDL backed device is selected, then you /// can use this device to get a default mapping. std::vector input_devices; diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index e7433912b..14ca02fd8 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -148,16 +148,6 @@ 21 - - - Any - - - - - Keyboard/Mouse - - diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index f31f86339..03d29f194 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -6,10 +6,11 @@ #include #include #include +#include "core/core.h" #include "yuzu/configuration/configure_input_player_widget.h" PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { - UpdateColors(); + is_controller_set = false; QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&PlayerControlPreview::UpdateInput)); @@ -17,38 +18,11 @@ PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { timer->start(16); } -PlayerControlPreview::~PlayerControlPreview() = default; - -void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, - const AnalogParam& analogs_param) { - player_index = index; - Settings::ButtonsRaw buttonss; - Settings::AnalogsRaw analogs; - std::transform(buttons_param.begin(), buttons_param.end(), buttonss.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); - std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); - - std::transform(buttonss.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - buttonss.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), - Input::CreateDevice); - std::transform(analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, - analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), - Input::CreateDevice); - UpdateColors(); -} -void PlayerControlPreview::SetPlayerInputRaw(std::size_t index, - const Settings::ButtonsRaw& buttons_, - Settings::AnalogsRaw analogs_) { - player_index = index; - std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - buttons_.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), - Input::CreateDevice); - std::transform(analogs_.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, - analogs_.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), - Input::CreateDevice); - UpdateColors(); -} +PlayerControlPreview::~PlayerControlPreview() { + if (is_controller_set) { + controller->DeleteCallback(callback_key); + } +}; PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index, bool player_on) { @@ -78,20 +52,16 @@ PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size } } -void PlayerControlPreview::SetConnectedStatus(bool checked) { - LedPattern led_pattern = GetColorPattern(player_index, checked); - - led_color[0] = led_pattern.position1 ? colors.led_on : colors.led_off; - led_color[1] = led_pattern.position2 ? colors.led_on : colors.led_off; - led_color[2] = led_pattern.position3 ? colors.led_on : colors.led_off; - led_color[3] = led_pattern.position4 ? colors.led_on : colors.led_off; - is_enabled = checked; - ResetInputs(); -} - -void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) { - controller_type = type; - UpdateColors(); +void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { + if (is_controller_set) { + controller->DeleteCallback(callback_key); + } + is_controller_set = true; + controller = controller_; + Core::HID::ControllerUpdateCallback engine_callback{ + [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }}; + callback_key = controller->SetCallback(engine_callback); + ControllerUpdate(Core::HID::ControllerTriggerType::All); } void PlayerControlPreview::BeginMappingButton(std::size_t index) { @@ -162,79 +132,99 @@ void PlayerControlPreview::UpdateColors() { } void PlayerControlPreview::ResetInputs() { - for (std::size_t index = 0; index < button_values.size(); ++index) { - button_values[index] = false; - } - - for (std::size_t index = 0; index < axis_values.size(); ++index) { - axis_values[index].properties = {0, 1, 0}; - axis_values[index].value = {0, 0}; - axis_values[index].raw_value = {0, 0}; - } + button_values.fill({ + .value = false, + }); + stick_values.fill({ + .x = {.value = 0, .properties = {0, 1, 0}}, + .y = {.value = 0, .properties = {0, 1, 0}}, + }); + trigger_values.fill({ + .analog = {.value = 0, .properties = {0, 1, 0}}, + .pressed = false, + }); update(); } -void PlayerControlPreview::UpdateInput() { - if (!is_enabled && !mapping_active && !Settings::values.tas_enable) { +void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType type) { + if (type == Core::HID::ControllerTriggerType::All) { + ControllerUpdate(Core::HID::ControllerTriggerType::Color); + ControllerUpdate(Core::HID::ControllerTriggerType::Type); + ControllerUpdate(Core::HID::ControllerTriggerType::Connected); + ControllerUpdate(Core::HID::ControllerTriggerType::Button); + ControllerUpdate(Core::HID::ControllerTriggerType::Stick); + ControllerUpdate(Core::HID::ControllerTriggerType::Trigger); + ControllerUpdate(Core::HID::ControllerTriggerType::Battery); return; } - bool input_changed = false; - const auto& button_state = buttons; - for (std::size_t index = 0; index < button_values.size(); ++index) { - bool value = false; - if (index < Settings::NativeButton::BUTTON_NS_END) { - value = button_state[index]->GetStatus(); - } - bool blink = mapping_active && index == button_mapping_index; - if (analog_mapping_index == Settings::NativeAnalog::NUM_STICKS_HID) { - blink &= blink_counter > 25; - } - if (button_values[index] != value || blink) { - input_changed = true; - } - button_values[index] = value || blink; + + switch (type) { + case Core::HID::ControllerTriggerType::Connected: + case Core::HID::ControllerTriggerType::Disconnected: + is_connected = controller->IsConnected(); + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Type: + controller_type = controller->GetNpadType(); + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Color: + UpdateColors(); + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Button: + button_values = controller->GetButtonsValues(); + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Stick: + using namespace Settings::NativeAnalog; + stick_values = controller->GetSticksValues(); + // Y axis is inverted + stick_values[LStick].y.value = -stick_values[LStick].y.value; + stick_values[LStick].y.raw_value = -stick_values[LStick].y.raw_value; + stick_values[RStick].y.value = -stick_values[RStick].y.value; + stick_values[RStick].y.raw_value = -stick_values[RStick].y.raw_value; + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Trigger: + trigger_values = controller->GetTriggersValues(); + needs_redraw = true; + break; + case Core::HID::ControllerTriggerType::Battery: + battery_values = controller->GetBatteryValues(); + needs_redraw = true; + break; + default: + break; } +} - const auto& analog_state = sticks; - for (std::size_t index = 0; index < axis_values.size(); ++index) { - const auto [stick_x_f, stick_y_f] = analog_state[index]->GetStatus(); - const auto [stick_x_rf, stick_y_rf] = analog_state[index]->GetRawStatus(); +void PlayerControlPreview::UpdateInput() { + if (mapping_active) { - if (static_cast(stick_x_rf * 45) != - static_cast(axis_values[index].raw_value.x() * 45) || - static_cast(-stick_y_rf * 45) != - static_cast(axis_values[index].raw_value.y() * 45)) { - input_changed = true; + for (std::size_t index = 0; index < button_values.size(); ++index) { + bool blink = index == button_mapping_index; + if (analog_mapping_index == Settings::NativeAnalog::NumAnalogs) { + blink &= blink_counter > 25; + } + if (button_values[index].value != blink) { + needs_redraw = true; + } + button_values[index].value = blink; } - axis_values[index].properties = analog_state[index]->GetAnalogProperties(); - axis_values[index].value = QPointF(stick_x_f, -stick_y_f); - axis_values[index].raw_value = QPointF(stick_x_rf, -stick_y_rf); - - const bool blink_analog = mapping_active && index == analog_mapping_index; - if (blink_analog) { - input_changed = true; - axis_values[index].value = - QPointF(blink_counter < 25 ? -blink_counter / 25.0f : 0, - blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0); + for (std::size_t index = 0; index < stick_values.size(); ++index) { + const bool blink_analog = index == analog_mapping_index; + if (blink_analog) { + needs_redraw = true; + stick_values[index].x.value = blink_counter < 25 ? -blink_counter / 25.0f : 0; + stick_values[index].y.value = + blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0; + } } } - - if (input_changed) { + if (needs_redraw) { update(); - if (controller_callback.input != nullptr) { - ControllerInput input{ - .axis_values = {std::pair{ - axis_values[Settings::NativeAnalog::LStick].value.x(), - axis_values[Settings::NativeAnalog::LStick].value.y()}, - std::pair{ - axis_values[Settings::NativeAnalog::RStick].value.x(), - axis_values[Settings::NativeAnalog::RStick].value.y()}}, - .button_values = button_values, - .changed = true, - }; - controller_callback.input(std::move(input)); - } } if (mapping_active) { @@ -242,10 +232,6 @@ void PlayerControlPreview::UpdateInput() { } } -void PlayerControlPreview::SetCallBack(ControllerCallback callback_) { - controller_callback = std::move(callback_); -} - void PlayerControlPreview::paintEvent(QPaintEvent* event) { QFrame::paintEvent(event); QPainter p(this); @@ -253,22 +239,22 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { const QPointF center = rect().center(); switch (controller_type) { - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::Handheld: DrawHandheldController(p, center); break; - case Settings::ControllerType::DualJoyconDetached: + case Core::HID::NpadType::JoyconDual: DrawDualController(p, center); break; - case Settings::ControllerType::LeftJoycon: + case Core::HID::NpadType::JoyconLeft: DrawLeftController(p, center); break; - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: DrawRightController(p, center); break; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: DrawGCController(p, center); break; - case Settings::ControllerType::ProController: + case Core::HID::NpadType::ProController: default: DrawProController(p, center); break; @@ -281,7 +267,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // Sideview left joystick DrawJoystickSideview(p, center + QPoint(142, -69), - -axis_values[Settings::NativeAnalog::LStick].value.y(), 1.15f, + -stick_values[Settings::NativeAnalog::LStick].y.value, 1.15f, button_values[LStick]); // Topview D-pad buttons @@ -292,7 +278,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // Topview left joystick DrawJoystickSideview(p, center + QPointF(-140.5f, -28), - -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1.15f, + -stick_values[Settings::NativeAnalog::LStick].x.value + 15.0f, 1.15f, button_values[LStick]); // Topview minus button @@ -334,8 +320,10 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f, - button_values[Settings::NativeButton::LStick]); + DrawJoystick(p, + center + QPointF(9, -69) + + (QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value) * 8), + 1.8f, button_values[Settings::NativeButton::LStick]); DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0)); } @@ -384,6 +372,9 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) p.setPen(colors.font2); p.setBrush(colors.font2); DrawCircle(p, center + QPoint(26, 71), 5); + + // Draw battery + DrawBattery(p, center + QPoint(-170, -140), battery_values[0]); } void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) { @@ -392,20 +383,22 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center // Sideview right joystick DrawJoystickSideview(p, center + QPoint(173 - 315, 11), - axis_values[Settings::NativeAnalog::RStick].value.y() + 10.0f, 1.15f, + stick_values[Settings::NativeAnalog::RStick].y.value + 10.0f, 1.15f, button_values[Settings::NativeButton::RStick]); + // Topview right joystick + DrawJoystickSideview(p, center + QPointF(140, -28), + -stick_values[Settings::NativeAnalog::RStick].x.value + 15.0f, 1.15f, + button_values[RStick]); + // Topview face buttons p.setPen(colors.outline); button_color = colors.button; DrawRoundButton(p, center + QPoint(163, -21), button_values[A], 11, 5, Direction::Up); + DrawRoundButton(p, center + QPoint(140, -21), button_values[B], 11, 5, Direction::Up); + DrawRoundButton(p, center + QPoint(140, -21), button_values[X], 11, 5, Direction::Up); DrawRoundButton(p, center + QPoint(117, -21), button_values[Y], 11, 5, Direction::Up); - // Topview right joystick - DrawJoystickSideview(p, center + QPointF(140, -28), - -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1.15f, - button_values[RStick]); - // Topview plus button p.setPen(colors.outline); button_color = colors.button; @@ -448,8 +441,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center { // Draw joysticks using namespace Settings::NativeAnalog; - DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f, - button_values[Settings::NativeButton::RStick]); + DrawJoystick(p, + center + QPointF(-9, 11) + + (QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value) * 8), + 1.8f, button_values[Settings::NativeButton::RStick]); DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90)); } @@ -503,6 +498,9 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5); + + // Draw battery + DrawBattery(p, center + QPoint(110, -140), battery_values[1]); } void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { @@ -512,17 +510,19 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) // Left/Right trigger DrawDualTriggers(p, center, button_values[L], button_values[R]); + // Topview right joystick + DrawJoystickSideview(p, center + QPointF(180, -78), + -stick_values[Settings::NativeAnalog::RStick].x.value + 15.0f, 1, + button_values[RStick]); + // Topview face buttons p.setPen(colors.outline); button_color = colors.button; DrawRoundButton(p, center + QPoint(200, -71), button_values[A], 10, 5, Direction::Up); + DrawRoundButton(p, center + QPoint(180, -71), button_values[B], 10, 5, Direction::Up); + DrawRoundButton(p, center + QPoint(180, -71), button_values[X], 10, 5, Direction::Up); DrawRoundButton(p, center + QPoint(160, -71), button_values[Y], 10, 5, Direction::Up); - // Topview right joystick - DrawJoystickSideview(p, center + QPointF(180, -78), - -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1, - button_values[RStick]); - // Topview plus button p.setPen(colors.outline); button_color = colors.button; @@ -538,7 +538,7 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) // Topview left joystick DrawJoystickSideview(p, center + QPointF(-180.5f, -78), - -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1, + -stick_values[Settings::NativeAnalog::LStick].x.value + 15.0f, 1, button_values[LStick]); // Topview minus button @@ -557,13 +557,13 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - const auto& l_stick = axis_values[LStick]; + const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); const auto l_button = button_values[Settings::NativeButton::LStick]; - const auto& r_stick = axis_values[RStick]; + const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); const auto r_button = button_values[Settings::NativeButton::RStick]; - DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button); - DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button); + DrawJoystick(p, center + QPointF(-65, -65) + (l_stick * 7), 1.62f, l_button); + DrawJoystick(p, center + QPointF(65, 12) + (r_stick * 7), 1.62f, r_button); DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90)); } @@ -634,6 +634,10 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f); + + // Draw battery + DrawBattery(p, center + QPoint(-100, -160), battery_values[0]); + DrawBattery(p, center + QPoint(40, -160), battery_values[1]); } void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { @@ -643,13 +647,13 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen { // Draw joysticks using namespace Settings::NativeAnalog; - const auto& l_stick = axis_values[LStick]; + const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); const auto l_button = button_values[Settings::NativeButton::LStick]; - const auto& r_stick = axis_values[RStick]; + const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); const auto r_button = button_values[Settings::NativeButton::RStick]; - DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button); - DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button); + DrawJoystick(p, center + QPointF(-171, -41) + (l_stick * 4), 1.0f, l_button); + DrawJoystick(p, center + QPointF(171, 8) + (r_stick * 4), 1.0f, r_button); DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0)); } @@ -732,6 +736,11 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f); + + // Draw battery + DrawBattery(p, center + QPoint(-200, 110), battery_values[0]); + DrawBattery(p, center + QPoint(-30, 110), battery_values[1]); + DrawBattery(p, center + QPoint(130, 110), battery_values[2]); } void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { @@ -741,9 +750,11 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - DrawProJoystick(p, center + QPointF(-111, -55), axis_values[LStick].value, 11, + const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); + const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); + DrawProJoystick(p, center + QPointF(-111, -55), l_stick, 11, button_values[Settings::NativeButton::LStick]); - DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11, + DrawProJoystick(p, center + QPointF(51, 0), r_stick, 11, button_values[Settings::NativeButton::RStick]); DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105)); } @@ -817,24 +828,26 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); + + // Draw battery + DrawBattery(p, center + QPoint(-30, -165), battery_values[0]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { - DrawGCTriggers(p, center, button_values[Settings::NativeButton::ZL], - button_values[Settings::NativeButton::ZR]); + DrawGCTriggers(p, center, trigger_values[0], trigger_values[1]); DrawGCButtonZ(p, center, button_values[Settings::NativeButton::R]); DrawGCBody(p, center); { // Draw joysticks using namespace Settings::NativeAnalog; - DrawGCJoystick(p, center + QPointF(-111, -44) + (axis_values[LStick].value * 10), false); + const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); + const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); + DrawGCJoystick(p, center + QPointF(-111, -44) + (l_stick * 10), {}); button_color = colors.button2; - DrawCircleButton(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), false, - 15); + DrawCircleButton(p, center + QPointF(61, 37) + (r_stick * 9.5f), {}, 15); p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C, - 1.0f); + DrawSymbol(p, center + QPointF(61, 37) + (r_stick * 9.5f), Symbol::C, 1.0f); DrawRawJoystick(p, center + QPointF(-198, -125), center + QPointF(198, -125)); } @@ -871,6 +884,9 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { // Minus and Plus buttons p.setPen(colors.outline); DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8); + + // Draw battery + DrawBattery(p, center + QPoint(-30, -165), battery_values[0]); } constexpr std::array symbol_a = { @@ -1939,8 +1955,9 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { } } -void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bool left_pressed, - bool right_pressed) { +void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; std::array qbody_top; @@ -1949,8 +1966,10 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bo const float trigger_x = pro_left_trigger[point * 2 + 0]; const float trigger_y = pro_left_trigger[point * 2 + 1]; - qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 2 : 0)); - qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 2 : 0)); + qleft_trigger[point] = + center + QPointF(trigger_x, trigger_y + (left_pressed.value ? 2 : 0)); + qright_trigger[point] = + center + QPointF(-trigger_x, trigger_y + (right_pressed.value ? 2 : 0)); } for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) { @@ -1967,16 +1986,17 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bo DrawPolygon(p, qbody_top); // Left trigger - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, bool left_pressed, - bool right_pressed) { +void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, + Input::TriggerStatus left_trigger, + Input::TriggerStatus right_trigger) { std::array qleft_trigger; std::array qright_trigger; @@ -1984,32 +2004,37 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, boo const float trigger_x = left_gc_trigger[point * 2 + 0]; const float trigger_y = left_gc_trigger[point * 2 + 1]; - qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 10 : 0)); - qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 10 : 0)); + qleft_trigger[point] = + center + QPointF(trigger_x, trigger_y + (left_trigger.analog.value * 10.0f)); + qright_trigger[point] = + center + QPointF(-trigger_x, trigger_y + (right_trigger.analog.value * 10.0f)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_trigger.pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_trigger.pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(-132, -119 + (left_pressed ? 10 : 0)), Symbol::L, 1.7f); + DrawSymbol(p, center + QPointF(-132, -119 + (left_trigger.analog.value * 10.0f)), Symbol::L, + 1.7f); // Draw R text p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(121.5f, -119 + (right_pressed ? 10 : 0)), Symbol::R, 1.7f); + DrawSymbol(p, center + QPointF(121.5f, -119 + (right_trigger.analog.value * 10.0f)), Symbol::R, + 1.7f); } void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center, - bool left_pressed, bool right_pressed) { + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; @@ -2018,23 +2043,24 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente const float left_trigger_y = left_joycon_trigger[point * 2 + 1]; qleft_trigger[point] = - center + QPointF(left_trigger_x, left_trigger_y + (left_pressed ? 0.5f : 0)); + center + QPointF(left_trigger_x, left_trigger_y + (left_pressed.value ? 0.5f : 0)); qright_trigger[point] = - center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed ? 0.5f : 0)); + center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed.value ? 0.5f : 0)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, bool left_pressed, - bool right_pressed) { +void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 1.62f; @@ -2043,25 +2069,27 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, b const float left_trigger_x = left_joycon_trigger[point * 2 + 0]; const float left_trigger_y = left_joycon_trigger[point * 2 + 1]; - qleft_trigger[point] = center + QPointF(left_trigger_x * size + offset, - left_trigger_y * size + (left_pressed ? 0.5f : 0)); + qleft_trigger[point] = + center + QPointF(left_trigger_x * size + offset, + left_trigger_y * size + (left_pressed.value ? 0.5f : 0)); qright_trigger[point] = center + QPointF(-left_trigger_x * size - offset, - left_trigger_y * size + (right_pressed ? 0.5f : 0)); + left_trigger_y * size + (right_pressed.value ? 0.5f : 0)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center, - bool left_pressed, bool right_pressed) { + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2080,9 +2108,9 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text @@ -2097,7 +2125,8 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce } void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center, - bool left_pressed, bool right_pressed) { + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2114,9 +2143,9 @@ void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF c } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw ZL text @@ -2130,7 +2159,8 @@ void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF c DrawSymbol(p, center + QPointF(180, -113), Symbol::ZR, 1.0f); } -void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, bool left_pressed) { +void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, + const Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2138,15 +2168,16 @@ void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, b for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { qleft_trigger[point] = center + QPointF(left_joycon_trigger[point * 2] * size + offset, left_joycon_trigger[point * 2 + 1] * size - - (left_pressed ? 0.5f : 1.0f)); + (left_pressed.value ? 0.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); } -void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, bool left_pressed) { +void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, + const Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2154,18 +2185,18 @@ void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { qleft_trigger[point] = center + QPointF(left_joycon_sideview_zl[point * 2] * size + offset2, left_joycon_sideview_zl[point * 2 + 1] * size + - (left_pressed ? 1.5f : 1.0f)); + (left_pressed.value ? 1.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.drawArc(center.x() + 158, center.y() + (left_pressed ? -203.5f : -204.0f), 77, 77, 225 * 16, - 44 * 16); + p.drawArc(center.x() + 158, center.y() + (left_pressed.value ? -203.5f : -204.0f), 77, 77, + 225 * 16, 44 * 16); } void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center, - bool left_pressed) { + const Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2174,7 +2205,7 @@ void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF ce } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Draw L text @@ -2184,7 +2215,7 @@ void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF ce } void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center, - bool left_pressed) { + const Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2193,7 +2224,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF c } p.setPen(colors.outline); - p.setBrush(left_pressed ? colors.highlight : colors.button); + p.setBrush(left_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Draw ZL text @@ -2203,7 +2234,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, - bool right_pressed) { + const Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2211,36 +2242,36 @@ void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset, left_joycon_trigger[point * 2 + 1] * size - - (right_pressed ? 0.5f : 1.0f)); + (right_pressed.value ? 0.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, - bool right_pressed) { + const Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { qright_trigger[point] = - center + - QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2, - left_joycon_sideview_zl[point * 2 + 1] * size + (right_pressed ? 0.5f : 0) + 1); + center + QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2, + left_joycon_sideview_zl[point * 2 + 1] * size + + (right_pressed.value ? 0.5f : 0) + 1); } p.setPen(colors.outline); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); - p.drawArc(center.x() - 236, center.y() + (right_pressed ? -203.5f : -204.0f), 77, 77, 271 * 16, - 44 * 16); + p.drawArc(center.x() - 236, center.y() + (right_pressed.value ? -203.5f : -204.0f), 77, 77, + 271 * 16, 44 * 16); } void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center, - bool right_pressed) { + const Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2249,7 +2280,7 @@ void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF c } p.setPen(colors.outline); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw R text @@ -2259,7 +2290,7 @@ void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center, - bool right_pressed) { + const Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2268,7 +2299,7 @@ void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF } p.setPen(colors.outline); - p.setBrush(right_pressed ? colors.highlight : colors.button); + p.setBrush(right_pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw ZR text @@ -2278,13 +2309,13 @@ void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF } void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size, - bool pressed) { + const Input::ButtonStatus& pressed) { const float radius1 = 13.0f * size; const float radius2 = 9.0f * size; // Outer circle p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawCircle(p, center, radius1); // Cross @@ -2292,17 +2323,17 @@ void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float p.drawLine(center - QPoint(0, radius1), center + QPoint(0, radius1)); // Inner circle - p.setBrush(pressed ? colors.highlight2 : colors.button2); + p.setBrush(pressed.value ? colors.highlight2 : colors.button2); DrawCircle(p, center, radius2); } void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle, - float size, bool pressed) { + float size, const Input::ButtonStatus& pressed) { QVector joystick; joystick.reserve(static_cast(left_joystick_sideview.size() / 2)); for (std::size_t point = 0; point < left_joystick_sideview.size() / 2; ++point) { - joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed ? 1 : 0), + joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed.value ? 1 : 0), left_joystick_sideview[point * 2 + 1] * size - 1)); } @@ -2314,14 +2345,15 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente // Draw joystick p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); p.drawPolygon(p2); p.drawLine(p2.at(1), p2.at(30)); p.drawLine(p2.at(32), p2.at(71)); } void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset, - float offset_scalar, bool pressed) { + float offset_scalar, + const Input::ButtonStatus& pressed) { const float radius1 = 24.0f; const float radius2 = 17.0f; @@ -2339,11 +2371,11 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co // Outer circle p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); p.drawEllipse(QPointF(0, 0), radius1 * amplitude, radius1); // Inner circle - p.setBrush(pressed ? colors.highlight2 : colors.button2); + p.setBrush(pressed.value ? colors.highlight2 : colors.button2); const float inner_offset = (radius1 - radius2) * 0.4f * ((offset.x() == 0 && offset.y() < 0) ? -1.0f : 1.0f); @@ -2355,14 +2387,15 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co p.restore(); } -void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) { +void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed) { // Outer circle p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawCircle(p, center, 26.0f); // Inner circle - p.setBrush(pressed ? colors.highlight2 : colors.button2); + p.setBrush(pressed.value ? colors.highlight2 : colors.button2); DrawCircle(p, center, 19.0f); p.setBrush(colors.transparent); DrawCircle(p, center, 13.5f); @@ -2371,26 +2404,24 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, boo void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right) { using namespace Settings::NativeAnalog; - if (controller_type != Settings::ControllerType::LeftJoycon) { - DrawJoystickProperties(p, center_right, axis_values[RStick].properties); + if (controller_type != Core::HID::NpadType::JoyconLeft) { + DrawJoystickProperties(p, center_right, stick_values[RStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); - DrawJoystickDot(p, center_right, axis_values[RStick].raw_value, - axis_values[RStick].properties); + DrawJoystickDot(p, center_right, stick_values[RStick], true); p.setPen(colors.indicator2); p.setBrush(colors.indicator2); - DrawJoystickDot(p, center_right, axis_values[RStick].value, axis_values[RStick].properties); + DrawJoystickDot(p, center_right, stick_values[RStick], false); } - if (controller_type != Settings::ControllerType::RightJoycon) { - DrawJoystickProperties(p, center_left, axis_values[LStick].properties); + if (controller_type != Core::HID::NpadType::JoyconRight) { + DrawJoystickProperties(p, center_left, stick_values[LStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); - DrawJoystickDot(p, center_left, axis_values[LStick].raw_value, - axis_values[LStick].properties); + DrawJoystickDot(p, center_left, stick_values[LStick], true); p.setPen(colors.indicator2); p.setBrush(colors.indicator2); - DrawJoystickDot(p, center_left, axis_values[LStick].value, axis_values[LStick].properties); + DrawJoystickDot(p, center_left, stick_values[LStick], false); } } @@ -2414,19 +2445,26 @@ void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF cen DrawCircle(p, center, deadzone); } -void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, const QPointF value, - const Input::AnalogProperties& properties) { +void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, + const Input::StickStatus& stick, bool raw) { constexpr float size = 45.0f; - const float range = size * properties.range; + const float range = size * stick.x.properties.range; - // Dot pointer - DrawCircle(p, center + (value * range), 2); + if (raw) { + const QPointF value = QPointF(stick.x.raw_value, stick.y.raw_value) * size; + DrawCircle(p, center + value, 2); + return; + } + + const QPointF value = QPointF(stick.x.value, stick.y.value) * range; + DrawCircle(p, center + value, 2); } -void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, +void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, + const Input::ButtonStatus& pressed, float width, float height, Direction direction, float radius) { p.setBrush(button_color); - if (pressed) { + if (pressed.value) { switch (direction) { case Direction::Left: center.setX(center.x() - 1); @@ -2448,17 +2486,17 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, bool pre QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f}; p.drawRoundedRect(rect, radius, radius); } -void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, bool pressed, - int button_size) { +void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed, int button_size) { p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); } -void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, bool pressed, - int button_size) { +void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed, int button_size) { // Draw outer line p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); DrawRectangle(p, center, button_size / 3.0f, button_size); @@ -2471,7 +2509,8 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, boo DrawRectangle(p, center, button_size / 3.0f, button_size); } -void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, bool pressed) { +void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) { @@ -2479,11 +2518,12 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, bool } p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, bool pressed) { +void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) { @@ -2491,27 +2531,28 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, bool } p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, bool pressed) { +void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) { button_x[point] = center + QPointF(gc_button_z[point * 2], - gc_button_z[point * 2 + 1] + (pressed ? 1 : 0)); + gc_button_z[point * 2 + 1] + (pressed.value ? 1 : 0)); } p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button2); + p.setBrush(pressed.value ? colors.highlight : colors.button2); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, bool pressed, - float button_size) { +void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, + const Input::ButtonStatus& pressed, float button_size) { p.setBrush(button_color); - if (pressed) { + if (pressed.value) { p.setBrush(colors.highlight); } p.drawEllipse(center, button_size, button_size); @@ -2540,7 +2581,8 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen } void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, - const Direction direction, bool pressed, float size) { + const Direction direction, + const Input::ButtonStatus& pressed, float size) { std::array arrow_button; QPoint offset; @@ -2567,8 +2609,8 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, } // Draw arrow button - p.setPen(pressed ? colors.highlight : colors.button); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setPen(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawPolygon(p, arrow_button); switch (direction) { @@ -2596,7 +2638,8 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, - const Direction direction, bool pressed) { + const Direction direction, + const Input::ButtonStatus& pressed) { std::array qtrigger_button; for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { @@ -2619,10 +2662,44 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, // Draw arrow button p.setPen(colors.outline); - p.setBrush(pressed ? colors.highlight : colors.button); + p.setBrush(pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qtrigger_button); } +void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery) { + p.setPen(colors.outline); + p.setBrush(colors.transparent); + p.drawRect(center.x(), center.y(), 56, 20); + p.drawRect(center.x() + 56, center.y() + 6, 3, 8); + p.setBrush(colors.deadzone); + switch (battery) { + case Input::BatteryLevel::Charging: + p.setBrush(colors.indicator2); + p.drawText(center + QPoint(2, 14), tr("Charging")); + break; + case Input::BatteryLevel::Full: + p.drawRect(center.x() + 42, center.y(), 14, 20); + p.drawRect(center.x() + 28, center.y(), 14, 20); + p.drawRect(center.x() + 14, center.y(), 14, 20); + break; + case Input::BatteryLevel::Medium: + p.drawRect(center.x() + 28, center.y(), 14, 20); + p.drawRect(center.x() + 14, center.y(), 14, 20); + p.drawRect(center.x(), center.y(), 14, 20); + break; + case Input::BatteryLevel::Low: + p.drawRect(center.x() + 14, center.y(), 14, 20); + p.drawRect(center.x(), center.y(), 14, 20); + break; + case Input::BatteryLevel::Critical: + p.drawRect(center.x(), center.y(), 14, 20); + break; + case Input::BatteryLevel::Empty: + p.drawRect(center.x(), center.y(), 5, 20); + break; + } +} + void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol, float icon_size) { std::array house_icon; diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index f4bbfa528..b44a2e347 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -7,9 +7,10 @@ #include #include #include +#include "common/input.h" #include "common/settings.h" -#include "core/frontend/input.h" -#include "yuzu/debugger/controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" class QLabel; @@ -24,17 +25,12 @@ public: explicit PlayerControlPreview(QWidget* parent); ~PlayerControlPreview() override; - void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, - const AnalogParam& analogs_param); - void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_, - Settings::AnalogsRaw analogs_); - void SetConnectedStatus(bool checked); - void SetControllerType(Settings::ControllerType type); + void SetController(Core::HID::EmulatedController* controller); void BeginMappingButton(std::size_t button_id); void BeginMappingAnalog(std::size_t button_id); void EndMapping(); + void ControllerUpdate(Core::HID::ControllerTriggerType type); void UpdateInput(); - void SetCallBack(ControllerCallback callback_); protected: void paintEvent(QPaintEvent* event) override; @@ -63,15 +59,6 @@ private: SR, }; - struct AxisValue { - QPointF value{}; - QPointF raw_value{}; - Input::AnalogProperties properties{}; - int size{}; - QPoint offset{}; - bool active{}; - }; - struct LedPattern { bool position1; bool position2; @@ -122,47 +109,66 @@ private: void DrawGCBody(QPainter& p, QPointF center); // Draw triggers functions - void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); - void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); - void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); - void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); - void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed, - bool right_pressed); - void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed, - bool right_pressed); - void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed); - void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed); - void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed); - void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed); - void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed); - void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed); - void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed); - void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed); + void DrawProTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed); + void DrawGCTriggers(QPainter& p, QPointF center, Input::TriggerStatus left_trigger, + Input::TriggerStatus right_trigger); + void DrawHandheldTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed); + void DrawDualTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed); + void DrawDualTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed); + void DrawDualZTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& left_pressed, + const Input::ButtonStatus& right_pressed); + void DrawLeftTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); + void DrawLeftZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); + void DrawLeftTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& left_pressed); + void DrawLeftZTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& left_pressed); + void DrawRightTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); + void DrawRightZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); + void DrawRightTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& right_pressed); + void DrawRightZTriggersTopView(QPainter& p, QPointF center, + const Input::ButtonStatus& right_pressed); // Draw joystick functions - void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); - void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); + void DrawJoystick(QPainter& p, QPointF center, float size, const Input::ButtonStatus& pressed); + void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, + const Input::ButtonStatus& pressed); void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right); void DrawJoystickProperties(QPainter& p, QPointF center, const Input::AnalogProperties& properties); - void DrawJoystickDot(QPainter& p, QPointF center, QPointF value, - const Input::AnalogProperties& properties); - void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed); - void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); + void DrawJoystickDot(QPainter& p, QPointF center, const Input::StickStatus& stick, bool raw); + void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, + const Input::ButtonStatus& pressed); + void DrawGCJoystick(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); // Draw button functions - void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size); - void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height, - Direction direction = Direction::None, float radius = 2); - void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size); - void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size); - void DrawGCButtonX(QPainter& p, QPointF center, bool pressed); - void DrawGCButtonY(QPainter& p, QPointF center, bool pressed); - void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed); + void DrawCircleButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + float button_size); + void DrawRoundButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + float width, float height, Direction direction = Direction::None, + float radius = 2); + void DrawMinusButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + int button_size); + void DrawPlusButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + int button_size); + void DrawGCButtonX(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + void DrawGCButtonY(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + void DrawGCButtonZ(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); - void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed, - float size = 1.0f); - void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed); + void DrawArrowButton(QPainter& p, QPointF center, Direction direction, + const Input::ButtonStatus& pressed, float size = 1.0f); + void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, + const Input::ButtonStatus& pressed); + + // Draw battery functions + void DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery); // Draw icon functions void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); @@ -178,24 +184,23 @@ private: void SetTextFont(QPainter& p, float text_size, const QString& font_family = QStringLiteral("sans-serif")); - using ButtonArray = - std::array, Settings::NativeButton::BUTTON_NS_END>; - using StickArray = - std::array, Settings::NativeAnalog::NUM_STICKS_HID>; + bool is_controller_set{}; + bool is_connected{}; + bool needs_redraw{}; + Core::HID::NpadType controller_type; - ControllerCallback controller_callback; - bool is_enabled{}; bool mapping_active{}; int blink_counter{}; + int callback_key; QColor button_color{}; ColorMapping colors{}; std::array led_color{}; - ButtonArray buttons{}; - StickArray sticks{}; std::size_t player_index{}; - std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END}; - std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID}; - std::array axis_values{}; - std::array button_values{}; - Settings::ControllerType controller_type{Settings::ControllerType::ProController}; + Core::HID::EmulatedController* controller; + std::size_t button_mapping_index{Settings::NativeButton::NumButtons}; + std::size_t analog_mapping_index{Settings::NativeAnalog::NumAnalogs}; + Core::HID::ButtonValues button_values{}; + Core::HID::SticksValues stick_values{}; + Core::HID::TriggerValues trigger_values{}; + Core::HID::BatteryValues battery_values{}; }; diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index f8e08c422..9fd1a919f 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -15,9 +15,9 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "input_common/drivers/udp_client.h" +#include "input_common/helpers/udp_protocol.h" #include "input_common/main.h" -#include "input_common/udp/client.h" -#include "input_common/udp/udp.h" #include "ui_configure_motion_touch.h" #include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_touch_from_button.h" diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp index 2af3afda8..1e7a3751d 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ b/src/yuzu/configuration/configure_mouse_advanced.cpp @@ -11,8 +11,11 @@ #include "common/assert.h" #include "common/param_package.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" #include "input_common/main.h" #include "ui_configure_mouse_advanced.h" +#include "yuzu/bootmanager.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_mouse_advanced.h" @@ -101,7 +104,7 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, [=, this](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, - InputCommon::Polling::DeviceType::Button); + InputCommon::Polling::InputType::Button); }); connect(button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { @@ -127,13 +130,10 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this] { - Common::ParamPackage params; - for (auto& poller : device_pollers) { - params = poller->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; - } + const auto& params = input_subsystem->GetNextInput(); + if (params.Has("engine")) { + SetPollingResult(params, false); + return; } }); @@ -196,26 +196,13 @@ void ConfigureMouseAdvanced::UpdateButtonLabels() { void ConfigureMouseAdvanced::HandleClick( QPushButton* button, std::function new_input_setter, - InputCommon::Polling::DeviceType type) { + InputCommon::Polling::InputType type) { button->setText(tr("[press key]")); button->setFocus(); - // Keyboard keys or mouse buttons can only be used as button devices - want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button; - if (want_keyboard_mouse) { - const auto iter = std::find(button_map.begin(), button_map.end(), button); - ASSERT(iter != button_map.end()); - const auto index = std::distance(button_map.begin(), iter); - ASSERT(index < Settings::NativeButton::NumButtons && index >= 0); - } - input_setter = new_input_setter; - device_pollers = input_subsystem->GetPollers(type); - - for (auto& poller : device_pollers) { - poller->Start(); - } + input_subsystem->BeginMapping(type); QWidget::grabMouse(); QWidget::grabKeyboard(); @@ -227,9 +214,7 @@ void ConfigureMouseAdvanced::HandleClick( void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { timeout_timer->stop(); poll_timer->stop(); - for (auto& poller : device_pollers) { - poller->Stop(); - } + input_subsystem->StopMapping(); QWidget::releaseMouse(); QWidget::releaseKeyboard(); @@ -247,15 +232,8 @@ void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) { return; } - if (want_keyboard_mouse) { - SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())}, - false); - } else { - // We don't want any mouse buttons, so don't stop polling - return; - } - - SetPollingResult({}, true); + const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); } void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { @@ -264,13 +242,6 @@ void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { } if (event->key() != Qt::Key_Escape) { - if (want_keyboard_mouse) { - SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, - false); - } else { - // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling - return; - } + input_subsystem->GetKeyboard()->PressKey(event->key()); } - SetPollingResult({}, true); } diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h index 65b6fca9a..5fa534eaf 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ b/src/yuzu/configuration/configure_mouse_advanced.h @@ -46,7 +46,7 @@ private: /// Called when the button was pressed. void HandleClick(QPushButton* button, std::function new_input_setter, - InputCommon::Polling::DeviceType type); + InputCommon::Polling::InputType type); /// Finish polling and configure input using the input_setter void SetPollingResult(const Common::ParamPackage& params, bool abort); @@ -67,12 +67,6 @@ private: std::array button_map; std::array buttons_param; - std::vector> device_pollers; - std::unique_ptr timeout_timer; std::unique_ptr poll_timer; - - /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, - /// keyboard events are ignored. - bool want_keyboard_mouse = false; }; diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp index 40129f228..bde0a08c4 100644 --- a/src/yuzu/configuration/configure_touch_from_button.cpp +++ b/src/yuzu/configuration/configure_touch_from_button.cpp @@ -163,13 +163,10 @@ void ConfigureTouchFromButton::ConnectEvents() { connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this]() { - Common::ParamPackage params; - for (auto& poller : device_pollers) { - params = poller->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; - } + const auto& params = input_subsystem->GetNextInput(); + if (params.Has("engine")) { + SetPollingResult(params, false); + return; } }); } @@ -248,11 +245,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is } }; - device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button); - - for (auto& poller : device_pollers) { - poller->Start(); - } + input_subsystem->BeginMapping(InputCommon::Polling::InputType::Button); grabKeyboard(); grabMouse(); @@ -365,14 +358,14 @@ void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& po void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params, const bool cancel) { + timeout_timer->stop(); + poll_timer->stop(); + input_subsystem->StopMapping(); + releaseKeyboard(); releaseMouse(); qApp->restoreOverrideCursor(); - timeout_timer->stop(); - poll_timer->stop(); - for (auto& poller : device_pollers) { - poller->Stop(); - } + if (input_setter) { (*input_setter)(params, cancel); input_setter.reset(); diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h index d9513e3bc..e1400481a 100644 --- a/src/yuzu/configuration/configure_touch_from_button.h +++ b/src/yuzu/configuration/configure_touch_from_button.h @@ -24,10 +24,6 @@ namespace InputCommon { class InputSubsystem; } -namespace InputCommon::Polling { -class DevicePoller; -} - namespace Settings { struct TouchFromButtonMap; } @@ -85,7 +81,6 @@ private: std::unique_ptr timeout_timer; std::unique_ptr poll_timer; - std::vector> device_pollers; std::optional> input_setter; static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2; From 173a6b1e57c71e8bfe7a1492d5fe9b6b3e81a6cb Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:50:30 -0500 Subject: [PATCH 068/291] core/emu_window: Remove touch input --- src/core/frontend/emu_window.cpp | 100 ++++--------------------------- src/core/frontend/emu_window.h | 30 ++-------- 2 files changed, 16 insertions(+), 114 deletions(-) diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index e1f7e5886..57c6ffc43 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -3,66 +3,31 @@ // Refer to the license.txt file included. #include -#include "common/settings.h" #include "core/frontend/emu_window.h" -#include "core/frontend/input.h" namespace Core::Frontend { GraphicsContext::~GraphicsContext() = default; -class EmuWindow::TouchState : public Input::Factory, - public std::enable_shared_from_this { -public: - std::unique_ptr Create(const Common::ParamPackage&) override { - return std::make_unique(shared_from_this()); - } - - std::mutex mutex; - - Input::TouchStatus status; - -private: - class Device : public Input::TouchDevice { - public: - explicit Device(std::weak_ptr&& touch_state_) : touch_state(touch_state_) {} - Input::TouchStatus GetStatus() const override { - if (auto state = touch_state.lock()) { - std::lock_guard guard{state->mutex}; - return state->status; - } - return {}; - } - - private: - std::weak_ptr touch_state; - }; -}; - EmuWindow::EmuWindow() { // TODO: Find a better place to set this. config.min_client_area_size = std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); active_config = config; - touch_state = std::make_shared(); - Input::RegisterFactory("emu_window", touch_state); } -EmuWindow::~EmuWindow() { - Input::UnregisterFactory("emu_window"); -} +EmuWindow::~EmuWindow() {} -/** - * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout - * @param layout FramebufferLayout object describing the framebuffer size and screen positions - * @param framebuffer_x Framebuffer x-coordinate to check - * @param framebuffer_y Framebuffer y-coordinate to check - * @return True if the coordinates are within the touchpad, otherwise false - */ -static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x, - u32 framebuffer_y) { - return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom && - framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right); +std::pair EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const { + std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); + const float x = + static_cast(framebuffer_x - framebuffer_layout.screen.left) / + static_cast(framebuffer_layout.screen.right - framebuffer_layout.screen.left); + const float y = + static_cast(framebuffer_y - framebuffer_layout.screen.top) / + static_cast(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); + + return std::make_pair(x, y); } std::pair EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { @@ -75,49 +40,6 @@ std::pair EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { return std::make_pair(new_x, new_y); } -void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) { - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { - return; - } - if (id >= touch_state->status.size()) { - return; - } - - std::lock_guard guard{touch_state->mutex}; - const float x = - static_cast(framebuffer_x - framebuffer_layout.screen.left) / - static_cast(framebuffer_layout.screen.right - framebuffer_layout.screen.left); - const float y = - static_cast(framebuffer_y - framebuffer_layout.screen.top) / - static_cast(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); - - touch_state->status[id] = std::make_tuple(x, y, true); -} - -void EmuWindow::TouchReleased(size_t id) { - if (id >= touch_state->status.size()) { - return; - } - std::lock_guard guard{touch_state->mutex}; - touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); -} - -void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) { - if (id >= touch_state->status.size()) { - return; - } - - if (!std::get<2>(touch_state->status[id])) { - return; - } - - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { - std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); - } - - TouchPressed(framebuffer_x, framebuffer_y, id); -} - void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) { NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height)); } diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 8a86a1d27..e413a520a 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -112,28 +112,6 @@ public: /// Returns if window is shown (not minimized) virtual bool IsShown() const = 0; - /** - * Signal that a touch pressed event has occurred (e.g. mouse click pressed) - * @param framebuffer_x Framebuffer x-coordinate that was pressed - * @param framebuffer_y Framebuffer y-coordinate that was pressed - * @param id Touch event ID - */ - void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id); - - /** - * Signal that a touch released event has occurred (e.g. mouse click released) - * @param id Touch event ID - */ - void TouchReleased(size_t id); - - /** - * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) - * @param framebuffer_x Framebuffer x-coordinate - * @param framebuffer_y Framebuffer y-coordinate - * @param id Touch event ID - */ - void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id); - /** * Returns currently active configuration. * @note Accesses to the returned object need not be consistent because it may be modified in @@ -212,6 +190,11 @@ protected: client_area_height = size.second; } + /** + * Converts a screen postion into the equivalent touchscreen position. + */ + std::pair MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; + WindowSystemInfo window_info; private: @@ -237,9 +220,6 @@ private: WindowConfig config; ///< Internal configuration (changes pending for being applied in /// ProcessConfigurationChanges) WindowConfig active_config; ///< Internal active configuration - - class TouchState; - std::shared_ptr touch_state; }; } // namespace Core::Frontend From 456397ed39a6966e1a1e333090e778c0d3414858 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 19:59:09 -0500 Subject: [PATCH 069/291] debugger/controller: Remove TAS --- src/yuzu/debugger/controller.cpp | 32 ++++---------------------------- src/yuzu/debugger/controller.h | 19 +------------------ 2 files changed, 5 insertions(+), 46 deletions(-) diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 0e190a3d5..d8e41f8b6 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -6,12 +6,11 @@ #include #include #include "common/settings.h" -#include "input_common/main.h" +#include "core/core.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) - : QWidget(parent, Qt::Dialog), input_subsystem{input_subsystem_} { +ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -21,7 +20,8 @@ ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - refreshConfiguration(); + widget->SetController(Core::System::GetInstance().HIDCore().GetEmulatedController( + Core::HID::NpadIdType::Player1)); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(widget); @@ -30,22 +30,10 @@ ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* // Configure focus so that widget is focusable and the dialog automatically forwards focus to // it. setFocusProxy(widget); - widget->SetConnectedStatus(false); widget->setFocusPolicy(Qt::StrongFocus); widget->setFocus(); } -void ControllerDialog::refreshConfiguration() { - const auto& players = Settings::values.players.GetValue(); - constexpr std::size_t player = 0; - widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs); - widget->SetControllerType(players[player].controller_type); - ControllerCallback callback{[this](ControllerInput input) { InputController(input); }}; - widget->SetCallBack(callback); - widget->repaint(); - widget->SetConnectedStatus(players[player].connected); -} - QAction* ControllerDialog::toggleViewAction() { if (toggle_view_action == nullptr) { toggle_view_action = new QAction(tr("&Controller P1"), this); @@ -61,7 +49,6 @@ void ControllerDialog::showEvent(QShowEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); } - refreshConfiguration(); QWidget::showEvent(ev); } @@ -69,16 +56,5 @@ void ControllerDialog::hideEvent(QHideEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); } - widget->SetConnectedStatus(false); QWidget::hideEvent(ev); } - -void ControllerDialog::InputController(ControllerInput input) { - u32 buttons = 0; - int index = 0; - for (bool btn : input.button_values) { - buttons |= (btn ? 1U : 0U) << index; - index++; - } - //input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); -} diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 7742db58b..697489cbb 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -4,9 +4,7 @@ #pragma once -#include #include -#include "common/settings.h" class QAction; class QHideEvent; @@ -17,35 +15,20 @@ namespace InputCommon { class InputSubsystem; } -struct ControllerInput { - std::array, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{}; - std::array button_values{}; - bool changed{}; -}; - -struct ControllerCallback { - std::function input; -}; - class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(QWidget* parent = nullptr, - InputCommon::InputSubsystem* input_subsystem_ = nullptr); + explicit ControllerDialog(QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); - void refreshConfiguration(); protected: void showEvent(QShowEvent* ev) override; void hideEvent(QHideEvent* ev) override; private: - void InputController(ControllerInput input); QAction* toggle_view_action = nullptr; - QFileSystemWatcher* watcher = nullptr; PlayerControlPreview* widget; - InputCommon::InputSubsystem* input_subsystem; }; From 6e2c84042d296272a2186feac67678c19fdb122b Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:18:26 -0500 Subject: [PATCH 070/291] settings: Cleanup settings --- src/common/settings.h | 3 --- src/common/settings_input.h | 13 ++++++++++++- src/core/hle/service/hid/controllers/debug_pad.h | 2 +- src/core/hle/service/hid/controllers/mouse.cpp | 2 +- src/core/hle/service/hid/controllers/npad.h | 2 +- src/core/hle/service/hid/hid.cpp | 3 +-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index fa4aa8747..4cf28617c 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -572,7 +572,6 @@ struct Values { BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; BasicSetting mouse_enabled{false, "mouse_enabled"}; - std::string mouse_device; MouseButtonsRaw mouse_buttons; BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; @@ -592,8 +591,6 @@ struct Values { BasicSetting touch_from_button_map_index{0, "touch_from_button_map"}; std::vector touch_from_button_maps; - std::atomic_bool is_device_reload_pending{true}; - // Data Storage BasicSetting use_virtual_sd{true, "use_virtual_sd"}; BasicSetting gamecard_inserted{false, "gamecard_inserted"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 609600582..2c0eb31d3 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -62,11 +62,22 @@ enum Values : int { constexpr int STICK_HID_BEGIN = LStick; constexpr int STICK_HID_END = NumAnalogs; -constexpr int NUM_STICKS_HID = NumAnalogs; extern const std::array mapping; } // namespace NativeAnalog +namespace NativeTrigger { +enum Values : int { + LTrigger, + RTrigger, + + NumTriggers, +}; + +constexpr int TRIGGER_HID_BEGIN = LTrigger; +constexpr int TRIGGER_HID_END = NumTriggers; +} // namespace NativeTrigger + namespace NativeVibration { enum Values : int { LeftVibrationDevice, diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 1b1645184..e90ae8415 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -87,7 +87,7 @@ private: std::array, Settings::NativeButton::NUM_BUTTONS_HID> buttons; - std::array, Settings::NativeAnalog::NUM_STICKS_HID> + std::array, Settings::NativeAnalog::NumAnalogs> analogs; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 544a71948..2211f1144 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -61,7 +61,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* } void Controller_Mouse::OnLoadInputDevices() { - mouse_device = Input::CreateDevice(Settings::values.mouse_device); + //mouse_device = Input::CreateDevice(Settings::values.mouse_device); std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), mouse_button_devices.begin(), Input::CreateDevice); } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 9ee146caf..f3e868bdb 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -563,7 +563,7 @@ private: std::array, Settings::NativeButton::NUM_BUTTONS_HID>, 10>; using StickArray = std::array< - std::array, Settings::NativeAnalog::NUM_STICKS_HID>, + std::array, Settings::NativeAnalog::NumAnalogs>, 10>; using VibrationArray = std::array, Settings::NativeVibration::NUM_VIBRATIONS_HID>, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 10c64d41a..9a5b60263 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -117,7 +117,7 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); + const bool should_reload = false; for (const auto& controller : controllers) { if (should_reload) { controller->OnLoadInputDevices(); @@ -2038,7 +2038,6 @@ public: }; void ReloadInputDevices() { - Settings::values.is_device_reload_pending.store(true); } void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { From 8fff6d6c67dbdaed8be639b0daeb9afdf8e53d59 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:19:28 -0500 Subject: [PATCH 071/291] Qt_applets: Use new input --- src/yuzu/applets/qt_controller.cpp | 6 +- src/yuzu/applets/qt_controller.h | 5 ++ src/yuzu/applets/qt_software_keyboard.cpp | 89 ++++++++++++----------- src/yuzu/applets/qt_software_keyboard.h | 12 +-- src/yuzu/applets/qt_web_browser.cpp | 3 +- 5 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index bf8445a89..4dd577a18 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -6,8 +6,11 @@ #include #include "common/assert.h" +#include "common/param_package.h" #include "common/string_util.h" #include "core/core.h" +#include "core/hid/emulated_controller.h +#include "core/hid/hid_types.h #include "core/hle/lock.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" @@ -48,7 +51,8 @@ void UpdateController(Settings::ControllerType controller_type, std::size_t npad ->GetAppletResource() ->GetController(Service::HID::HidController::NPad); - npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); + npad.UpdateControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad(controller_type), + npad_index, connected); } // Returns true if the given controller type is compatible with the given parameters. diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index 037325f50..98060e6f8 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -31,6 +31,10 @@ namespace Ui { class QtControllerSelectorDialog; } +namespace Core { +class System; +} + class QtControllerSelectorDialog final : public QDialog { Q_OBJECT @@ -102,6 +106,7 @@ private: Core::Frontend::ControllerParameters parameters; InputCommon::InputSubsystem* input_subsystem; + Core::System& system; std::unique_ptr input_profiles; diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index a83a11a95..7e8731232 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -10,7 +10,8 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/frontend/input_interpreter.h" +#include "core/hid/hid_types.h" +#include "core/hid/input_interpreter.h" #include "ui_qt_software_keyboard.h" #include "yuzu/applets/qt_software_keyboard.h" #include "yuzu/main.h" @@ -484,7 +485,7 @@ void QtSoftwareKeyboardDialog::open() { void QtSoftwareKeyboardDialog::reject() { // Pressing the ESC key in a dialog calls QDialog::reject(). // We will override this behavior to the "Cancel" action on the software keyboard. - TranslateButtonPress(HIDButton::X); + TranslateButtonPress(Core::HID::NpadButton::X); } void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { @@ -722,7 +723,7 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() { connect( ui->line_edit_osk, &QLineEdit::returnPressed, this, - [this] { TranslateButtonPress(HIDButton::Plus); }, Qt::QueuedConnection); + [this] { TranslateButtonPress(Core::HID::NpadButton::Plus); }, Qt::QueuedConnection); ui->line_edit_osk->setPlaceholderText( QString::fromStdU16String(initialize_parameters.guide_text)); @@ -1208,9 +1209,9 @@ void QtSoftwareKeyboardDialog::SetupMouseHover() { } } -template +template void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { TranslateButtonPress(button); } @@ -1219,9 +1220,9 @@ void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { (f(T), ...); } -template +template void QtSoftwareKeyboardDialog::HandleButtonHold() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonHeld(button)) { TranslateButtonPress(button); } @@ -1230,9 +1231,9 @@ void QtSoftwareKeyboardDialog::HandleButtonHold() { (f(T), ...); } -void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { +void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button) { switch (button) { - case HIDButton::A: + case Core::HID::NpadButton::A: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: case BottomOSKIndex::UpperCase: @@ -1245,7 +1246,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { break; } break; - case HIDButton::B: + case Core::HID::NpadButton::B: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_backspace->click(); @@ -1260,7 +1261,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { break; } break; - case HIDButton::X: + case Core::HID::NpadButton::X: if (is_inline) { emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); } else { @@ -1271,7 +1272,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { emit SubmitNormalText(SwkbdResult::Cancel, std::move(text)); } break; - case HIDButton::Y: + case Core::HID::NpadButton::Y: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_space->click(); @@ -1284,8 +1285,8 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { break; } break; - case HIDButton::LStick: - case HIDButton::RStick: + case Core::HID::NpadButton::StickL: + case Core::HID::NpadButton::StickR: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_shift->click(); @@ -1298,13 +1299,13 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { break; } break; - case HIDButton::L: + case Core::HID::NpadButton::L: MoveTextCursorDirection(Direction::Left); break; - case HIDButton::R: + case Core::HID::NpadButton::R: MoveTextCursorDirection(Direction::Right); break; - case HIDButton::Plus: + case Core::HID::NpadButton::Plus: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_ok->click(); @@ -1319,24 +1320,24 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { break; } break; - case HIDButton::DLeft: - case HIDButton::LStickLeft: - case HIDButton::RStickLeft: + case Core::HID::NpadButton::Left: + case Core::HID::NpadButton::StickLLeft: + case Core::HID::NpadButton::StickRLeft: MoveButtonDirection(Direction::Left); break; - case HIDButton::DUp: - case HIDButton::LStickUp: - case HIDButton::RStickUp: + case Core::HID::NpadButton::Up: + case Core::HID::NpadButton::StickLUp: + case Core::HID::NpadButton::StickRUp: MoveButtonDirection(Direction::Up); break; - case HIDButton::DRight: - case HIDButton::LStickRight: - case HIDButton::RStickRight: + case Core::HID::NpadButton::Right: + case Core::HID::NpadButton::StickLRight: + case Core::HID::NpadButton::StickRRight: MoveButtonDirection(Direction::Right); break; - case HIDButton::DDown: - case HIDButton::LStickDown: - case HIDButton::RStickDown: + case Core::HID::NpadButton::Down: + case Core::HID::NpadButton::StickLDown: + case Core::HID::NpadButton::StickRDown: MoveButtonDirection(Direction::Down); break; default: @@ -1467,19 +1468,25 @@ void QtSoftwareKeyboardDialog::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleButtonPressedOnce(); + HandleButtonPressedOnce< + Core::HID::NpadButton::A, Core::HID::NpadButton::B, Core::HID::NpadButton::X, + Core::HID::NpadButton::Y, Core::HID::NpadButton::StickL, Core::HID::NpadButton::StickR, + Core::HID::NpadButton::L, Core::HID::NpadButton::R, Core::HID::NpadButton::Plus, + Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, + Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, + Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, + Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft, + Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight, + Core::HID::NpadButton::StickRDown>(); - HandleButtonHold(); + HandleButtonHold(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index 592d9c085..b030cdcf7 100644 --- a/src/yuzu/applets/qt_software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -14,14 +14,16 @@ #include "core/frontend/applets/software_keyboard.h" -enum class HIDButton : u8; - class InputInterpreter; namespace Core { class System; } +namespace Core::HID { +enum class NpadButton : u64; +} + namespace Ui { class QtSoftwareKeyboardDialog; } @@ -146,7 +148,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonPressedOnce(); /** @@ -154,7 +156,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonHold(); /** @@ -162,7 +164,7 @@ private: * * @param button The button press to process. */ - void TranslateButtonPress(HIDButton button); + void TranslateButtonPress(Core::HID::NpadButton button); /** * Moves the focus of a button in a certain direction. diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 24d72a496..8e190f9fe 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -14,9 +14,10 @@ #endif #include "common/fs/path_util.h" +#include "common/param_package.h" #include "core/core.h" #include "core/hid/input_interpreter.h" -#include "input_common/keyboard.h" +#include "input_common/drivers/keyboard.h" #include "input_common/main.h" #include "yuzu/applets/qt_web_browser.h" #include "yuzu/applets/qt_web_browser_scripts.h" From db08721dccdec9330b883324e2a99d784c2405fd Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:25:22 -0500 Subject: [PATCH 072/291] service/hid: Create ring LIFO --- src/core/CMakeLists.txt | 2 +- src/core/hle/service/hid/ring_lifo.h | 54 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/core/hle/service/hid/ring_lifo.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 09163fab9..582c15f7e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -132,7 +132,6 @@ add_library(core STATIC frontend/emu_window.h frontend/framebuffer_layout.cpp frontend/framebuffer_layout.h - frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h hid/emulated_console.cpp @@ -415,6 +414,7 @@ add_library(core STATIC hle/service/hid/hid.h hle/service/hid/irs.cpp hle/service/hid/irs.h + hle/service/hid/ring_lifo.h hle/service/hid/xcd.cpp hle/service/hid/xcd.h hle/service/hid/errors.h diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h new file mode 100644 index 000000000..1cc2a194f --- /dev/null +++ b/src/core/hle/service/hid/ring_lifo.h @@ -0,0 +1,54 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "common/common_types.h" +#include "common/swap.h" + +namespace Service::HID { +constexpr std::size_t max_entry_size = 17; + +template +struct AtomicStorage { + s64_le sampling_number; + State state; +}; + +template +struct Lifo { + s64_le timestamp{}; + s64_le total_entry_count = max_entry_size; + s64_le last_entry_index{}; + s64_le entry_count{}; + std::array, max_entry_size> entries{}; + + const AtomicStorage& ReadCurrentEntry() const { + return entries[last_entry_index]; + } + + const AtomicStorage& ReadPreviousEntry() const { + return entries[GetPreviuousEntryIndex()]; + } + + std::size_t GetPreviuousEntryIndex() const { + return (last_entry_index + total_entry_count - 1) % total_entry_count; + } + + std::size_t GetNextEntryIndex() const { + return (last_entry_index + 1) % total_entry_count; + } + + void WriteNextEntry(const State& new_state) { + if (entry_count < total_entry_count - 1) { + entry_count++; + } + last_entry_index = GetNextEntryIndex(); + const auto& previous_entry = ReadPreviousEntry(); + entries[last_entry_index].sampling_number = previous_entry.sampling_number + 1; + entries[last_entry_index].state = new_state; + } +}; + +} // namespace Service::HID From dbe030110256876438cf568314e3ffb60cd89952 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:29:00 -0500 Subject: [PATCH 073/291] service/hid: Use remove duplicated code, update names --- src/core/hle/service/hid/hid.cpp | 67 ++++++++++++++------------------ src/core/hle/service/hid/hid.h | 27 ------------- 2 files changed, 30 insertions(+), 64 deletions(-) diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9a5b60263..18f29bb78 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/frontend/input.h" +#include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" @@ -34,10 +35,9 @@ namespace Service::HID { // Updating period for each HID device. -// HID is polled every 15ms, this value was derived from -// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet -constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) +// Period time is obtained by measuring the number of samples in a second +constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) +constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -89,7 +89,7 @@ IAppletResource::IAppletResource(Core::System& system_, system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); - ReloadInputDevices(); + system.HIDCore().ReloadInputDevices(); } void IAppletResource::ActivateController(HidController controller) { @@ -117,11 +117,7 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - const bool should_reload = false; for (const auto& controller : controllers) { - if (should_reload) { - controller->OnLoadInputDevices(); - } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } @@ -891,7 +887,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - const auto hold_type{rp.PopEnum()}; + const auto hold_type{rp.PopEnum()}; applet_resource->GetController(HidController::NPad).SetHoldType(hold_type); @@ -924,7 +920,7 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -946,7 +942,7 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", @@ -968,7 +964,7 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1134,36 +1130,36 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw()}; - VibrationDeviceInfo vibration_device_info; + Core::HID::VibrationDeviceInfo vibration_device_info; switch (vibration_device_handle.npad_type) { - case Controller_NPad::NpadType::ProController: - case Controller_NPad::NpadType::Handheld: - case Controller_NPad::NpadType::JoyconDual: - case Controller_NPad::NpadType::JoyconLeft: - case Controller_NPad::NpadType::JoyconRight: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::Handheld: + case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadType::JoyconRight: default: - vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; + vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; break; - case Controller_NPad::NpadType::GameCube: - vibration_device_info.type = VibrationDeviceType::GcErm; + case Core::HID::NpadType::GameCube: + vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; break; - case Controller_NPad::NpadType::Pokeball: - vibration_device_info.type = VibrationDeviceType::Unknown; + case Core::HID::NpadType::Pokeball: + vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; break; } switch (vibration_device_handle.device_index) { case Controller_NPad::DeviceIndex::Left: - vibration_device_info.position = VibrationDevicePosition::Left; + vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; break; case Controller_NPad::DeviceIndex::Right: - vibration_device_info.position = VibrationDevicePosition::Right; + vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; break; case Controller_NPad::DeviceIndex::None: default: UNREACHABLE_MSG("DeviceIndex should never be None!"); - vibration_device_info.position = VibrationDevicePosition::None; + vibration_device_info.position = Core::HID::VibrationDevicePosition::None; break; } @@ -1278,7 +1274,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { struct Parameters { Controller_NPad::DeviceHandle vibration_device_handle; u64 applet_resource_user_id; - VibrationGcErmCommand gc_erm_command; + Core::HID::VibrationGcErmCommand gc_erm_command; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -1292,21 +1288,21 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { */ const auto vibration_value = [parameters] { switch (parameters.gc_erm_command) { - case VibrationGcErmCommand::Stop: + case Core::HID::VibrationGcErmCommand::Stop: return Controller_NPad::VibrationValue{ .amp_low = 0.0f, .freq_low = 160.0f, .amp_high = 0.0f, .freq_high = 320.0f, }; - case VibrationGcErmCommand::Start: + case Core::HID::VibrationGcErmCommand::Start: return Controller_NPad::VibrationValue{ .amp_low = 1.0f, .freq_low = 160.0f, .amp_high = 1.0f, .freq_high = 320.0f, }; - case VibrationGcErmCommand::StopHard: + case Core::HID::VibrationGcErmCommand::StopHard: return Controller_NPad::VibrationValue{ .amp_low = 0.0f, .freq_low = 0.0f, @@ -1348,7 +1344,7 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { const auto gc_erm_command = [last_vibration] { if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { - return VibrationGcErmCommand::Start; + return Core::HID::VibrationGcErmCommand::Start; } /** @@ -1358,10 +1354,10 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { * This is done to reuse the controller vibration functions made for regular controllers. */ if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { - return VibrationGcErmCommand::StopHard; + return Core::HID::VibrationGcErmCommand::StopHard; } - return VibrationGcErmCommand::Stop; + return Core::HID::VibrationGcErmCommand::Stop; }(); LOG_DEBUG(Service_HID, @@ -2037,9 +2033,6 @@ public: } }; -void ReloadInputDevices() { -} - void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index b1fe75e94..2e0c33c1c 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -161,38 +161,11 @@ private: void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); - enum class VibrationDeviceType : u32 { - Unknown = 0, - LinearResonantActuator = 1, - GcErm = 2, - }; - - enum class VibrationDevicePosition : u32 { - None = 0, - Left = 1, - Right = 2, - }; - - enum class VibrationGcErmCommand : u64 { - Stop = 0, - Start = 1, - StopHard = 2, - }; - - struct VibrationDeviceInfo { - VibrationDeviceType type{}; - VibrationDevicePosition position{}; - }; - static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); - std::shared_ptr applet_resource; KernelHelpers::ServiceContext service_context; }; -/// Reload input devices. Used when input configuration changed -void ReloadInputDevices(); - /// Registers all HID services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); From 072559dede9e4ab098b84f43ee6db31d3987b2c3 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:31:06 -0500 Subject: [PATCH 074/291] service/hid: Update debug pad, xpad, stubbed and controller base to use ring lifo and the emulated controller --- .../service/hid/controllers/controller_base.h | 11 --- .../hle/service/hid/controllers/debug_pad.cpp | 68 +++++------------ .../hle/service/hid/controllers/debug_pad.h | 73 ++++++------------- .../hle/service/hid/controllers/stubbed.cpp | 3 +- .../hle/service/hid/controllers/stubbed.h | 11 ++- src/core/hle/service/hid/controllers/xpad.cpp | 29 +++----- src/core/hle/service/hid/controllers/xpad.h | 51 +++++-------- 7 files changed, 80 insertions(+), 166 deletions(-) diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 1556fb08e..4ba2eda1a 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -35,9 +35,6 @@ public: virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) {} - // Called when input devices should be loaded - virtual void OnLoadInputDevices() = 0; - void ActivateController(); void DeactivateController(); @@ -47,14 +44,6 @@ public: protected: bool is_activated{false}; - struct CommonHeader { - s64_le timestamp; - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index d439b8fb0..b2b4edf51 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -5,7 +5,10 @@ #include #include "common/common_types.h" #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" namespace Service::HID { @@ -14,7 +17,10 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff; [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; -Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {} +Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} { + controller = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Other); +} + Controller_DebugPad::~Controller_DebugPad() = default; void Controller_DebugPad::OnInit() {} @@ -23,63 +29,29 @@ void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + debug_pad_lifo.entry_count = 0; + debug_pad_lifo.last_entry_index = 0; + std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo)); return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; if (Settings::values.debug_pad_enabled) { - cur_entry.attribute.connected.Assign(1); - auto& pad = cur_entry.pad_state; + next_state.attribute.connected.Assign(1); - using namespace Settings::NativeButton; - pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); - pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); - pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); - pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); - pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); - pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); - pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); - pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); - pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + const auto& button_state = controller->GetDebugPadButtons(); + const auto& stick_state = controller->GetSticks(); - const auto [stick_l_x_f, stick_l_y_f] = - analogs[static_cast(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analogs[static_cast(JoystickId::Joystick_Right)]->GetStatus(); - cur_entry.l_stick.x = static_cast(stick_l_x_f * HID_JOYSTICK_MAX); - cur_entry.l_stick.y = static_cast(stick_l_y_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.x = static_cast(stick_r_x_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.y = static_cast(stick_r_y_f * HID_JOYSTICK_MAX); + next_state.pad_state = button_state; + next_state.l_stick = stick_state.left; + next_state.r_stick = stick_state.right; } - std::memcpy(data, &shared_memory, sizeof(SharedMemory)); + debug_pad_lifo.WriteNextEntry(next_state); + std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo)); } -void Controller_DebugPad::OnLoadInputDevices() { - std::transform(Settings::values.debug_pad_buttons.begin(), - Settings::values.debug_pad_buttons.begin() + - Settings::NativeButton::NUM_BUTTONS_HID, - buttons.begin(), Input::CreateDevice); - std::transform(Settings::values.debug_pad_analogs.begin(), - Settings::values.debug_pad_analogs.end(), analogs.begin(), - Input::CreateDevice); -} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index e90ae8415..11b6c669b 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -10,8 +10,14 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedController; +struct DebugPadButton; +struct AnalogStickState; +} // namespace Core::HID namespace Service::HID { class Controller_DebugPad final : public ControllerBase { @@ -28,66 +34,31 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct AnalogStick { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogStick) == 0x8); - - struct PadState { - union { - u32_le raw{}; - BitField<0, 1, u32> a; - BitField<1, 1, u32> b; - BitField<2, 1, u32> x; - BitField<3, 1, u32> y; - BitField<4, 1, u32> l; - BitField<5, 1, u32> r; - BitField<6, 1, u32> zl; - BitField<7, 1, u32> zr; - BitField<8, 1, u32> plus; - BitField<9, 1, u32> minus; - BitField<10, 1, u32> d_left; - BitField<11, 1, u32> d_up; - BitField<12, 1, u32> d_right; - BitField<13, 1, u32> d_down; - }; - }; - static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); - - struct Attributes { + // This is nn::hid::DebugPadAttribute + struct DebugPadAttribute { union { u32_le raw{}; BitField<0, 1, u32> connected; }; }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); + static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); - struct PadStates { + // This is nn::hid::DebugPadState + struct DebugPadState { s64_le sampling_number; - s64_le sampling_number2; - Attributes attribute; - PadState pad_state; - AnalogStick r_stick; - AnalogStick l_stick; + DebugPadAttribute attribute; + Core::HID::DebugPadButton pad_state; + Core::HID::AnalogStickState r_stick; + Core::HID::AnalogStickState l_stick; }; - static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); + static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); - struct SharedMemory { - CommonHeader header; - std::array pad_states; - INSERT_PADDING_BYTES(0x138); - }; - static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::DebugPadLifo + Lifo debug_pad_lifo{}; + static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); + DebugPadState next_state{}; - std::array, Settings::NativeButton::NUM_BUTTONS_HID> - buttons; - std::array, Settings::NativeAnalog::NumAnalogs> - analogs; + Core::HID::EmulatedController* controller; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 772c20453..a8c93909d 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -31,10 +31,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); } -void Controller_Stubbed::OnLoadInputDevices() {} - void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { common_offset = off; smart_update = true; } + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 21092af0d..29f95a100 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -22,12 +22,17 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - void SetCommonHeaderOffset(std::size_t off); private: + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + bool smart_update{}; std::size_t common_offset{}; }; diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 41dc22cf9..29a412ff9 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -19,28 +19,19 @@ void Controller_XPad::OnRelease() {} void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - for (auto& xpad_entry : shared_memory.shared_memory_entries) { - xpad_entry.header.timestamp = core_timing.GetCPUTicks(); - xpad_entry.header.total_entry_count = 17; - - if (!IsControllerActivated()) { - xpad_entry.header.entry_count = 0; - xpad_entry.header.last_entry_index = 0; - return; - } - xpad_entry.header.entry_count = 16; - - const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; - xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; - auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + if (!IsControllerActivated()) { + basic_xpad_lifo.entry_count = 0; + basic_xpad_lifo.last_entry_index = 0; + std::memcpy(data, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + return; } + + const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; // TODO(ogniK): Update xpad states - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + basic_xpad_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); } -void Controller_XPad::OnLoadInputDevices() {} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index f9ab5facf..a5421f93b 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -8,7 +8,9 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { class Controller_XPad final : public ControllerBase { @@ -25,11 +27,9 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Attributes { + // This is nn::hid::BasicXpadAttributeSet + struct BasicXpadAttributeSet { union { u32_le raw{}; BitField<0, 1, u32> is_connected; @@ -40,9 +40,10 @@ private: BitField<5, 1, u32> is_right_wired; }; }; - static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); + static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size"); - struct Buttons { + // This is nn::hid::BasicXpadButtonSet + struct BasicXpadButtonSet { union { u32_le raw{}; // Button states @@ -88,35 +89,21 @@ private: BitField<30, 1, u32> handheld_left_b; }; }; - static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); + static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size"); - struct AnalogStick { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); - - struct XPadState { + // This is nn::hid::detail::BasicXpadState + struct BasicXpadState { s64_le sampling_number; - s64_le sampling_number2; - Attributes attributes; - Buttons pad_states; - AnalogStick l_stick; - AnalogStick r_stick; + BasicXpadAttributeSet attributes; + BasicXpadButtonSet pad_states; + Core::HID::AnalogStickState l_stick; + Core::HID::AnalogStickState r_stick; }; - static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); + static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); - struct XPadEntry { - CommonHeader header; - std::array pad_states{}; - INSERT_PADDING_BYTES(0x138); - }; - static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); - - struct SharedMemory { - std::array shared_memory_entries{}; - }; - static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::BasicXpadLifo + Lifo basic_xpad_lifo{}; + static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); + BasicXpadState next_state{}; }; } // namespace Service::HID From afe2d667d95e74be8f401010fa31a9eeca77d93a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:33:50 -0500 Subject: [PATCH 075/291] service/hid: Update touch and gestures to use ring lifo and the emulated console --- .../hle/service/hid/controllers/gesture.cpp | 274 +++++++----------- .../hle/service/hid/controllers/gesture.h | 80 ++--- .../service/hid/controllers/touchscreen.cpp | 136 +++------ .../hle/service/hid/controllers/touchscreen.h | 71 ++--- 4 files changed, 191 insertions(+), 370 deletions(-) diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 764abb5b6..2f98cc54b 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -5,8 +5,10 @@ #include "common/logging/log.h" #include "common/math_util.h" #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/gesture.h" namespace Service::HID { @@ -23,16 +25,15 @@ constexpr f32 Square(s32 num) { return static_cast(num * num); } -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} +Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) { + console = system.HIDCore().GetEmulatedConsole(); +} + Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - mouse_finger_id[id] = MAX_POINTS; - keyboard_finger_id[id] = MAX_POINTS; - udp_finger_id[id] = MAX_POINTS; - } - shared_memory.header.entry_count = 0; + gesture_lifo.entry_count = 0; + gesture_lifo.last_entry_index = 0; force_update = true; } @@ -40,50 +41,43 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - + // TODO FIND WTF IS WRONG HERE!!!!!!!! + return; if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + gesture_lifo.entry_count = 0; + gesture_lifo.last_entry_index = 0; + std::memcpy(data, &gesture_lifo, sizeof(gesture_lifo)); return; } ReadTouchInput(); GestureProperties gesture = GetGestureProperties(); - f32 time_difference = static_cast(shared_memory.header.timestamp - last_update_timestamp) / - (1000 * 1000 * 1000); + f32 time_difference = + static_cast(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = shared_memory.header.timestamp; + last_update_timestamp = gesture_lifo.timestamp; UpdateGestureSharedMemory(data, size, gesture, time_difference); } void Controller_Gesture::ReadTouchInput() { - const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); - const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); - udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); - } - - if (Settings::values.use_touch_from_button) { - const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - keyboard_finger_id[id] = - UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); - } + const auto touch_status = console->GetTouch(); + for (std::size_t id = 0; id < fingers.size(); ++id) { + const Core::HID::TouchFinger& status = touch_status[id]; + Finger& finger = fingers[id]; + finger.pos = status.position; + finger.pressed = status.pressed; } } bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; if (force_update) { force_update = false; return true; @@ -97,7 +91,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, } // Update on press and hold event after 0.5 seconds - if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && + if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && time_difference > press_delay) { return enable_press_and_tap; } @@ -108,27 +102,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, f32 time_difference) { - TouchType type = TouchType::Idle; - Attribute attributes{}; + GestureType type = GestureType::Idle; + GestureAttribute attributes{}; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - if (shared_memory.header.entry_count < 16) { - shared_memory.header.entry_count++; - } - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - // Reset values to default - cur_entry.delta = {}; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; - cur_entry.direction = Direction::None; - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + // Reset next state to default + next_state.sampling_number = last_entry.sampling_number + 1; + next_state.delta = {}; + next_state.vel_x = 0; + next_state.vel_y = 0; + next_state.direction = GestureDirection::None; + next_state.rotation_angle = 0; + next_state.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -141,46 +127,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, } // Apply attributes - cur_entry.detection_count = gesture.detection_count; - cur_entry.type = type; - cur_entry.attributes = attributes; - cur_entry.pos = gesture.mid_point; - cur_entry.point_count = static_cast(gesture.active_points); - cur_entry.points = gesture.points; + next_state.detection_count = gesture.detection_count; + next_state.type = type; + next_state.attributes = attributes; + next_state.pos = gesture.mid_point; + next_state.point_count = static_cast(gesture.active_points); + next_state.points = gesture.points; last_gesture = gesture; - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + gesture_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); } -void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, - Attribute& attributes) { - const auto& last_entry = GetLastGestureEntry(); +void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, + GestureAttribute& attributes) { + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; gesture.detection_count++; - type = TouchType::Touch; + type = GestureType::Touch; // New touch after cancel is not considered new - if (last_entry.type != TouchType::Cancel) { + if (last_entry.type != GestureType::Cancel) { attributes.is_new_touch.Assign(1); enable_press_and_tap = true; } } -void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; // Promote to pan type if touch moved for (size_t id = 0; id < MAX_POINTS; id++) { if (gesture.points[id] != last_gesture.points[id]) { - type = TouchType::Pan; + type = GestureType::Pan; break; } } // Number of fingers changed cancel the last event and clear data if (gesture.active_points != last_gesture.active_points) { - type = TouchType::Cancel; + type = GestureType::Cancel; enable_press_and_tap = false; gesture.active_points = 0; gesture.mid_point = {}; @@ -189,41 +176,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch } // Calculate extra parameters of panning - if (type == TouchType::Pan) { + if (type == GestureType::Pan) { UpdatePanEvent(gesture, last_gesture, type, time_difference); return; } // Promote to press type - if (last_entry.type == TouchType::Touch) { - type = TouchType::Press; + if (last_entry.type == GestureType::Touch) { + type = GestureType::Press; } } void Controller_Gesture::EndGesture(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, - Attribute& attributes, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); + GestureProperties& last_gesture_props, GestureType& type, + GestureAttribute& attributes, f32 time_difference) { + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; if (last_gesture_props.active_points != 0) { switch (last_entry.type) { - case TouchType::Touch: + case GestureType::Touch: if (enable_press_and_tap) { SetTapEvent(gesture, last_gesture_props, type, attributes); return; } - type = TouchType::Cancel; + type = GestureType::Cancel; force_update = true; break; - case TouchType::Press: - case TouchType::Tap: - case TouchType::Swipe: - case TouchType::Pinch: - case TouchType::Rotate: - type = TouchType::Complete; + case GestureType::Press: + case GestureType::Tap: + case GestureType::Swipe: + case GestureType::Pinch: + case GestureType::Rotate: + type = GestureType::Complete; force_update = true; break; - case TouchType::Pan: + case GestureType::Pan: EndPanEvent(gesture, last_gesture_props, type, time_difference); break; default: @@ -231,15 +218,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, } return; } - if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { + if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { gesture.detection_count++; } } void Controller_Gesture::SetTapEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, - Attribute& attributes) { - type = TouchType::Tap; + GestureProperties& last_gesture_props, GestureType& type, + GestureAttribute& attributes) { + type = GestureType::Tap; gesture = last_gesture_props; force_update = true; f32 tap_time_difference = @@ -251,44 +238,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, } void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, + GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - const auto& last_entry = GetLastGestureEntry(); + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - cur_entry.delta = gesture.mid_point - last_entry.pos; - cur_entry.vel_x = static_cast(cur_entry.delta.x) / time_difference; - cur_entry.vel_y = static_cast(cur_entry.delta.y) / time_difference; + next_state.delta = gesture.mid_point - last_entry.pos; + next_state.vel_x = static_cast(next_state.delta.x) / time_difference; + next_state.vel_y = static_cast(next_state.delta.y) / time_difference; last_pan_time_difference = time_difference; // Promote to pinch type if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > pinch_threshold) { - type = TouchType::Pinch; - cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; + type = GestureType::Pinch; + next_state.scale = gesture.average_distance / last_gesture_props.average_distance; } const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / (1 + (gesture.angle * last_gesture_props.angle))); // Promote to rotate type if (std::abs(angle_between_two_lines) > angle_threshold) { - type = TouchType::Rotate; - cur_entry.scale = 0; - cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + type = GestureType::Rotate; + next_state.scale = 0; + next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; } } void Controller_Gesture::EndPanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, + GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - const auto& last_entry = GetLastGestureEntry(); - cur_entry.vel_x = + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + next_state.vel_x = static_cast(last_entry.delta.x) / (last_pan_time_difference + time_difference); - cur_entry.vel_y = + next_state.vel_y = static_cast(last_entry.delta.y) / (last_pan_time_difference + time_difference); const f32 curr_vel = - std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); // Set swipe event with parameters if (curr_vel > swipe_threshold) { @@ -297,93 +282,34 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, } // End panning without swipe - type = TouchType::Complete; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + type = GestureType::Complete; + next_state.vel_x = 0; + next_state.vel_y = 0; force_update = true; } void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - const auto& last_entry = GetLastGestureEntry(); + GestureProperties& last_gesture_props, GestureType& type) { + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - type = TouchType::Swipe; + type = GestureType::Swipe; gesture = last_gesture_props; force_update = true; - cur_entry.delta = last_entry.delta; + next_state.delta = last_entry.delta; - if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { - if (cur_entry.delta.x > 0) { - cur_entry.direction = Direction::Right; + if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { + if (next_state.delta.x > 0) { + next_state.direction = GestureDirection::Right; return; } - cur_entry.direction = Direction::Left; + next_state.direction = GestureDirection::Left; return; } - if (cur_entry.delta.y > 0) { - cur_entry.direction = Direction::Down; + if (next_state.delta.y > 0) { + next_state.direction = GestureDirection::Down; return; } - cur_entry.direction = Direction::Up; -} - -void Controller_Gesture::OnLoadInputDevices() { - touch_mouse_device = Input::CreateDevice("engine:emu_window"); - touch_udp_device = Input::CreateDevice("engine:cemuhookudp"); - touch_btn_device = Input::CreateDevice("engine:touch_from_button"); -} - -std::optional Controller_Gesture::GetUnusedFingerID() const { - // Dont assign any touch input to a point if disabled - if (!Settings::values.touchscreen.enabled) { - return std::nullopt; - } - std::size_t first_free_id = 0; - while (first_free_id < MAX_POINTS) { - if (!fingers[first_free_id].pressed) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; -} - -const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; -} - -std::size_t Controller_Gesture::UpdateTouchInputEvent( - const std::tuple& touch_input, std::size_t finger_id) { - const auto& [x, y, pressed] = touch_input; - if (finger_id > MAX_POINTS) { - LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); - return MAX_POINTS; - } - if (pressed) { - if (finger_id == MAX_POINTS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id do nothing - return MAX_POINTS; - } - finger_id = first_free_id.value(); - fingers[finger_id].pressed = true; - } - fingers[finger_id].pos = {x, y}; - return finger_id; - } - - if (finger_id != MAX_POINTS) { - fingers[finger_id].pressed = false; - } - - return MAX_POINTS; + next_state.direction = GestureDirection::Up; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7e7ae6625..8e6f315a4 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -8,8 +8,12 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/point.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedController; +} // namespace Core::HID namespace Service::HID { class Controller_Gesture final : public ControllerBase { @@ -26,14 +30,12 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: static constexpr size_t MAX_FINGERS = 16; static constexpr size_t MAX_POINTS = 4; - enum class TouchType : u32 { + // This is nn::hid::GestureType + enum class GestureType : u32 { Idle, // Nothing touching the screen Complete, // Set at the end of a touch event Cancel, // Set when the number of fingers change @@ -46,7 +48,8 @@ private: Rotate, // All points rotating from the midpoint }; - enum class Direction : u32 { + // This is nn::hid::GestureDirection + enum class GestureDirection : u32 { None, Left, Up, @@ -54,7 +57,8 @@ private: Down, }; - struct Attribute { + // This is nn::hid::GestureAttribute + struct GestureAttribute { union { u32_le raw{}; @@ -62,31 +66,25 @@ private: BitField<8, 1, u32> is_double_tap; }; }; - static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); + static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); + // This is nn::hid::GestureState struct GestureState { s64_le sampling_number; - s64_le sampling_number2; s64_le detection_count; - TouchType type; - Direction direction; + GestureType type; + GestureDirection direction; Common::Point pos; Common::Point delta; f32 vel_x; f32 vel_y; - Attribute attributes; + GestureAttribute attributes; f32 scale; f32 rotation_angle; s32_le point_count; std::array, 4> points; }; - static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); - - struct SharedMemory { - CommonHeader header; - std::array gesture_states; - }; - static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); + static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); struct Finger { Common::Point pos{}; @@ -114,58 +112,42 @@ private: f32 time_difference); // Initializes new gesture - void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); + void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); // Updates existing gesture state - void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); + void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); // Terminates exiting gesture void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, Attribute& attributes, f32 time_difference); + GestureType& type, GestureAttribute& attributes, f32 time_difference); // Set current event to a tap event void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, Attribute& attributes); + GestureType& type, GestureAttribute& attributes); // Calculates and set the extra parameters related to a pan event void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, f32 time_difference); + GestureType& type, f32 time_difference); // Terminates the pan event void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, f32 time_difference); + GestureType& type, f32 time_difference); // Set current event to a swipe event void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type); - - // Returns an unused finger id, if there is no fingers available std::nullopt is returned. - [[nodiscard]] std::optional GetUnusedFingerID() const; - - // Retrieves the last gesture entry, as indicated by shared memory indices. - [[nodiscard]] GestureState& GetLastGestureEntry(); - [[nodiscard]] const GestureState& GetLastGestureEntry() const; - - /** - * If the touch is new it tries to assign a new finger id, if there is no fingers available no - * changes will be made. Updates the coordinates if the finger id it's already set. If the touch - * ends delays the output by one frame to set the end_touch flag before finally freeing the - * finger id - */ - size_t UpdateTouchInputEvent(const std::tuple& touch_input, - size_t finger_id); + GestureType& type); // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - SharedMemory shared_memory{}; - std::unique_ptr touch_mouse_device; - std::unique_ptr touch_udp_device; - std::unique_ptr touch_btn_device; - std::array mouse_finger_id{}; - std::array keyboard_finger_id{}; - std::array udp_finger_id{}; + // This is nn::hid::detail::GestureLifo + Lifo gesture_lifo{}; + static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); + GestureState next_state{}; + std::array fingers{}; + Core::HID::EmulatedConsole* console; + GestureProperties last_gesture{}; s64_le last_update_timestamp{}; s64_le last_tap_timestamp{}; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 6ef17acc5..e0a44d06b 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -7,72 +7,79 @@ #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/frontend/emu_window.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/touchscreen.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} +Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} { + console = system.HIDCore().GetEmulatedConsole(); +} + Controller_Touchscreen::~Controller_Touchscreen() = default; -void Controller_Touchscreen::OnInit() { - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - mouse_finger_id[id] = MAX_FINGERS; - keyboard_finger_id[id] = MAX_FINGERS; - udp_finger_id[id] = MAX_FINGERS; - } -} +void Controller_Touchscreen::OnInit() {} void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; + touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + touch_screen_lifo.entry_count = 0; + touch_screen_lifo.last_entry_index = 0; + std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = - shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + const auto touch_status = console->GetTouch(); + for (std::size_t id = 0; id < MAX_FINGERS; id++) { + const auto& current_touch = touch_status[id]; + auto& finger = fingers[id]; + finger.position = current_touch.position; + finger.id = current_touch.id; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + if (finger.attribute.start_touch) { + finger.attribute.raw = 0; + continue; + } - const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); - const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); - udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); - } + if (finger.attribute.end_touch) { + finger.attribute.raw = 0; + finger.pressed = false; + continue; + } - if (Settings::values.use_touch_from_button) { - const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - keyboard_finger_id[id] = - UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); + if (!finger.pressed && current_touch.pressed) { + finger.attribute.start_touch.Assign(1); + finger.pressed = true; + continue; + } + + if (finger.pressed && !current_touch.pressed) { + finger.attribute.raw = 0; + finger.attribute.end_touch.Assign(1); } } - std::array active_fingers; + std::array active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); const auto active_fingers_count = static_cast(std::distance(active_fingers.begin(), end_iter)); const u64 tick = core_timing.GetCPUTicks(); - cur_entry.entry_count = static_cast(active_fingers_count); + const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; + + next_state.sampling_number = last_entry.sampling_number + 1; + next_state.entry_count = static_cast(active_fingers_count); + for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - auto& touch_entry = cur_entry.states[id]; + auto& touch_entry = next_state.states[id]; if (id < active_fingers_count) { const auto& [active_x, active_y] = active_fingers[id].position; touch_entry.position = { @@ -97,66 +104,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin touch_entry.finger = 0; } } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); -} -void Controller_Touchscreen::OnLoadInputDevices() { - touch_mouse_device = Input::CreateDevice("engine:emu_window"); - touch_udp_device = Input::CreateDevice("engine:cemuhookudp"); - touch_btn_device = Input::CreateDevice("engine:touch_from_button"); -} - -std::optional Controller_Touchscreen::GetUnusedFingerID() const { - // Dont assign any touch input to a finger if disabled - if (!Settings::values.touchscreen.enabled) { - return std::nullopt; - } - std::size_t first_free_id = 0; - while (first_free_id < MAX_FINGERS) { - if (!fingers[first_free_id].pressed) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -std::size_t Controller_Touchscreen::UpdateTouchInputEvent( - const std::tuple& touch_input, std::size_t finger_id) { - const auto& [x, y, pressed] = touch_input; - if (finger_id > MAX_FINGERS) { - LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); - return MAX_FINGERS; - } - if (pressed) { - Attributes attribute{}; - if (finger_id == MAX_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id do nothing - return MAX_FINGERS; - } - finger_id = first_free_id.value(); - fingers[finger_id].pressed = true; - fingers[finger_id].id = static_cast(finger_id); - attribute.start_touch.Assign(1); - } - fingers[finger_id].position = {x, y}; - fingers[finger_id].attribute = attribute; - return finger_id; - } - - if (finger_id != MAX_FINGERS) { - if (!fingers[finger_id].attribute.end_touch) { - fingers[finger_id].attribute.end_touch.Assign(1); - fingers[finger_id].attribute.start_touch.Assign(0); - return finger_id; - } - fingers[finger_id].pressed = false; - } - - return MAX_FINGERS; + touch_screen_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 8e9b40c0a..bcf79237d 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,18 +9,22 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" -#include "core/frontend/input.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { class Controller_Touchscreen final : public ControllerBase { public: + // This is nn::hid::TouchScreenModeForNx enum class TouchScreenModeForNx : u8 { UseSystemSetting, Finger, Heat2, }; + // This is nn::hid::TouchScreenConfigurationForNx struct TouchScreenConfigurationForNx { TouchScreenModeForNx mode; INSERT_PADDING_BYTES_NOINIT(0x7); @@ -41,73 +45,32 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: static constexpr std::size_t MAX_FINGERS = 16; - // Returns an unused finger id, if there is no fingers available std::nullopt will be returned - std::optional GetUnusedFingerID() const; - - // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no - // changes will be made. Updates the coordinates if the finger id it's already set. If the touch - // ends delays the output by one frame to set the end_touch flag before finally freeing the - // finger id - std::size_t UpdateTouchInputEvent(const std::tuple& touch_input, - std::size_t finger_id); - - struct Attributes { - union { - u32 raw{}; - BitField<0, 1, u32> start_touch; - BitField<1, 1, u32> end_touch; - }; - }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - - struct TouchState { - u64_le delta_time; - Attributes attribute; - u32_le finger; - Common::Point position; - u32_le diameter_x; - u32_le diameter_y; - u32_le rotation_angle; - }; - static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); - - struct TouchScreenEntry { + // This is nn::hid::TouchScreenState + struct TouchScreenState { s64_le sampling_number; - s64_le sampling_number2; s32_le entry_count; - std::array states; + INSERT_PADDING_BYTES(4); // Reserved + std::array states; }; - static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); - - struct TouchScreenSharedMemory { - CommonHeader header; - std::array shared_memory_entries{}; - INSERT_PADDING_BYTES(0x3c8); - }; - static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, - "TouchScreenSharedMemory is an invalid size"); + static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); struct Finger { u64_le last_touch{}; Common::Point position; u32_le id{}; bool pressed{}; - Attributes attribute; + Core::HID::TouchAttribute attribute; }; - TouchScreenSharedMemory shared_memory{}; - std::unique_ptr touch_mouse_device; - std::unique_ptr touch_udp_device; - std::unique_ptr touch_btn_device; - std::array mouse_finger_id; - std::array keyboard_finger_id; - std::array udp_finger_id; + // This is nn::hid::detail::TouchScreenLifo + Lifo touch_screen_lifo{}; + static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); + TouchScreenState next_state{}; + std::array fingers; + Core::HID::EmulatedConsole* console; }; } // namespace Service::HID From 800a66d25a214363d1d06b68a59f315ed295f9e4 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:35:27 -0500 Subject: [PATCH 076/291] service/hid: Update mouse and keyboard to use ring lifo and the emulated device --- .../hle/service/hid/controllers/keyboard.cpp | 56 ++++++----------- .../hle/service/hid/controllers/keyboard.h | 53 +++++----------- .../hle/service/hid/controllers/mouse.cpp | 60 ++++++++----------- src/core/hle/service/hid/controllers/mouse.h | 58 ++++-------------- 4 files changed, 70 insertions(+), 157 deletions(-) diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index c6c620008..db0f56b92 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -5,14 +5,19 @@ #include #include "common/common_types.h" #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/keyboard.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; constexpr u8 KEYS_PER_BYTE = 8; -Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {} +Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} { + emulated_devices = system.HIDCore().GetEmulatedDevices(); +} + Controller_Keyboard::~Controller_Keyboard() = default; void Controller_Keyboard::OnInit() {} @@ -21,51 +26,26 @@ void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + keyboard_lifo.entry_count = 0; + keyboard_lifo.last_entry_index = 0; + std::memcpy(data, &keyboard_lifo, sizeof(keyboard_lifo)); return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - cur_entry.key.fill(0); if (Settings::values.keyboard_enabled) { - for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { - auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; - entry = static_cast(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); - } + const auto& keyboard_state = emulated_devices->GetKeyboard(); + const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier(); - using namespace Settings::NativeKeyboard; - - // TODO: Assign the correct key to all modifiers - cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus()); - cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus()); - cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus()); - cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus()); - cur_entry.modifier.gui.Assign(0); - cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus()); - cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus()); - cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus()); - cur_entry.modifier.katakana.Assign(0); - cur_entry.modifier.hiragana.Assign(0); + next_state.key = keyboard_state; + next_state.modifier = keyboard_modifier_state; } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + + keyboard_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); } -void Controller_Keyboard::OnLoadInputDevices() { - std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_keys.begin(), Input::CreateDevice); - std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), - keyboard_mods.begin(), Input::CreateDevice); -} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 172a80e9c..6919e092a 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -10,8 +10,14 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedDevices; +struct KeyboardModifier; +struct KeyboardKey; +} // namespace Core::HID namespace Service::HID { class Controller_Keyboard final : public ControllerBase { @@ -28,47 +34,20 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Modifiers { - union { - u32_le raw{}; - BitField<0, 1, u32> control; - BitField<1, 1, u32> shift; - BitField<2, 1, u32> left_alt; - BitField<3, 1, u32> right_alt; - BitField<4, 1, u32> gui; - BitField<8, 1, u32> caps_lock; - BitField<9, 1, u32> scroll_lock; - BitField<10, 1, u32> num_lock; - BitField<11, 1, u32> katakana; - BitField<12, 1, u32> hiragana; - }; - }; - static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size"); - + // This is nn::hid::detail::KeyboardState struct KeyboardState { s64_le sampling_number; - s64_le sampling_number2; - - Modifiers modifier; - std::array key; + Core::HID::KeyboardModifier modifier; + Core::HID::KeyboardKey key; }; - static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); + static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); - struct SharedMemory { - CommonHeader header; - std::array pad_states; - INSERT_PADDING_BYTES(0x28); - }; - static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::KeyboardLifo + Lifo keyboard_lifo{}; + static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); + KeyboardState next_state{}; - std::array, Settings::NativeKeyboard::NumKeyboardKeys> - keyboard_keys; - std::array, Settings::NativeKeyboard::NumKeyboardMods> - keyboard_mods; + Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 2211f1144..2f607bfe9 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -4,14 +4,19 @@ #include #include "common/common_types.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/mouse.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {} +Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} { + emulated_devices = system.HIDCore().GetEmulatedDevices(); +} + Controller_Mouse::~Controller_Mouse() = default; void Controller_Mouse::OnInit() {} @@ -19,50 +24,35 @@ void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; + mouse_lifo.timestamp = core_timing.GetCPUTicks(); if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + mouse_lifo.entry_count = 0; + mouse_lifo.last_entry_index = 0; + std::memcpy(data, &mouse_lifo, sizeof(mouse_lifo)); return; } - shared_memory.header.entry_count = 16; - auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; + const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - cur_entry.attribute.raw = 0; + next_state.attribute.raw = 0; if (Settings::values.mouse_enabled) { - const auto [px, py, sx, sy] = mouse_device->GetStatus(); - const auto x = static_cast(px * Layout::ScreenUndocked::Width); - const auto y = static_cast(py * Layout::ScreenUndocked::Height); - cur_entry.x = x; - cur_entry.y = y; - cur_entry.delta_x = x - last_entry.x; - cur_entry.delta_y = y - last_entry.y; - cur_entry.mouse_wheel_x = sx; - cur_entry.mouse_wheel_y = sy; - cur_entry.attribute.is_connected.Assign(1); + const auto& mouse_button_state = emulated_devices->GetMouseButtons(); + const auto& mouse_position_state = emulated_devices->GetMousePosition(); + next_state.attribute.is_connected.Assign(1); + next_state.x = mouse_position_state.x; + next_state.y = mouse_position_state.y; + next_state.delta_x = next_state.x - last_entry.x; + next_state.delta_y = next_state.y - last_entry.y; + next_state.delta_wheel_x = mouse_position_state.delta_wheel_x; + next_state.delta_wheel_y = mouse_position_state.delta_wheel_y; - using namespace Settings::NativeMouseButton; - cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus()); - cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus()); - cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus()); - cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus()); - cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus()); + next_state.button = mouse_button_state; } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + mouse_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); } -void Controller_Mouse::OnLoadInputDevices() { - //mouse_device = Input::CreateDevice(Settings::values.mouse_device); - std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), - mouse_button_devices.begin(), Input::CreateDevice); -} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 3d391a798..ce868a247 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -9,8 +9,13 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedDevices; +struct MouseState; +} // namespace Core::HID namespace Service::HID { class Controller_Mouse final : public ControllerBase { @@ -27,53 +32,12 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Buttons { - union { - u32_le raw{}; - BitField<0, 1, u32> left; - BitField<1, 1, u32> right; - BitField<2, 1, u32> middle; - BitField<3, 1, u32> forward; - BitField<4, 1, u32> back; - }; - }; - static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size"); + // This is nn::hid::detail::MouseLifo + Lifo mouse_lifo{}; + static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); + Core::HID::MouseState next_state{}; - struct Attributes { - union { - u32_le raw{}; - BitField<0, 1, u32> transferable; - BitField<1, 1, u32> is_connected; - }; - }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - - struct MouseState { - s64_le sampling_number; - s64_le sampling_number2; - s32_le x; - s32_le y; - s32_le delta_x; - s32_le delta_y; - s32_le mouse_wheel_x; - s32_le mouse_wheel_y; - Buttons button; - Attributes attribute; - }; - static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); - - struct SharedMemory { - CommonHeader header; - std::array mouse_states; - }; - SharedMemory shared_memory{}; - - std::unique_ptr mouse_device; - std::array, Settings::NativeMouseButton::NumMouseButtons> - mouse_button_devices; + Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID From a2ad5762e61f5d63d9a8c8a409f32c24409df67f Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:36:05 -0500 Subject: [PATCH 077/291] service/hid: Update console sixaxis to the emulated console --- .../hid/controllers/console_sixaxis.cpp | 33 ++++++++----------- .../service/hid/controllers/console_sixaxis.h | 21 +++++++----- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index bda6e2557..1d351fde0 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" @@ -10,7 +11,10 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) - : ControllerBase{system_} {} + : ControllerBase{system_} { + console = system.HIDCore().GetEmulatedConsole(); +} + Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; void Controller_ConsoleSixAxis::OnInit() {} @@ -38,25 +42,21 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti cur_entry.sampling_number2 = cur_entry.sampling_number; // Try to read sixaxis sensor states - MotionDevice motion_device{}; - const auto& device = motions[0]; - if (device) { - std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation, - motion_device.orientation, motion_device.quaternion) = device->GetStatus(); - console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f; - } + const auto motion_status = console->GetMotion(); - cur_entry.accel = motion_device.accel; + console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; + + cur_entry.accel = motion_status.accel; // Zero gyro values as they just mess up with the camera // Note: Probably a correct sensivity setting must be set cur_entry.gyro = {}; cur_entry.quaternion = { { - motion_device.quaternion.xyz.y, - motion_device.quaternion.xyz.x, - -motion_device.quaternion.w, + motion_status.quaternion.xyz.y, + motion_status.quaternion.xyz.x, + -motion_status.quaternion.w, }, - -motion_device.quaternion.xyz.z, + -motion_status.quaternion.xyz.z, }; console_six_axis.sampling_number++; @@ -70,13 +70,6 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); } -void Controller_ConsoleSixAxis::OnLoadInputDevices() { - const auto player = Settings::values.players.GetValue()[0]; - std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, - player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(), - Input::CreateDevice); -} - void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { is_transfer_memory_set = true; transfer_memory = t_mem; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index fd8a427af..6d18d2ce0 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -5,10 +5,10 @@ #pragma once #include -#include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" -#include "core/frontend/input.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" namespace Service::HID { @@ -26,9 +26,6 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - // Called on InitializeSevenSixAxisSensor void SetTransferMemoryPointer(u8* t_mem); @@ -47,12 +44,22 @@ private: }; static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + // TODO(german77): SevenSixAxisMemory doesn't follow the standard lifo. Investigate struct SevenSixAxisMemory { CommonHeader header{}; std::array sevensixaxis_states{}; }; static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); + // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { u64_le sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; @@ -69,9 +76,7 @@ private: Common::Quaternion quaternion; }; - using MotionArray = - std::array, Settings::NativeMotion::NUM_MOTIONS_HID>; - MotionArray motions; + Core::HID::EmulatedConsole* console; u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; ConsoleSharedMemory console_six_axis{}; From c87ad2d0d635d8786c48fed856e1bcf1ecc154bf Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:37:50 -0500 Subject: [PATCH 078/291] service/hid: Rewrite npad to use ring lifo and the emulated controller --- src/core/hle/service/hid/controllers/npad.cpp | 1116 +++++++---------- src/core/hle/service/hid/controllers/npad.h | 393 ++---- 2 files changed, 612 insertions(+), 897 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 196876810..03cbd42f4 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -12,7 +12,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/input.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" @@ -20,64 +19,13 @@ #include "core/hle/service/kernel_helpers.h" namespace Service::HID { -constexpr s32 HID_JOYSTICK_MAX = 0x7fff; -constexpr s32 HID_TRIGGER_MAX = 0x7fff; -[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; constexpr std::size_t NPAD_OFFSET = 0x9A00; -constexpr u32 BATTERY_FULL = 2; constexpr u32 MAX_NPAD_ID = 7; constexpr std::size_t HANDHELD_INDEX = 8; constexpr std::array npad_id_list{ 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, }; -enum class JoystickId : std::size_t { - Joystick_Left, - Joystick_Right, -}; - -Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad( - Settings::ControllerType type) { - switch (type) { - case Settings::ControllerType::ProController: - return NPadControllerType::ProController; - case Settings::ControllerType::DualJoyconDetached: - return NPadControllerType::JoyDual; - case Settings::ControllerType::LeftJoycon: - return NPadControllerType::JoyLeft; - case Settings::ControllerType::RightJoycon: - return NPadControllerType::JoyRight; - case Settings::ControllerType::Handheld: - return NPadControllerType::Handheld; - case Settings::ControllerType::GameCube: - return NPadControllerType::GameCube; - default: - UNREACHABLE(); - return NPadControllerType::ProController; - } -} - -Settings::ControllerType Controller_NPad::MapNPadToSettingsType( - Controller_NPad::NPadControllerType type) { - switch (type) { - case NPadControllerType::ProController: - return Settings::ControllerType::ProController; - case NPadControllerType::JoyDual: - return Settings::ControllerType::DualJoyconDetached; - case NPadControllerType::JoyLeft: - return Settings::ControllerType::LeftJoycon; - case NPadControllerType::JoyRight: - return Settings::ControllerType::RightJoycon; - case NPadControllerType::Handheld: - return Settings::ControllerType::Handheld; - case NPadControllerType::GameCube: - return Settings::ControllerType::GameCube; - default: - UNREACHABLE(); - return Settings::ControllerType::ProController; - } -} - std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { switch (npad_id) { case 0: @@ -143,118 +91,157 @@ bool Controller_NPad::IsNpadIdValid(u32 npad_id) { bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { return IsNpadIdValid(device_handle.npad_id) && - device_handle.npad_type < NpadType::MaxNpadType && + device_handle.npad_type < Core::HID::NpadType::MaxNpadType && device_handle.device_index < DeviceIndex::MaxDeviceIndex; } Controller_NPad::Controller_NPad(Core::System& system_, KernelHelpers::ServiceContext& service_context_) : ControllerBase{system_}, service_context{service_context_} { - latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + controller.device = system.HIDCore().GetEmulatedControllerByIndex(i); + controller.vibration[0].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + controller.vibration[1].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + Core::HID::ControllerUpdateCallback engine_callback{ + [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }}; + controller.callback_key = controller.device->SetCallback(engine_callback); + } } Controller_NPad::~Controller_NPad() { + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + controller.device->DeleteCallback(controller.callback_key); + } OnRelease(); } -void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { - const auto controller_type = connected_controllers[controller_idx].type; - auto& controller = shared_memory_entries[controller_idx]; - if (controller_type == NPadControllerType::None) { - styleset_changed_events[controller_idx]->GetWritableEvent().Signal(); +void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, + std::size_t controller_idx) { + if (type == Core::HID::ControllerTriggerType::All) { + ControllerUpdate(Core::HID::ControllerTriggerType::Type, controller_idx); + ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); return; } - controller.style_set.raw = 0; // Zero out - controller.device_type.raw = 0; - controller.system_properties.raw = 0; + + switch (type) { + case Core::HID::ControllerTriggerType::Connected: + InitNewlyAddedController(controller_idx); + break; + case Core::HID::ControllerTriggerType::Disconnected: + DisconnectNpadAtIndex(controller_idx); + break; + case Core::HID::ControllerTriggerType::Type: { + auto& controller = controller_data[controller_idx]; + if (controller.device->IsConnected()) { + LOG_ERROR(Service_HID, "Controller type changed without turning off the controller"); + } + break; + } + default: + break; + } +} + +void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { + auto& controller = controller_data[controller_idx]; + const auto controller_type = controller.device->GetNpadType(); + auto& shared_memory = controller.shared_memory_entry; + if (controller_type == Core::HID::NpadType::None) { + controller.styleset_changed_event->GetWritableEvent().Signal(); + return; + } + shared_memory.style_set.raw = 0; // Zero out + shared_memory.device_type.raw = 0; + shared_memory.system_properties.raw = 0; switch (controller_type) { - case NPadControllerType::None: + case Core::HID::NpadType::None: UNREACHABLE(); break; - case NPadControllerType::ProController: - controller.style_set.fullkey.Assign(1); - controller.device_type.fullkey.Assign(1); - controller.system_properties.is_vertical.Assign(1); - controller.system_properties.use_plus.Assign(1); - controller.system_properties.use_minus.Assign(1); - controller.assignment_mode = NpadAssignments::Single; - controller.footer_type = AppletFooterUiType::SwitchProController; + case Core::HID::NpadType::ProController: + shared_memory.style_set.fullkey.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; + shared_memory.footer_type = AppletFooterUiType::SwitchProController; break; - case NPadControllerType::Handheld: - controller.style_set.handheld.Assign(1); - controller.device_type.handheld_left.Assign(1); - controller.device_type.handheld_right.Assign(1); - controller.system_properties.is_vertical.Assign(1); - controller.system_properties.use_plus.Assign(1); - controller.system_properties.use_minus.Assign(1); - controller.assignment_mode = NpadAssignments::Dual; - controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; + case Core::HID::NpadType::Handheld: + shared_memory.style_set.handheld.Assign(1); + shared_memory.device_type.handheld_left.Assign(1); + shared_memory.device_type.handheld_right.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; - case NPadControllerType::JoyDual: - controller.style_set.joycon_dual.Assign(1); - controller.device_type.joycon_left.Assign(1); - controller.device_type.joycon_right.Assign(1); - controller.system_properties.is_vertical.Assign(1); - controller.system_properties.use_plus.Assign(1); - controller.system_properties.use_minus.Assign(1); - controller.assignment_mode = NpadAssignments::Dual; - controller.footer_type = AppletFooterUiType::JoyDual; + case Core::HID::NpadType::JoyconDual: + shared_memory.style_set.joycon_dual.Assign(1); + shared_memory.device_type.joycon_left.Assign(1); + shared_memory.device_type.joycon_right.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory.footer_type = AppletFooterUiType::JoyDual; break; - case NPadControllerType::JoyLeft: - controller.style_set.joycon_left.Assign(1); - controller.device_type.joycon_left.Assign(1); - controller.system_properties.is_horizontal.Assign(1); - controller.system_properties.use_minus.Assign(1); - controller.assignment_mode = NpadAssignments::Single; - controller.footer_type = AppletFooterUiType::JoyLeftHorizontal; + case Core::HID::NpadType::JoyconLeft: + shared_memory.style_set.joycon_left.Assign(1); + shared_memory.device_type.joycon_left.Assign(1); + shared_memory.system_properties.is_horizontal.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; + shared_memory.footer_type = AppletFooterUiType::JoyLeftHorizontal; break; - case NPadControllerType::JoyRight: - controller.style_set.joycon_right.Assign(1); - controller.device_type.joycon_right.Assign(1); - controller.system_properties.is_horizontal.Assign(1); - controller.system_properties.use_plus.Assign(1); - controller.assignment_mode = NpadAssignments::Single; - controller.footer_type = AppletFooterUiType::JoyRightHorizontal; + case Core::HID::NpadType::JoyconRight: + shared_memory.style_set.joycon_right.Assign(1); + shared_memory.device_type.joycon_right.Assign(1); + shared_memory.system_properties.is_horizontal.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; + shared_memory.footer_type = AppletFooterUiType::JoyRightHorizontal; break; - case NPadControllerType::GameCube: - controller.style_set.gamecube.Assign(1); + case Core::HID::NpadType::GameCube: + shared_memory.style_set.gamecube.Assign(1); // The GC Controller behaves like a wired Pro Controller - controller.device_type.fullkey.Assign(1); - controller.system_properties.is_vertical.Assign(1); - controller.system_properties.use_plus.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); break; - case NPadControllerType::Pokeball: - controller.style_set.palma.Assign(1); - controller.device_type.palma.Assign(1); - controller.assignment_mode = NpadAssignments::Single; + case Core::HID::NpadType::Pokeball: + shared_memory.style_set.palma.Assign(1); + shared_memory.device_type.palma.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; + break; + default: break; } - controller.fullkey_color.attribute = ColorAttributes::Ok; - controller.fullkey_color.fullkey.body = 0; - controller.fullkey_color.fullkey.button = 0; + const auto& body_colors = controller.device->GetColors(); - controller.joycon_color.attribute = ColorAttributes::Ok; - controller.joycon_color.left.body = - Settings::values.players.GetValue()[controller_idx].body_color_left; - controller.joycon_color.left.button = - Settings::values.players.GetValue()[controller_idx].button_color_left; - controller.joycon_color.right.body = - Settings::values.players.GetValue()[controller_idx].body_color_right; - controller.joycon_color.right.button = - Settings::values.players.GetValue()[controller_idx].button_color_right; + shared_memory.fullkey_color.attribute = ColorAttribute::Ok; + shared_memory.fullkey_color.fullkey = body_colors.fullkey; + + shared_memory.joycon_color.attribute = ColorAttribute::Ok; + shared_memory.joycon_color.left = body_colors.left; + shared_memory.joycon_color.right = body_colors.right; // TODO: Investigate when we should report all batery types - controller.battery_level_dual = BATTERY_FULL; - controller.battery_level_left = BATTERY_FULL; - controller.battery_level_right = BATTERY_FULL; + const auto& battery_level = controller.device->GetBattery(); + shared_memory.battery_level_dual = battery_level.dual.battery_level; + shared_memory.battery_level_left = battery_level.left.battery_level; + shared_memory.battery_level_right = battery_level.right.battery_level; SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); } void Controller_NPad::OnInit() { - for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - styleset_changed_events[i] = + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + controller.styleset_changed_event = service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } @@ -262,10 +249,9 @@ void Controller_NPad::OnInit() { return; } - OnLoadInputDevices(); - - if (style.raw == 0) { + if (system.HIDCore().GetSupportedStyleTag().raw == 0) { // We want to support all controllers + Core::HID::NpadStyleTag style{}; style.handheld.Assign(1); style.joycon_left.Assign(1); style.joycon_right.Assign(1); @@ -273,173 +259,98 @@ void Controller_NPad::OnInit() { style.fullkey.Assign(1); style.gamecube.Assign(1); style.palma.Assign(1); - } - - std::transform(Settings::values.players.GetValue().begin(), - Settings::values.players.GetValue().end(), connected_controllers.begin(), - [](const Settings::PlayerInput& player) { - return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), - player.connected}; - }); - - // Connect the Player 1 or Handheld controller if none are connected. - if (std::none_of(connected_controllers.begin(), connected_controllers.end(), - [](const ControllerHolder& controller) { return controller.is_connected; })) { - const auto controller = - MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type); - if (controller == NPadControllerType::Handheld) { - Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; - connected_controllers[HANDHELD_INDEX] = {controller, true}; - } else { - Settings::values.players.GetValue()[0].connected = true; - connected_controllers[0] = {controller, true}; - } - } - - // Account for handheld - if (connected_controllers[HANDHELD_INDEX].is_connected) { - connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; + system.HIDCore().SetSupportedStyleTag(style); } supported_npad_id_types.resize(npad_id_list.size()); std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), npad_id_list.size() * sizeof(u32)); - for (std::size_t i = 0; i < connected_controllers.size(); ++i) { - const auto& controller = connected_controllers[i]; - if (controller.is_connected) { - AddNewControllerAt(controller.type, i); + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i].device; + if (controller->IsConnected()) { + AddNewControllerAt(controller->GetNpadType(), i); } } -} -void Controller_NPad::OnLoadInputDevices() { - const auto& players = Settings::values.players.GetValue(); - - std::lock_guard lock{mutex}; - for (std::size_t i = 0; i < players.size(); ++i) { - std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, - buttons[i].begin(), Input::CreateDevice); - std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, - players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, - sticks[i].begin(), Input::CreateDevice); - std::transform(players[i].vibrations.begin() + - Settings::NativeVibration::VIBRATION_HID_BEGIN, - players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, - vibrations[i].begin(), Input::CreateDevice); - std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, - players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, - motions[i].begin(), Input::CreateDevice); - for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) { - InitializeVibrationDeviceAtIndex(i, device_idx); + // Prefill controller buffers + for (auto& controller : controller_data) { + NPadGenericState dummy_pad_state{}; + auto& npad = controller.shared_memory_entry; + for (std::size_t i = 0; i < 17; ++i) { + dummy_pad_state.sampling_number = + npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; + npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); + npad.handheld_lifo.WriteNextEntry(dummy_pad_state); + npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); + npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); + npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); + npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); + npad.palma_lifo.WriteNextEntry(dummy_pad_state); } } } void Controller_NPad::OnRelease() { - for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { - for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { - VibrateControllerAtIndex(npad_idx, device_idx, {}); + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + service_context.CloseEvent(controller.styleset_changed_event); + for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { + VibrateControllerAtIndex(i, device_idx, {}); } } - - for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - service_context.CloseEvent(styleset_changed_events[i]); - } } void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { std::lock_guard lock{mutex}; - const auto controller_idx = NPadIdToIndex(npad_id); - const auto controller_type = connected_controllers[controller_idx].type; - if (!connected_controllers[controller_idx].is_connected) { + auto& controller = controller_data[controller_idx]; + const auto controller_type = controller.device->GetNpadType(); + if (!controller.device->IsConnected()) { return; } - auto& pad_state = npad_pad_states[controller_idx].pad_states; - auto& lstick_entry = npad_pad_states[controller_idx].l_stick; - auto& rstick_entry = npad_pad_states[controller_idx].r_stick; - auto& trigger_entry = npad_trigger_states[controller_idx]; - const auto& button_state = buttons[controller_idx]; - const auto& analog_state = sticks[controller_idx]; - const auto [stick_l_x_f, stick_l_y_f] = - analog_state[static_cast(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analog_state[static_cast(JoystickId::Joystick_Right)]->GetStatus(); - using namespace Settings::NativeButton; - if (controller_type != NPadControllerType::JoyLeft) { - pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); + auto& pad_entry = controller.npad_pad_state; + auto& trigger_entry = controller.npad_trigger_state; + const auto button_state = controller.device->GetNpadButtons(); + const auto stick_state = controller.device->GetSticks(); - pad_state.r_stick_right.Assign( - analog_state[static_cast(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); - pad_state.r_stick_left.Assign( - analog_state[static_cast(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); - pad_state.r_stick_up.Assign( - analog_state[static_cast(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); - pad_state.r_stick_down.Assign( - analog_state[static_cast(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); - rstick_entry.x = static_cast(stick_r_x_f * HID_JOYSTICK_MAX); - rstick_entry.y = static_cast(stick_r_y_f * HID_JOYSTICK_MAX); + using btn = Core::HID::NpadButton; + pad_entry.npad_buttons.raw = btn::None; + if (controller_type != Core::HID::NpadType::JoyconLeft) { + constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | + btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | + btn::StickRRight | btn::StickRDown; + pad_entry.npad_buttons.raw |= button_state.raw & right_button_mask; + pad_entry.r_stick = stick_state.right; } - if (controller_type != NPadControllerType::JoyRight) { - pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); - - pad_state.l_stick_right.Assign( - analog_state[static_cast(JoystickId::Joystick_Left)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); - pad_state.l_stick_left.Assign( - analog_state[static_cast(JoystickId::Joystick_Left)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); - pad_state.l_stick_up.Assign( - analog_state[static_cast(JoystickId::Joystick_Left)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); - pad_state.l_stick_down.Assign( - analog_state[static_cast(JoystickId::Joystick_Left)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); - lstick_entry.x = static_cast(stick_l_x_f * HID_JOYSTICK_MAX); - lstick_entry.y = static_cast(stick_l_y_f * HID_JOYSTICK_MAX); + if (controller_type != Core::HID::NpadType::JoyconRight) { + constexpr btn left_button_mask = + btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL | + btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown; + pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask; + pad_entry.l_stick = stick_state.left; } - if (controller_type == NPadControllerType::JoyLeft) { - pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); + if (controller_type == Core::HID::NpadType::JoyconLeft) { + 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 == NPadControllerType::JoyRight) { - pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); + if (controller_type == Core::HID::NpadType::JoyconRight) { + pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); + pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); } - if (controller_type == NPadControllerType::GameCube) { - trigger_entry.l_analog = static_cast( - button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); - trigger_entry.r_analog = static_cast( - button_state[ZR - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); - pad_state.zl.Assign(false); - pad_state.zr.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); + if (controller_type == Core::HID::NpadType::GameCube) { + const auto& trigger_state = controller.device->GetTriggers(); + trigger_entry.l_analog = trigger_state.left; + trigger_entry.r_analog = trigger_state.right; + pad_entry.npad_buttons.zl.Assign(false); + pad_entry.npad_buttons.zr.Assign(button_state.r); + pad_entry.npad_buttons.l.Assign(button_state.zl); + pad_entry.npad_buttons.r.Assign(button_state.zr); } } @@ -448,173 +359,124 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (!IsControllerActivated()) { return; } - for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { - auto& npad = shared_memory_entries[i]; - const std::array controller_npads{ - &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states, - &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states, - &npad.system_ext_states}; + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + auto& npad = controller.shared_memory_entry; - // There is the posibility to have more controllers with analog triggers - const std::array controller_triggers{ - &npad.gc_trigger_states, - }; + const auto& controller_type = controller.device->GetNpadType(); - for (auto* main_controller : controller_npads) { - main_controller->common.entry_count = 16; - main_controller->common.total_entry_count = 17; - - const auto& last_entry = - main_controller->npad[main_controller->common.last_entry_index]; - - main_controller->common.timestamp = core_timing.GetCPUTicks(); - main_controller->common.last_entry_index = - (main_controller->common.last_entry_index + 1) % 17; - - auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index]; - - cur_entry.timestamp = last_entry.timestamp + 1; - cur_entry.timestamp2 = cur_entry.timestamp; - } - - for (auto* analog_trigger : controller_triggers) { - analog_trigger->entry_count = 16; - analog_trigger->total_entry_count = 17; - - const auto& last_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; - - analog_trigger->timestamp = core_timing.GetCPUTicks(); - analog_trigger->last_entry_index = (analog_trigger->last_entry_index + 1) % 17; - - auto& cur_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; - - cur_entry.timestamp = last_entry.timestamp + 1; - cur_entry.timestamp2 = cur_entry.timestamp; - } - - const auto& controller_type = connected_controllers[i].type; - - if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { + if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { continue; } const u32 npad_index = static_cast(i); RequestPadStateUpdate(npad_index); - auto& pad_state = npad_pad_states[npad_index]; - auto& trigger_state = npad_trigger_states[npad_index]; - - auto& main_controller = - npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index]; - auto& handheld_entry = - npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; - auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index]; - auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index]; - auto& right_entry = - npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index]; - auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index]; - auto& libnx_entry = - npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index]; - auto& trigger_entry = - npad.gc_trigger_states.trigger[npad.gc_trigger_states.last_entry_index]; - - libnx_entry.connection_status.raw = 0; - libnx_entry.connection_status.is_connected.Assign(1); - - switch (controller_type) { - case NPadControllerType::None: - UNREACHABLE(); - break; - case NPadControllerType::ProController: - main_controller.connection_status.raw = 0; - main_controller.connection_status.is_connected.Assign(1); - main_controller.connection_status.is_wired.Assign(1); - main_controller.pad.pad_states.raw = pad_state.pad_states.raw; - main_controller.pad.l_stick = pad_state.l_stick; - main_controller.pad.r_stick = pad_state.r_stick; - - libnx_entry.connection_status.is_wired.Assign(1); - break; - case NPadControllerType::Handheld: - handheld_entry.connection_status.raw = 0; - handheld_entry.connection_status.is_connected.Assign(1); - handheld_entry.connection_status.is_wired.Assign(1); - handheld_entry.connection_status.is_left_connected.Assign(1); - handheld_entry.connection_status.is_right_connected.Assign(1); - handheld_entry.connection_status.is_left_wired.Assign(1); - handheld_entry.connection_status.is_right_wired.Assign(1); - handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; - handheld_entry.pad.l_stick = pad_state.l_stick; - handheld_entry.pad.r_stick = pad_state.r_stick; - - libnx_entry.connection_status.is_wired.Assign(1); - libnx_entry.connection_status.is_left_connected.Assign(1); - libnx_entry.connection_status.is_right_connected.Assign(1); - libnx_entry.connection_status.is_left_wired.Assign(1); - libnx_entry.connection_status.is_right_wired.Assign(1); - break; - case NPadControllerType::JoyDual: - dual_entry.connection_status.raw = 0; - dual_entry.connection_status.is_connected.Assign(1); - dual_entry.connection_status.is_left_connected.Assign(1); - dual_entry.connection_status.is_right_connected.Assign(1); - dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; - dual_entry.pad.l_stick = pad_state.l_stick; - dual_entry.pad.r_stick = pad_state.r_stick; - - libnx_entry.connection_status.is_left_connected.Assign(1); - libnx_entry.connection_status.is_right_connected.Assign(1); - break; - case NPadControllerType::JoyLeft: - left_entry.connection_status.raw = 0; - left_entry.connection_status.is_connected.Assign(1); - left_entry.connection_status.is_left_connected.Assign(1); - left_entry.pad.pad_states.raw = pad_state.pad_states.raw; - left_entry.pad.l_stick = pad_state.l_stick; - left_entry.pad.r_stick = pad_state.r_stick; - - libnx_entry.connection_status.is_left_connected.Assign(1); - break; - case NPadControllerType::JoyRight: - right_entry.connection_status.raw = 0; - right_entry.connection_status.is_connected.Assign(1); - right_entry.connection_status.is_right_connected.Assign(1); - right_entry.pad.pad_states.raw = pad_state.pad_states.raw; - right_entry.pad.l_stick = pad_state.l_stick; - right_entry.pad.r_stick = pad_state.r_stick; - - libnx_entry.connection_status.is_right_connected.Assign(1); - break; - case NPadControllerType::GameCube: - main_controller.connection_status.raw = 0; - main_controller.connection_status.is_connected.Assign(1); - main_controller.connection_status.is_wired.Assign(1); - main_controller.pad.pad_states.raw = pad_state.pad_states.raw; - main_controller.pad.l_stick = pad_state.l_stick; - main_controller.pad.r_stick = pad_state.r_stick; - trigger_entry.l_analog = trigger_state.l_analog; - trigger_entry.r_analog = trigger_state.r_analog; - - libnx_entry.connection_status.is_wired.Assign(1); - break; - case NPadControllerType::Pokeball: - pokeball_entry.connection_status.raw = 0; - pokeball_entry.connection_status.is_connected.Assign(1); - pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; - pokeball_entry.pad.l_stick = pad_state.l_stick; - pokeball_entry.pad.r_stick = pad_state.r_stick; - break; - } + auto& pad_state = controller.npad_pad_state; + auto& libnx_state = controller.npad_libnx_state; + auto& trigger_state = controller.npad_trigger_state; // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate // any controllers. - libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; - libnx_entry.pad.l_stick = pad_state.l_stick; - libnx_entry.pad.r_stick = pad_state.r_stick; + libnx_state.connection_status.raw = 0; + libnx_state.connection_status.is_connected.Assign(1); + switch (controller_type) { + case Core::HID::NpadType::None: + UNREACHABLE(); + break; + case Core::HID::NpadType::ProController: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_wired.Assign(1); - press_state |= static_cast(pad_state.pad_states.raw); + libnx_state.connection_status.is_wired.Assign(1); + pad_state.sampling_number = + npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.fullkey_lifo.WriteNextEntry(pad_state); + break; + case Core::HID::NpadType::Handheld: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_wired.Assign(1); + pad_state.connection_status.is_left_connected.Assign(1); + pad_state.connection_status.is_right_connected.Assign(1); + pad_state.connection_status.is_left_wired.Assign(1); + pad_state.connection_status.is_right_wired.Assign(1); + + libnx_state.connection_status.is_wired.Assign(1); + libnx_state.connection_status.is_left_connected.Assign(1); + libnx_state.connection_status.is_right_connected.Assign(1); + libnx_state.connection_status.is_left_wired.Assign(1); + libnx_state.connection_status.is_right_wired.Assign(1); + pad_state.sampling_number = + npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.handheld_lifo.WriteNextEntry(pad_state); + break; + case Core::HID::NpadType::JoyconDual: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_left_connected.Assign(1); + pad_state.connection_status.is_right_connected.Assign(1); + + libnx_state.connection_status.is_left_connected.Assign(1); + libnx_state.connection_status.is_right_connected.Assign(1); + pad_state.sampling_number = + npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.joy_dual_lifo.WriteNextEntry(pad_state); + break; + case Core::HID::NpadType::JoyconLeft: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_left_connected.Assign(1); + + libnx_state.connection_status.is_left_connected.Assign(1); + pad_state.sampling_number = + npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.joy_left_lifo.WriteNextEntry(pad_state); + break; + case Core::HID::NpadType::JoyconRight: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_right_connected.Assign(1); + + libnx_state.connection_status.is_right_connected.Assign(1); + pad_state.sampling_number = + npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.joy_right_lifo.WriteNextEntry(pad_state); + break; + case Core::HID::NpadType::GameCube: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.connection_status.is_wired.Assign(1); + + libnx_state.connection_status.is_wired.Assign(1); + pad_state.sampling_number = + npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + trigger_state.sampling_number = + npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.fullkey_lifo.WriteNextEntry(pad_state); + npad.gc_trigger_lifo.WriteNextEntry(trigger_state); + break; + case Core::HID::NpadType::Pokeball: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + pad_state.sampling_number = + npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.palma_lifo.WriteNextEntry(pad_state); + break; + default: + break; + } + + libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; + libnx_state.l_stick = pad_state.l_stick; + libnx_state.r_stick = pad_state.r_stick; + npad.system_ext_lifo.WriteNextEntry(pad_state); + + press_state |= static_cast(pad_state.npad_buttons.raw); + + std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), + &controller.shared_memory_entry, sizeof(NpadInternalState)); } - std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), - shared_memory_entries.size() * sizeof(NPadEntry)); } void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, @@ -622,145 +484,130 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing if (!IsControllerActivated()) { return; } - for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { - auto& npad = shared_memory_entries[i]; - const auto& controller_type = connected_controllers[i].type; + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; - if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { + const auto& controller_type = controller.device->GetNpadType(); + + if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { continue; } - const std::array controller_sixaxes{ - &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, - &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, - }; - - for (auto* sixaxis_sensor : controller_sixaxes) { - sixaxis_sensor->common.entry_count = 16; - sixaxis_sensor->common.total_entry_count = 17; - - const auto& last_entry = - sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; - - sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks(); - sixaxis_sensor->common.last_entry_index = - (sixaxis_sensor->common.last_entry_index + 1) % 17; - - auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; - - cur_entry.timestamp = last_entry.timestamp + 1; - cur_entry.timestamp2 = cur_entry.timestamp; - } - - // Try to read sixaxis sensor states - std::array motion_devices; + auto& npad = controller.shared_memory_entry; + const auto& motion_state = controller.device->GetMotions(); + auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; + auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; + auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; + auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; + auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; + auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) { sixaxis_at_rest = true; - for (std::size_t e = 0; e < motion_devices.size(); ++e) { - const auto& device = motions[i][e]; - if (device) { - std::tie(motion_devices[e].accel, motion_devices[e].gyro, - motion_devices[e].rotation, motion_devices[e].orientation, - motion_devices[e].quaternion) = device->GetStatus(); - sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; - } + for (std::size_t e = 0; e < motion_state.size(); ++e) { + sixaxis_at_rest = sixaxis_at_rest && motion_state[e].is_at_rest; } } - auto& full_sixaxis_entry = - npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index]; - auto& handheld_sixaxis_entry = - npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; - auto& dual_left_sixaxis_entry = - npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; - auto& dual_right_sixaxis_entry = - npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; - auto& left_sixaxis_entry = - npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; - auto& right_sixaxis_entry = - npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; - switch (controller_type) { - case NPadControllerType::None: + case Core::HID::NpadType::None: UNREACHABLE(); break; - case NPadControllerType::ProController: - full_sixaxis_entry.attribute.raw = 0; - if (sixaxis_sensors_enabled && motions[i][0]) { - full_sixaxis_entry.attribute.is_connected.Assign(1); - full_sixaxis_entry.accel = motion_devices[0].accel; - full_sixaxis_entry.gyro = motion_devices[0].gyro; - full_sixaxis_entry.rotation = motion_devices[0].rotation; - full_sixaxis_entry.orientation = motion_devices[0].orientation; + case Core::HID::NpadType::ProController: + sixaxis_fullkey_state.attribute.raw = 0; + if (sixaxis_sensors_enabled) { + sixaxis_fullkey_state.attribute.is_connected.Assign(1); + sixaxis_fullkey_state.accel = motion_state[0].accel; + sixaxis_fullkey_state.gyro = motion_state[0].gyro; + sixaxis_fullkey_state.rotation = motion_state[0].rotation; + sixaxis_fullkey_state.orientation = motion_state[0].orientation; } break; - case NPadControllerType::Handheld: - handheld_sixaxis_entry.attribute.raw = 0; - if (sixaxis_sensors_enabled && motions[i][0]) { - handheld_sixaxis_entry.attribute.is_connected.Assign(1); - handheld_sixaxis_entry.accel = motion_devices[0].accel; - handheld_sixaxis_entry.gyro = motion_devices[0].gyro; - handheld_sixaxis_entry.rotation = motion_devices[0].rotation; - handheld_sixaxis_entry.orientation = motion_devices[0].orientation; + case Core::HID::NpadType::Handheld: + sixaxis_handheld_state.attribute.raw = 0; + if (sixaxis_sensors_enabled) { + sixaxis_handheld_state.attribute.is_connected.Assign(1); + sixaxis_handheld_state.accel = motion_state[0].accel; + sixaxis_handheld_state.gyro = motion_state[0].gyro; + sixaxis_handheld_state.rotation = motion_state[0].rotation; + sixaxis_handheld_state.orientation = motion_state[0].orientation; } break; - case NPadControllerType::JoyDual: - dual_left_sixaxis_entry.attribute.raw = 0; - dual_right_sixaxis_entry.attribute.raw = 0; - if (sixaxis_sensors_enabled && motions[i][0]) { + case Core::HID::NpadType::JoyconDual: + sixaxis_dual_left_state.attribute.raw = 0; + sixaxis_dual_right_state.attribute.raw = 0; + if (sixaxis_sensors_enabled) { // Set motion for the left joycon - dual_left_sixaxis_entry.attribute.is_connected.Assign(1); - dual_left_sixaxis_entry.accel = motion_devices[0].accel; - dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; - dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; - dual_left_sixaxis_entry.orientation = motion_devices[0].orientation; + sixaxis_dual_left_state.attribute.is_connected.Assign(1); + sixaxis_dual_left_state.accel = motion_state[0].accel; + sixaxis_dual_left_state.gyro = motion_state[0].gyro; + sixaxis_dual_left_state.rotation = motion_state[0].rotation; + sixaxis_dual_left_state.orientation = motion_state[0].orientation; } - if (sixaxis_sensors_enabled && motions[i][1]) { + if (sixaxis_sensors_enabled) { // Set motion for the right joycon - dual_right_sixaxis_entry.attribute.is_connected.Assign(1); - dual_right_sixaxis_entry.accel = motion_devices[1].accel; - dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; - dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; - dual_right_sixaxis_entry.orientation = motion_devices[1].orientation; + sixaxis_dual_right_state.attribute.is_connected.Assign(1); + sixaxis_dual_right_state.accel = motion_state[1].accel; + sixaxis_dual_right_state.gyro = motion_state[1].gyro; + sixaxis_dual_right_state.rotation = motion_state[1].rotation; + sixaxis_dual_right_state.orientation = motion_state[1].orientation; } break; - case NPadControllerType::JoyLeft: - left_sixaxis_entry.attribute.raw = 0; - if (sixaxis_sensors_enabled && motions[i][0]) { - left_sixaxis_entry.attribute.is_connected.Assign(1); - left_sixaxis_entry.accel = motion_devices[0].accel; - left_sixaxis_entry.gyro = motion_devices[0].gyro; - left_sixaxis_entry.rotation = motion_devices[0].rotation; - left_sixaxis_entry.orientation = motion_devices[0].orientation; + case Core::HID::NpadType::JoyconLeft: + sixaxis_left_lifo_state.attribute.raw = 0; + if (sixaxis_sensors_enabled) { + sixaxis_left_lifo_state.attribute.is_connected.Assign(1); + sixaxis_left_lifo_state.accel = motion_state[0].accel; + sixaxis_left_lifo_state.gyro = motion_state[0].gyro; + sixaxis_left_lifo_state.rotation = motion_state[0].rotation; + sixaxis_left_lifo_state.orientation = motion_state[0].orientation; } break; - case NPadControllerType::JoyRight: - right_sixaxis_entry.attribute.raw = 0; - if (sixaxis_sensors_enabled && motions[i][1]) { - right_sixaxis_entry.attribute.is_connected.Assign(1); - right_sixaxis_entry.accel = motion_devices[1].accel; - right_sixaxis_entry.gyro = motion_devices[1].gyro; - right_sixaxis_entry.rotation = motion_devices[1].rotation; - right_sixaxis_entry.orientation = motion_devices[1].orientation; + case Core::HID::NpadType::JoyconRight: + sixaxis_right_lifo_state.attribute.raw = 0; + if (sixaxis_sensors_enabled) { + sixaxis_right_lifo_state.attribute.is_connected.Assign(1); + sixaxis_right_lifo_state.accel = motion_state[1].accel; + sixaxis_right_lifo_state.gyro = motion_state[1].gyro; + sixaxis_right_lifo_state.rotation = motion_state[1].rotation; + sixaxis_right_lifo_state.orientation = motion_state[1].orientation; } break; - case NPadControllerType::GameCube: - case NPadControllerType::Pokeball: + default: break; } + + sixaxis_fullkey_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_handheld_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_left_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_right_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_left_lifo_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_right_lifo_state.sampling_number = + npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + + npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); + npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); + npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); + npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); + npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); + std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), + &controller.shared_memory_entry, sizeof(NpadInternalState)); } - std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), - shared_memory_entries.size() * sizeof(NPadEntry)); } -void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) { - style.raw = style_set.raw; +void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { + system.HIDCore().SetSupportedStyleTag(style_set); } -Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const { - return style; +Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { + return system.HIDCore().GetSupportedStyleTag(); } void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { @@ -779,11 +626,11 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { return supported_npad_id_types.size(); } -void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { +void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { hold_type = joy_hold_type; } -Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { +Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { return hold_type; } @@ -803,29 +650,31 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { +void Controller_NPad::SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode) { const std::size_t npad_index = NPadIdToIndex(npad_id); - ASSERT(npad_index < shared_memory_entries.size()); - if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) { - shared_memory_entries[npad_index].assignment_mode = assignment_mode; + ASSERT(npad_index < controller_data.size()); + auto& controller = controller_data[npad_index]; + if (controller.shared_memory_entry.assignment_mode != assignment_mode) { + controller.shared_memory_entry.assignment_mode = assignment_mode; } } bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, const VibrationValue& vibration_value) { - if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { + auto& controller = controller_data[npad_index]; + + if (!controller.device->IsConnected()) { return false; } - const auto& player = Settings::values.players.GetValue()[npad_index]; - - if (!player.vibration_enabled) { - if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || - latest_vibration_values[npad_index][device_index].amp_high != 0.0f) { + if (!controller.device->IsVibrationEnabled()) { + if (controller.vibration[device_index].latest_vibration_value.amp_low != 0.0f || + controller.vibration[device_index].latest_vibration_value.amp_high != 0.0f) { // Send an empty vibration to stop any vibrations. - vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); + Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; + controller.device->SetVibration(device_index, vibration); // Then reset the vibration value to its default value. - latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE; + controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE; } return false; @@ -840,22 +689,18 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size // Filter out non-zero vibrations that are within 10ms of each other. if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && - duration_cast(now - last_vibration_timepoints[npad_index][device_index]) < + duration_cast( + now - controller.vibration[device_index].last_vibration_timepoint) < milliseconds(10)) { return false; } - last_vibration_timepoints[npad_index][device_index] = now; + controller.vibration[device_index].last_vibration_timepoint = now; } - auto& vibration = vibrations[npad_index][device_index]; - const auto player_vibration_strength = static_cast(player.vibration_strength); - const auto amp_low = - std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f); - const auto amp_high = - std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f); - return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high, - vibration_value.freq_high); + Core::HID::VibrationValue vibration{vibration_value.amp_low, vibration_value.freq_low, + vibration_value.amp_high, vibration_value.freq_high}; + return controller.device->SetVibration(device_index, vibration); } void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, @@ -869,10 +714,10 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han } const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + auto& controller = controller_data[npad_index]; const auto device_index = static_cast(vibration_device_handle.device_index); - if (!vibration_devices_mounted[npad_index][device_index] || - !connected_controllers[npad_index].is_connected) { + if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { return; } @@ -882,23 +727,25 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han } // Some games try to send mismatched parameters in the device handle, block these. - if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && - (vibration_device_handle.npad_type == NpadType::JoyconRight || + if ((controller.device->GetNpadType() == Core::HID::NpadType::JoyconLeft && + (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconRight || vibration_device_handle.device_index == DeviceIndex::Right)) || - (connected_controllers[npad_index].type == NPadControllerType::JoyRight && - (vibration_device_handle.npad_type == NpadType::JoyconLeft || + (controller.device->GetNpadType() == Core::HID::NpadType::JoyconRight && + (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconLeft || vibration_device_handle.device_index == DeviceIndex::Left))) { return; } // Filter out vibrations with equivalent values to reduce unnecessary state changes. - if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low && - vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) { + if (vibration_value.amp_low == + controller.vibration[device_index].latest_vibration_value.amp_low && + vibration_value.amp_high == + controller.vibration[device_index].latest_vibration_value.amp_high) { return; } if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { - latest_vibration_values[npad_index][device_index] = vibration_value; + controller.vibration[device_index].latest_vibration_value = vibration_value; } } @@ -925,8 +772,9 @@ Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( } const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto& controller = controller_data[npad_index]; const auto device_index = static_cast(vibration_device_handle.device_index); - return latest_vibration_values[npad_index][device_index]; + return controller.vibration[device_index].latest_vibration_value; } void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { @@ -941,17 +789,14 @@ void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_de void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index) { + auto& controller = controller_data[npad_index]; if (!Settings::values.vibration_enabled.GetValue()) { - vibration_devices_mounted[npad_index][device_index] = false; + controller.vibration[device_index].device_mounted = false; return; } - if (vibrations[npad_index][device_index]) { - vibration_devices_mounted[npad_index][device_index] = - vibrations[npad_index][device_index]->GetStatus() == 1; - } else { - vibration_devices_mounted[npad_index][device_index] = false; - } + controller.vibration[device_index].device_mounted = + controller.device->TestVibration(device_index) == 1; } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { @@ -964,42 +809,35 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev } const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto& controller = controller_data[npad_index]; const auto device_index = static_cast(vibration_device_handle.device_index); - return vibration_devices_mounted[npad_index][device_index]; + return controller.vibration[device_index].device_mounted; } Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) { - return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent(); + const auto& controller = controller_data[NPadIdToIndex(npad_id)]; + return controller.styleset_changed_event->GetReadableEvent(); } void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { - styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal(); + const auto& controller = controller_data[NPadIdToIndex(npad_id)]; + controller.styleset_changed_event->GetWritableEvent().Signal(); } -void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { +void Controller_NPad::AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index) { UpdateControllerAt(controller, npad_index, true); } -void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, +void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index, bool connected) { + auto& controller = controller_data[npad_index].device; if (!connected) { DisconnectNpadAtIndex(npad_index); return; } - if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) { - Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = - MapNPadToSettingsType(controller); - Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; - connected_controllers[HANDHELD_INDEX] = {controller, true}; - InitNewlyAddedController(HANDHELD_INDEX); - return; - } - - Settings::values.players.GetValue()[npad_index].controller_type = - MapNPadToSettingsType(controller); - Settings::values.players.GetValue()[npad_index].connected = true; - connected_controllers[npad_index] = {controller, true}; + controller->SetNpadType(type); + controller->Connect(); InitNewlyAddedController(npad_index); } @@ -1008,27 +846,27 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) { } void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { - for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { + auto& controller = controller_data[npad_index]; + for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { // Send an empty vibration to stop any vibrations. VibrateControllerAtIndex(npad_index, device_idx, {}); - vibration_devices_mounted[npad_index][device_idx] = false; + controller.vibration[device_idx].device_mounted = false; } - Settings::values.players.GetValue()[npad_index].connected = false; - connected_controllers[npad_index].is_connected = false; + controller.device->Disconnect(); - auto& controller = shared_memory_entries[npad_index]; - controller.style_set.raw = 0; // Zero out - controller.device_type.raw = 0; - controller.system_properties.raw = 0; - controller.button_properties.raw = 0; - controller.battery_level_dual = 0; - controller.battery_level_left = 0; - controller.battery_level_right = 0; - controller.fullkey_color = {}; - controller.joycon_color = {}; - controller.assignment_mode = NpadAssignments::Dual; - controller.footer_type = AppletFooterUiType::None; + auto& shared_memory_entry = controller.shared_memory_entry; + shared_memory_entry.style_set.raw = 0; // Zero out + shared_memory_entry.device_type.raw = 0; + shared_memory_entry.system_properties.raw = 0; + shared_memory_entry.button_properties.raw = 0; + shared_memory_entry.battery_level_dual = 0; + shared_memory_entry.battery_level_left = 0; + shared_memory_entry.battery_level_right = 0; + shared_memory_entry.fullkey_color = {}; + shared_memory_entry.joycon_color = {}; + shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory_entry.footer_type = AppletFooterUiType::None; SignalStyleSetChangedEvent(IndexToNPad(npad_index)); } @@ -1069,16 +907,18 @@ void Controller_NPad::ResetSixAxisFusionParameters() { void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { const auto npad_index_1 = NPadIdToIndex(npad_id_1); const auto npad_index_2 = NPadIdToIndex(npad_id_2); + const auto& controller_1 = controller_data[npad_index_1].device; + const auto& controller_2 = controller_data[npad_index_2].device; // If the controllers at both npad indices form a pair of left and right joycons, merge them. // Otherwise, do nothing. - if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft && - connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) || - (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && - connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { + if ((controller_1->GetNpadType() == Core::HID::NpadType::JoyconLeft && + controller_2->GetNpadType() == Core::HID::NpadType::JoyconRight) || + (controller_2->GetNpadType() == Core::HID::NpadType::JoyconLeft && + controller_1->GetNpadType() == Core::HID::NpadType::JoyconRight)) { // Disconnect the joycon at the second id and connect the dual joycon at the first index. DisconnectNpad(npad_id_2); - AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); + AddNewControllerAt(Core::HID::NpadType::JoyconDual, npad_index_1); } } @@ -1099,16 +939,17 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { } const auto npad_index_1 = NPadIdToIndex(npad_id_1); const auto npad_index_2 = NPadIdToIndex(npad_id_2); + const auto& controller_1 = controller_data[npad_index_1].device; + const auto& controller_2 = controller_data[npad_index_2].device; + const auto type_index_1 = controller_1->GetNpadType(); + const auto type_index_2 = controller_2->GetNpadType(); - if (!IsControllerSupported(connected_controllers[npad_index_1].type) || - !IsControllerSupported(connected_controllers[npad_index_2].type)) { + if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) { return false; } - std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); - - AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1); - AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2); + AddNewControllerAt(type_index_2, npad_index_1); + AddNewControllerAt(type_index_1, npad_index_2); return true; } @@ -1141,12 +982,14 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { } bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { - return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; + auto& controller = controller_data[NPadIdToIndex(npad_id)]; + return controller.unintended_home_button_input_protection; } void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id) { - unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; + auto& controller = controller_data[NPadIdToIndex(npad_id)]; + controller.unintended_home_button_input_protection = is_protection_enabled; } void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { @@ -1154,32 +997,34 @@ void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { } void Controller_NPad::ClearAllConnectedControllers() { - for (auto& controller : connected_controllers) { - if (controller.is_connected && controller.type != NPadControllerType::None) { - controller.type = NPadControllerType::None; - controller.is_connected = false; + for (auto& controller : controller_data) { + if (controller.device->IsConnected() && + controller.device->GetNpadType() != Core::HID::NpadType::None) { + controller.device->SetNpadType(Core::HID::NpadType::None); + controller.device->Disconnect(); } } } void Controller_NPad::DisconnectAllConnectedControllers() { - for (auto& controller : connected_controllers) { - controller.is_connected = false; + for (auto& controller : controller_data) { + controller.device->Disconnect(); } } void Controller_NPad::ConnectAllDisconnectedControllers() { - for (auto& controller : connected_controllers) { - if (controller.type != NPadControllerType::None && !controller.is_connected) { - controller.is_connected = true; + for (auto& controller : controller_data) { + if (controller.device->GetNpadType() != Core::HID::NpadType::None && + !controller.device->IsConnected()) { + controller.device->Connect(); } } } void Controller_NPad::ClearAllControllers() { - for (auto& controller : connected_controllers) { - controller.type = NPadControllerType::None; - controller.is_connected = false; + for (auto& controller : controller_data) { + controller.device->SetNpadType(Core::HID::NpadType::None); + controller.device->Disconnect(); } } @@ -1187,8 +1032,8 @@ u32 Controller_NPad::GetAndResetPressState() { return press_state.exchange(0); } -bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { - if (controller == NPadControllerType::Handheld) { +bool Controller_NPad::IsControllerSupported(Core::HID::NpadType controller) const { + if (controller == Core::HID::NpadType::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != supported_npad_id_types.end(); @@ -1196,7 +1041,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const if (!support_handheld) { return false; } - // Handheld should not be supported in docked mode + // Handheld shouldn't be supported in docked mode if (Settings::values.use_docked_mode.GetValue()) { return false; } @@ -1206,18 +1051,19 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { + Core::HID::NpadStyleTag style = GetSupportedStyleSet(); switch (controller) { - case NPadControllerType::ProController: + case Core::HID::NpadType::ProController: return style.fullkey; - case NPadControllerType::JoyDual: + case Core::HID::NpadType::JoyconDual: return style.joycon_dual; - case NPadControllerType::JoyLeft: + case Core::HID::NpadType::JoyconLeft: return style.joycon_left; - case NPadControllerType::JoyRight: + case Core::HID::NpadType::JoyconRight: return style.joycon_right; - case NPadControllerType::GameCube: + case Core::HID::NpadType::GameCube: return style.gamecube; - case NPadControllerType::Pokeball: + case Core::HID::NpadType::Pokeball: return style.palma; default: return false; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index f3e868bdb..483cae5b6 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -12,8 +12,10 @@ #include "common/common_types.h" #include "common/quaternion.h" #include "common/settings.h" -#include "core/frontend/input.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Kernel { class KEvent; @@ -48,31 +50,6 @@ public: void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - - enum class NPadControllerType { - None, - ProController, - Handheld, - JoyDual, - JoyLeft, - JoyRight, - GameCube, - Pokeball, - }; - - enum class NpadType : u8 { - ProController = 3, - Handheld = 4, - JoyconDual = 5, - JoyconLeft = 6, - JoyconRight = 7, - GameCube = 8, - Pokeball = 9, - MaxNpadType = 10, - }; - enum class DeviceIndex : u8 { Left = 0, Right = 1, @@ -80,28 +57,33 @@ public: MaxDeviceIndex = 3, }; + // This is nn::hid::GyroscopeZeroDriftMode enum class GyroscopeZeroDriftMode : u32 { Loose = 0, Standard = 1, Tight = 2, }; - enum class NpadHoldType : u64 { + // This is nn::hid::NpadJoyHoldType + enum class NpadJoyHoldType : u64 { Vertical = 0, Horizontal = 1, }; - enum class NpadAssignments : u32 { + // This is nn::hid::NpadJoyAssignmentMode + enum class NpadJoyAssignmentMode : u32 { Dual = 0, Single = 1, }; + // This is nn::hid::NpadHandheldActivationMode enum class NpadHandheldActivationMode : u64 { Dual = 0, Single = 1, None = 2, }; + // This is nn::hid::NpadCommunicationMode enum class NpadCommunicationMode : u64 { Mode_5ms = 0, Mode_10ms = 1, @@ -110,33 +92,14 @@ public: }; struct DeviceHandle { - NpadType npad_type; + Core::HID::NpadType npad_type; u8 npad_id; DeviceIndex device_index; INSERT_PADDING_BYTES_NOINIT(1); }; static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); - struct NpadStyleSet { - union { - u32_le raw{}; - - BitField<0, 1, u32> fullkey; - BitField<1, 1, u32> handheld; - BitField<2, 1, u32> joycon_dual; - BitField<3, 1, u32> joycon_left; - BitField<4, 1, u32> joycon_right; - BitField<5, 1, u32> gamecube; - BitField<6, 1, u32> palma; - BitField<7, 1, u32> lark; - BitField<8, 1, u32> handheld_lark; - BitField<9, 1, u32> lucia; - BitField<29, 1, u32> system_ext; - BitField<30, 1, u32> system; - }; - }; - static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); - + // This is nn::hid::VibrationValue struct VibrationValue { f32 amp_low; f32 freq_low; @@ -168,15 +131,15 @@ public: }; }; - void SetSupportedStyleSet(NpadStyleSet style_set); - NpadStyleSet GetSupportedStyleSet() const; + void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); + Core::HID::NpadStyleTag GetSupportedStyleSet() const; void SetSupportedNpadIdTypes(u8* data, std::size_t length); void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); std::size_t GetSupportedNpadIdTypesSize() const; - void SetHoldType(NpadHoldType joy_hold_type); - NpadHoldType GetHoldType() const; + void SetHoldType(NpadJoyHoldType joy_hold_type); + NpadJoyHoldType GetHoldType() const; void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); NpadHandheldActivationMode GetNpadHandheldActivationMode() const; @@ -184,7 +147,7 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); + void SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode); bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, const VibrationValue& vibration_value); @@ -209,9 +172,9 @@ public: void SignalStyleSetChangedEvent(u32 npad_id) const; // Adds a new controller at an index. - void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); + void AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index); // Adds a new controller at an index with connection status. - void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); + void UpdateControllerAt(Core::HID::NpadType controller, std::size_t npad_index, bool connected); void DisconnectNpad(u32 npad_id); void DisconnectNpadAtIndex(std::size_t index); @@ -241,103 +204,37 @@ public: // Specifically for cheat engine and other features. u32 GetAndResetPressState(); - static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type); - static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); static std::size_t NPadIdToIndex(u32 npad_id); static u32 IndexToNPad(std::size_t index); static bool IsNpadIdValid(u32 npad_id); static bool IsDeviceHandleValid(const DeviceHandle& device_handle); private: - struct CommonHeader { - s64_le timestamp; - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - enum class ColorAttributes : u32_le { + // This is nn::hid::detail::ColorAttribute + enum class ColorAttribute : u32_le { Ok = 0, ReadError = 1, NoController = 2, }; - static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); + static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); - struct ControllerColor { - u32_le body; - u32_le button; + // This is nn::hid::detail::NpadFullKeyColorState + struct NpadFullKeyColorState { + ColorAttribute attribute; + Core::HID::NpadControllerColor fullkey; }; - static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); + static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); - struct FullKeyColor { - ColorAttributes attribute; - ControllerColor fullkey; + // This is nn::hid::detail::NpadJoyColorState + struct NpadJoyColorState { + ColorAttribute attribute; + Core::HID::NpadControllerColor left; + Core::HID::NpadControllerColor right; }; - static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); + static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); - struct JoyconColor { - ColorAttributes attribute; - ControllerColor left; - ControllerColor right; - }; - static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size"); - - struct ControllerPadState { - union { - u64_le raw{}; - // Button states - BitField<0, 1, u64> a; - BitField<1, 1, u64> b; - BitField<2, 1, u64> x; - BitField<3, 1, u64> y; - BitField<4, 1, u64> l_stick; - BitField<5, 1, u64> r_stick; - BitField<6, 1, u64> l; - BitField<7, 1, u64> r; - BitField<8, 1, u64> zl; - BitField<9, 1, u64> zr; - BitField<10, 1, u64> plus; - BitField<11, 1, u64> minus; - - // D-Pad - BitField<12, 1, u64> d_left; - BitField<13, 1, u64> d_up; - BitField<14, 1, u64> d_right; - BitField<15, 1, u64> d_down; - - // Left JoyStick - BitField<16, 1, u64> l_stick_left; - BitField<17, 1, u64> l_stick_up; - BitField<18, 1, u64> l_stick_right; - BitField<19, 1, u64> l_stick_down; - - // Right JoyStick - BitField<20, 1, u64> r_stick_left; - BitField<21, 1, u64> r_stick_up; - BitField<22, 1, u64> r_stick_right; - BitField<23, 1, u64> r_stick_down; - - // Not always active? - BitField<24, 1, u64> left_sl; - BitField<25, 1, u64> left_sr; - - BitField<26, 1, u64> right_sl; - BitField<27, 1, u64> right_sr; - - BitField<28, 1, u64> palma; - BitField<30, 1, u64> handheld_left_b; - }; - }; - static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); - - struct AnalogPosition { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); - - struct ConnectionState { + // This is nn::hid::NpadAttribute + struct NpadAttribute { union { u32_le raw{}; BitField<0, 1, u32> is_connected; @@ -348,76 +245,57 @@ private: BitField<5, 1, u32> is_right_wired; }; }; - static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); + static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); - struct ControllerPad { - ControllerPadState pad_states; - AnalogPosition l_stick; - AnalogPosition r_stick; + // This is nn::hid::NpadFullKeyState + // This is nn::hid::NpadHandheldState + // This is nn::hid::NpadJoyDualState + // This is nn::hid::NpadJoyLeftState + // This is nn::hid::NpadJoyRightState + // This is nn::hid::NpadPalmaState + // This is nn::hid::NpadSystemExtState + struct NPadGenericState { + s64_le sampling_number; + Core::HID::NpadButtonState npad_buttons; + Core::HID::AnalogStickState l_stick; + Core::HID::AnalogStickState r_stick; + NpadAttribute connection_status; + INSERT_PADDING_BYTES(4); // Reserved }; - static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size"); + static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); - struct GenericStates { - s64_le timestamp; - s64_le timestamp2; - ControllerPad pad; - ConnectionState connection_status; - }; - static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); - - struct NPadGeneric { - CommonHeader common; - std::array npad; - }; - static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); - - struct SixAxisAttributes { + // This is nn::hid::SixAxisSensorAttribute + struct SixAxisSensorAttribute { union { u32_le raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_interpolated; }; }; - static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size"); + static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size"); - struct SixAxisStates { - s64_le timestamp{}; - INSERT_PADDING_WORDS(2); - s64_le timestamp2{}; + // This is nn::hid::SixAxisSensorState + struct SixAxisSensorState { + s64_le delta_time{}; + s64_le sampling_number{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Vec3f rotation{}; std::array orientation{}; - SixAxisAttributes attribute; + SixAxisSensorAttribute attribute; INSERT_PADDING_BYTES(4); // Reserved }; - static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); + static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); - struct SixAxisGeneric { - CommonHeader common{}; - std::array sixaxis{}; - }; - static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); - - struct TriggerState { - s64_le timestamp{}; - s64_le timestamp2{}; + // This is nn::hid::server::NpadGcTriggerState + struct NpadGcTriggerState { + s64_le sampling_number{}; s32_le l_analog{}; s32_le r_analog{}; }; - static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size"); - - struct TriggerGeneric { - INSERT_PADDING_BYTES(0x4); - s64_le timestamp; - INSERT_PADDING_BYTES(0x4); - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; - std::array trigger{}; - }; - static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size"); + static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); + // This is nn::hid::NpadSystemProperties struct NPadSystemProperties { union { s64_le raw{}; @@ -438,15 +316,18 @@ private: }; static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); - struct NPadButtonProperties { + // This is nn::hid::NpadSystemButtonProperties + struct NpadSystemButtonProperties { union { s32_le raw{}; BitField<0, 1, s32> is_home_button_protection_enabled; }; }; - static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); + static_assert(sizeof(NpadSystemButtonProperties) == 0x4, + "NPadButtonProperties is an invalid size"); - struct NPadDevice { + // This is nn::hid::system::DeviceType + struct DeviceType { union { u32_le raw{}; BitField<0, 1, s32> fullkey; @@ -469,14 +350,6 @@ private: }; }; - struct MotionDevice { - Common::Vec3f accel; - Common::Vec3f gyro; - Common::Vec3f rotation; - std::array orientation; - Common::Quaternion quaternion; - }; - struct NfcXcdHandle { INSERT_PADDING_BYTES(0x60); }; @@ -485,6 +358,7 @@ private: INSERT_PADDING_BYTES(0x4); }; + // This is nn::hid::server::NpadGcTriggerState enum class AppletFooterUiType : u8 { None = 0, HandheldNone = 1, @@ -510,95 +384,90 @@ private: Lagon = 21, }; - struct NPadEntry { - NpadStyleSet style_set; - NpadAssignments assignment_mode; - FullKeyColor fullkey_color; - JoyconColor joycon_color; - - NPadGeneric fullkey_states; - NPadGeneric handheld_states; - NPadGeneric joy_dual_states; - NPadGeneric joy_left_states; - NPadGeneric joy_right_states; - NPadGeneric palma_states; - NPadGeneric system_ext_states; - SixAxisGeneric sixaxis_fullkey; - SixAxisGeneric sixaxis_handheld; - SixAxisGeneric sixaxis_dual_left; - SixAxisGeneric sixaxis_dual_right; - SixAxisGeneric sixaxis_left; - SixAxisGeneric sixaxis_right; - NPadDevice device_type; - INSERT_PADDING_BYTES(0x4); // reserved + // This is nn::hid::detail::NpadInternalState + struct NpadInternalState { + Core::HID::NpadStyleTag style_set; + NpadJoyAssignmentMode assignment_mode; + NpadFullKeyColorState fullkey_color; + NpadJoyColorState joycon_color; + Lifo fullkey_lifo; + Lifo handheld_lifo; + Lifo joy_dual_lifo; + Lifo joy_left_lifo; + Lifo joy_right_lifo; + Lifo palma_lifo; + Lifo system_ext_lifo; + Lifo sixaxis_fullkey_lifo; + Lifo sixaxis_handheld_lifo; + Lifo sixaxis_dual_left_lifo; + Lifo sixaxis_dual_right_lifo; + Lifo sixaxis_left_lifo; + Lifo sixaxis_right_lifo; + DeviceType device_type; + INSERT_PADDING_BYTES(0x4); // Reserved NPadSystemProperties system_properties; - NPadButtonProperties button_properties; - u32 battery_level_dual; - u32 battery_level_left; - u32 battery_level_right; + NpadSystemButtonProperties button_properties; + Core::HID::BatteryLevel battery_level_dual; + Core::HID::BatteryLevel battery_level_left; + Core::HID::BatteryLevel battery_level_right; AppletFooterUiAttributes footer_attributes; AppletFooterUiType footer_type; - // nfc_states needs to be checked switchbrew does not match with HW + // nfc_states needs to be checked switchbrew doesn't match with HW NfcXcdHandle nfc_states; - INSERT_PADDING_BYTES(0x8); // Mutex - TriggerGeneric gc_trigger_states; - INSERT_PADDING_BYTES(0xc1f); + INSERT_PADDING_BYTES(0x18); // Unknown + Lifo gc_trigger_lifo; + INSERT_PADDING_BYTES(0xc1f); // Unknown }; - static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); + static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); - struct ControllerHolder { - NPadControllerType type; - bool is_connected; + struct VibrationData { + bool device_mounted{}; + VibrationValue latest_vibration_value{}; + std::chrono::steady_clock::time_point last_vibration_timepoint{}; }; + struct ControllerData { + Core::HID::EmulatedController* device; + Kernel::KEvent* styleset_changed_event{}; + NpadInternalState shared_memory_entry{}; + + std::array vibration{}; + bool unintended_home_button_input_protection{}; + + // Current pad state + NPadGenericState npad_pad_state{}; + NPadGenericState npad_libnx_state{}; + NpadGcTriggerState npad_trigger_state{}; + SixAxisSensorState sixaxis_fullkey_state{}; + SixAxisSensorState sixaxis_handheld_state{}; + SixAxisSensorState sixaxis_dual_left_state{}; + SixAxisSensorState sixaxis_dual_right_state{}; + SixAxisSensorState sixaxis_left_lifo_state{}; + SixAxisSensorState sixaxis_right_lifo_state{}; + int callback_key; + }; + + void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); void InitNewlyAddedController(std::size_t controller_idx); - bool IsControllerSupported(NPadControllerType controller) const; + bool IsControllerSupported(Core::HID::NpadType controller) const; void RequestPadStateUpdate(u32 npad_id); std::atomic press_state{}; - NpadStyleSet style{}; - std::array shared_memory_entries{}; - using ButtonArray = std::array< - std::array, Settings::NativeButton::NUM_BUTTONS_HID>, - 10>; - using StickArray = std::array< - std::array, Settings::NativeAnalog::NumAnalogs>, - 10>; - using VibrationArray = std::array, - Settings::NativeVibration::NUM_VIBRATIONS_HID>, - 10>; - using MotionArray = std::array< - std::array, Settings::NativeMotion::NUM_MOTIONS_HID>, - 10>; - + std::array controller_data{}; KernelHelpers::ServiceContext& service_context; std::mutex mutex; - ButtonArray buttons; - StickArray sticks; - VibrationArray vibrations; - MotionArray motions; std::vector supported_npad_id_types{}; - NpadHoldType hold_type{NpadHoldType::Vertical}; + NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; - // Each controller should have their own styleset changed event - std::array styleset_changed_events{}; - std::array, 10> - last_vibration_timepoints{}; - std::array, 10> latest_vibration_values{}; bool permit_vibration_session_enabled{false}; - std::array, 10> vibration_devices_mounted{}; - std::array connected_controllers{}; - std::array unintended_home_button_input_protection{}; bool analog_stick_use_center_clamp{}; GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; bool sixaxis_sensors_enabled{true}; f32 sixaxis_fusion_parameter1{}; f32 sixaxis_fusion_parameter2{}; bool sixaxis_at_rest{true}; - std::array npad_pad_states{}; - std::array npad_trigger_states{}; bool is_in_lr_assignment_mode{false}; }; } // namespace Service::HID From dd62a0187d2f8208e288528a7cbf01810bfed20a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:39:43 -0500 Subject: [PATCH 079/291] core: Remove frontend/input --- src/core/frontend/input.h | 217 -------------------------------------- 1 file changed, 217 deletions(-) delete mode 100644 src/core/frontend/input.h diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h deleted file mode 100644 index f1747c5b2..000000000 --- a/src/core/frontend/input.h +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "common/logging/log.h" -#include "common/param_package.h" -#include "common/quaternion.h" -#include "common/vector_math.h" - -namespace Input { - -enum class AnalogDirection : u8 { - RIGHT, - LEFT, - UP, - DOWN, -}; -struct AnalogProperties { - float deadzone; - float range; - float threshold; -}; -template -struct InputCallback { - std::function on_change; -}; - -/// An abstract class template for an input device (a button, an analog input, etc.). -template -class InputDevice { -public: - virtual ~InputDevice() = default; - virtual StatusType GetStatus() const { - return {}; - } - virtual StatusType GetRawStatus() const { - return GetStatus(); - } - virtual AnalogProperties GetAnalogProperties() const { - return {}; - } - virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { - return {}; - } - virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, - [[maybe_unused]] f32 amp_high, - [[maybe_unused]] f32 freq_high) const { - return {}; - } - void SetCallback(InputCallback callback_) { - callback = std::move(callback_); - } - void TriggerOnChange() { - if (callback.on_change) { - callback.on_change(GetStatus()); - } - } - -private: - InputCallback callback; -}; - -/// An abstract class template for a factory that can create input devices. -template -class Factory { -public: - virtual ~Factory() = default; - virtual std::unique_ptr Create(const Common::ParamPackage&) = 0; -}; - -namespace Impl { - -template -using FactoryListType = std::unordered_map>>; - -template -struct FactoryList { - static FactoryListType list; -}; - -template -FactoryListType FactoryList::list; - -} // namespace Impl - -/** - * Registers an input device factory. - * @tparam InputDeviceType the type of input devices the factory can create - * @param name the name of the factory. Will be used to match the "engine" parameter when creating - * a device - * @param factory the factory object to register - */ -template -void RegisterFactory(const std::string& name, std::shared_ptr> factory) { - auto pair = std::make_pair(name, std::move(factory)); - if (!Impl::FactoryList::list.insert(std::move(pair)).second) { - LOG_ERROR(Input, "Factory '{}' already registered", name); - } -} - -/** - * Unregisters an input device factory. - * @tparam InputDeviceType the type of input devices the factory can create - * @param name the name of the factory to unregister - */ -template -void UnregisterFactory(const std::string& name) { - if (Impl::FactoryList::list.erase(name) == 0) { - LOG_ERROR(Input, "Factory '{}' not registered", name); - } -} - -/** - * Create an input device from given paramters. - * @tparam InputDeviceType the type of input devices to create - * @param params a serialized ParamPackage string contains all parameters for creating the device - */ -template -std::unique_ptr CreateDevice(const std::string& params) { - const Common::ParamPackage package(params); - const std::string engine = package.Get("engine", "null"); - const auto& factory_list = Impl::FactoryList::list; - const auto pair = factory_list.find(engine); - if (pair == factory_list.end()) { - if (engine != "null") { - LOG_ERROR(Input, "Unknown engine name: {}", engine); - } - return std::make_unique(); - } - return pair->second->Create(package); -} - -/** - * A button device is an input device that returns bool as status. - * true for pressed; false for released. - */ -using ButtonDevice = InputDevice; - -/** - * An analog device is an input device that returns a tuple of x and y coordinates as status. The - * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up - * direction - */ -using AnalogDevice = InputDevice>; - -/** - * A vibration device is an input device that returns an unsigned byte as status. - * It represents whether the vibration device supports vibration or not. - * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. - */ -using VibrationDevice = InputDevice; - -/** - * A motion status is an object that returns a tuple of accelerometer state vector, - * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state - * vector. - * - * For both 3D vectors: - * x+ is the same direction as RIGHT on D-pad. - * y+ is normal to the touch screen, pointing outward. - * z+ is the same direction as UP on D-pad. - * - * For accelerometer state vector - * Units: g (gravitational acceleration) - * - * For gyroscope state vector: - * Orientation is determined by right-hand rule. - * Units: deg/sec - * - * For rotation state vector - * Units: rotations - * - * For orientation state matrix - * x vector - * y vector - * z vector - * - * For quaternion state vector - * xyz vector - * w float - */ -using MotionStatus = std::tuple, Common::Vec3, Common::Vec3, - std::array, Common::Quaternion>; - -/** - * A motion device is an input device that returns a motion status object - */ -using MotionDevice = InputDevice; - -/** - * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. - * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is - * pressed. - */ -using TouchStatus = std::array, 16>; - -/** - * A touch device is an input device that returns a touch status object - */ -using TouchDevice = InputDevice; - -/** - * A mouse device is an input device that returns a tuple of two floats and four ints. - * The first two floats are X and Y device coordinates of the mouse (from 0-1). - * The s32s are the mouse wheel. - */ -using MouseDevice = InputDevice>; - -} // namespace Input From 510c7d29537f4d17ec5751b981729e1bf66fe44c Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:46:17 -0500 Subject: [PATCH 080/291] core/frontend: Update applets --- src/core/frontend/applets/controller.cpp | 23 +++++++++++-------- .../service/am/applets/applet_controller.cpp | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 03bbedf8b..ca1edce15 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -49,26 +49,31 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb // Connect controllers based on the following priority list from highest to lowest priority: // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld if (parameters.allow_pro_controller) { - npad.AddNewControllerAt( - npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); + npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( + Settings::ControllerType::ProController), + index); } else if (parameters.allow_dual_joycons) { - npad.AddNewControllerAt( - npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); + npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( + Settings::ControllerType::DualJoyconDetached), + index); } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { // Assign left joycons to even player indices and right joycons to odd player indices. // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and // a right Joycon for Player 2 in 2 Player Assist mode. if (index % 2 == 0) { - npad.AddNewControllerAt( - npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); + npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( + Settings::ControllerType::LeftJoycon), + index); } else { - npad.AddNewControllerAt( - npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); + npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( + Settings::ControllerType::RightJoycon), + index); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && !Settings::values.use_docked_mode.GetValue()) { // We should *never* reach here under any normal circumstances. - npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), + npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( + Settings::ControllerType::Handheld), index); } else { UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 2721679c1..c1b6cd126 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -25,7 +25,7 @@ namespace Service::AM::Applets { static Core::Frontend::ControllerParameters ConvertToFrontendParameters( ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, std::vector identification_colors, std::vector text) { - HID::Controller_NPad::NpadStyleSet npad_style_set; + Core::HID::NpadStyleTag npad_style_set; npad_style_set.raw = private_arg.style_set; return { From 1b82d5bb4f9440603e7af0af6abed7968aef37e4 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:50:32 -0500 Subject: [PATCH 081/291] yuzu: Update overlay applet --- src/yuzu/util/overlay_dialog.cpp | 27 +++++++++++++++------------ src/yuzu/util/overlay_dialog.h | 10 ++++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index 95b148545..c66dfbdff 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -6,7 +6,8 @@ #include #include "core/core.h" -#include "core/frontend/input_interpreter.h" +#include "core/hid/hid_types.h" +#include "core/hid/input_interpreter.h" #include "ui_overlay_dialog.h" #include "yuzu/util/overlay_dialog.h" @@ -179,9 +180,9 @@ void OverlayDialog::MoveAndResizeWindow() { QDialog::resize(width, height); } -template +template void OverlayDialog::HandleButtonPressedOnce() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { TranslateButtonPress(button); } @@ -190,7 +191,7 @@ void OverlayDialog::HandleButtonPressedOnce() { (f(T), ...); } -void OverlayDialog::TranslateButtonPress(HIDButton button) { +void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) { QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label; @@ -198,20 +199,20 @@ void OverlayDialog::TranslateButtonPress(HIDButton button) { // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it switch (button) { - case HIDButton::A: - case HIDButton::B: + case Core::HID::NpadButton::A: + case Core::HID::NpadButton::B: if (left_button->hasFocus()) { left_button->click(); } else if (right_button->hasFocus()) { right_button->click(); } break; - case HIDButton::DLeft: - case HIDButton::LStickLeft: + case Core::HID::NpadButton::Left: + case Core::HID::NpadButton::StickLLeft: focusPreviousChild(); break; - case HIDButton::DRight: - case HIDButton::LStickRight: + case Core::HID::NpadButton::Right: + case Core::HID::NpadButton::StickLRight: focusNextChild(); break; default: @@ -241,8 +242,10 @@ void OverlayDialog::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleButtonPressedOnce(); + HandleButtonPressedOnce(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h index e8c388bd0..d8a140ff3 100644 --- a/src/yuzu/util/overlay_dialog.h +++ b/src/yuzu/util/overlay_dialog.h @@ -13,14 +13,16 @@ #include "common/common_types.h" -enum class HIDButton : u8; - class InputInterpreter; namespace Core { class System; } +namespace Core::HID { +enum class NpadButton : u64; +} + namespace Ui { class OverlayDialog; } @@ -79,7 +81,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonPressedOnce(); /** @@ -87,7 +89,7 @@ private: * * @param button The button press to process. */ - void TranslateButtonPress(HIDButton button); + void TranslateButtonPress(Core::HID::NpadButton button); void StartInputThread(); void StopInputThread(); From e14ae06391ac724e4be4557df0568846687a3662 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 20:53:04 -0500 Subject: [PATCH 082/291] core: Update input interpreter --- src/core/hid/input_interpreter.cpp | 17 +++++----- src/core/hid/input_interpreter.h | 52 ++++++------------------------ src/yuzu/applets/qt_controller.cpp | 2 -- src/yuzu_cmd/config.cpp | 1 - 4 files changed, 18 insertions(+), 54 deletions(-) diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp index c33d8a11a..7e7c1816f 100644 --- a/src/core/hid/input_interpreter.cpp +++ b/src/core/hid/input_interpreter.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/core.h" +#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" @@ -38,25 +39,23 @@ void InputInterpreter::ResetButtonStates() { } } -bool InputInterpreter::IsButtonPressed(HIDButton button) const { - return (button_states[current_index] & (1U << static_cast(button))) != 0; +bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const { + return (button_states[current_index] & static_cast(button)) != 0; } -bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { - const bool current_press = - (button_states[current_index] & (1U << static_cast(button))) != 0; - const bool previous_press = - (button_states[previous_index] & (1U << static_cast(button))) != 0; +bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const { + const bool current_press = (button_states[current_index] & static_cast(button)) != 0; + const bool previous_press = (button_states[previous_index] & static_cast(button)) != 0; return current_press && !previous_press; } -bool InputInterpreter::IsButtonHeld(HIDButton button) const { +bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const { u32 held_buttons{button_states[0]}; for (std::size_t i = 1; i < button_states.size(); ++i) { held_buttons &= button_states[i]; } - return (held_buttons & (1U << static_cast(button))) != 0; + return (held_buttons & static_cast(button)) != 0; } diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h index 9495e3daf..1791cf9b7 100644 --- a/src/core/hid/input_interpreter.h +++ b/src/core/hid/input_interpreter.h @@ -12,46 +12,14 @@ namespace Core { class System; } +namespace Core::HID { +enum class NpadButton : u64; +} + namespace Service::HID { class Controller_NPad; } -enum class HIDButton : u8 { - A, - B, - X, - Y, - LStick, - RStick, - L, - R, - ZL, - ZR, - Plus, - Minus, - - DLeft, - DUp, - DRight, - DDown, - - LStickLeft, - LStickUp, - LStickRight, - LStickDown, - - RStickLeft, - RStickUp, - RStickRight, - RStickDown, - - LeftSL, - LeftSR, - - RightSL, - RightSR, -}; - /** * The InputInterpreter class interfaces with HID to retrieve button press states. * Input is intended to be polled every 50ms so that a button is considered to be @@ -76,7 +44,7 @@ public: * * @returns True when the button is pressed. */ - [[nodiscard]] bool IsButtonPressed(HIDButton button) const; + [[nodiscard]] bool IsButtonPressed(Core::HID::NpadButton button) const; /** * Checks whether any of the buttons in the parameter list is pressed. @@ -85,7 +53,7 @@ public: * * @returns True when at least one of the buttons is pressed. */ - template + template [[nodiscard]] bool IsAnyButtonPressed() { return (IsButtonPressed(T) || ...); } @@ -98,7 +66,7 @@ public: * * @returns True when the button is pressed once. */ - [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const; + [[nodiscard]] bool IsButtonPressedOnce(Core::HID::NpadButton button) const; /** * Checks whether any of the buttons in the parameter list is pressed once. @@ -107,7 +75,7 @@ public: * * @returns True when at least one of the buttons is pressed once. */ - template + template [[nodiscard]] bool IsAnyButtonPressedOnce() const { return (IsButtonPressedOnce(T) || ...); } @@ -119,7 +87,7 @@ public: * * @returns True when the button is held down. */ - [[nodiscard]] bool IsButtonHeld(HIDButton button) const; + [[nodiscard]] bool IsButtonHeld(Core::HID::NpadButton button) const; /** * Checks whether any of the buttons in the parameter list is held down. @@ -128,7 +96,7 @@ public: * * @returns True when at least one of the buttons is held down. */ - template + template [[nodiscard]] bool IsAnyButtonHeld() const { return (IsButtonHeld(T) || ...); } diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 4dd577a18..2cd5ed718 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -9,8 +9,6 @@ #include "common/param_package.h" #include "common/string_util.h" #include "core/core.h" -#include "core/hid/emulated_controller.h -#include "core/hid/hid_types.h #include "core/hle/lock.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 33241ea98..103a12b12 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -24,7 +24,6 @@ #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" #include "input_common/main.h" -#include "input_common/udp/client.h" #include "yuzu_cmd/config.h" #include "yuzu_cmd/default_ini.h" From 06a5ef5874144a70e30e577a83ba68d1dad79e78 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 11 Oct 2021 00:43:11 -0500 Subject: [PATCH 083/291] core/hid: Add output devices --- src/common/input.h | 39 ++++++ src/core/hid/emulated_controller.cpp | 119 ++++++++++++++---- src/core/hid/emulated_controller.h | 13 +- src/core/hid/hid_types.h | 18 +++ src/core/hle/service/hid/controllers/npad.cpp | 27 +--- src/core/hle/service/hid/controllers/npad.h | 18 +-- src/input_common/drivers/gc_adapter.cpp | 8 +- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 8 +- src/input_common/drivers/sdl_driver.h | 2 +- .../helpers/stick_from_buttons.cpp | 3 +- src/input_common/helpers/stick_from_buttons.h | 3 +- .../helpers/touch_from_buttons.cpp | 4 +- src/input_common/input_engine.h | 18 ++- src/input_common/input_poller.cpp | 40 +++++- src/input_common/input_poller.h | 28 ++++- src/input_common/main.cpp | 32 +++-- .../configuration/configure_input_player.cpp | 7 ++ .../configure_input_player_widget.cpp | 59 ++++----- .../configure_input_player_widget.h | 10 +- 20 files changed, 313 insertions(+), 145 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 6eefc55f9..3a28b77a7 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -38,6 +38,27 @@ enum class BatteryLevel { Charging, }; +enum class PollingMode { + Active, + Pasive, + Camera, + NCF, + IR, +}; + +enum class VibrationError { + None, + NotSupported, + Disabled, + Unknown, +}; + +enum class PollingError { + None, + NotSupported, + Unknown, +}; + struct AnalogProperties { float deadzone{}; float range{1.0f}; @@ -149,6 +170,24 @@ private: InputCallback callback; }; +/// An abstract class template for an output device (rumble, LED pattern, polling mode). +class OutputDevice { +public: + virtual ~OutputDevice() = default; + + virtual void SetLED([[maybe_unused]] LedStatus led_status) { + return; + } + + virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { + return VibrationError::NotSupported; + } + + virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { + return PollingError::NotSupported; + } +}; + /// An abstract class template for a factory that can create input devices. template class Factory { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 4eb5d99bc..b9d16657a 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -66,12 +66,32 @@ void EmulatedController::ReloadFromSettings() { for (std::size_t index = 0; index < player.motions.size(); ++index) { motion_params[index] = Common::ParamPackage(player.motions[index]); } + + controller.colors_state.left = { + .body = player.body_color_left, + .button = player.button_color_left, + }; + + controller.colors_state.right = { + .body = player.body_color_right, + .button = player.button_color_right, + }; + + controller.colors_state.fullkey = controller.colors_state.left; + + SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + + if (player.connected) { + Connect(); + } else { + Disconnect(); + } + ReloadInput(); } void EmulatedController::ReloadInput() { const auto player_index = NpadIdTypeToIndex(npad_id_type); - const auto& player = Settings::values.players.GetValue()[player_index]; const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -90,21 +110,13 @@ void EmulatedController::ReloadInput() { trigger_devices[1] = Input::CreateDevice(button_params[Settings::NativeButton::ZR]); - controller.colors_state.left = { - .body = player.body_color_left, - .button = player.button_color_left, - }; - - controller.colors_state.right = { - .body = player.body_color_right, - .button = player.button_color_right, - }; - - controller.colors_state.fullkey = controller.colors_state.left; - battery_devices[0] = Input::CreateDevice(left_side); battery_devices[1] = Input::CreateDevice(right_side); + button_params[Settings::NativeButton::ZL].Set("output",true); + output_devices[0] = + Input::CreateDevice(button_params[Settings::NativeButton::ZL]); + for (std::size_t index = 0; index < button_devices.size(); ++index) { if (!button_devices[index]) { continue; @@ -149,14 +161,6 @@ void EmulatedController::ReloadInput() { [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; motion_devices[index]->SetCallback(motion_callback); } - - SetNpadType(MapSettingsTypeToNPad(player.controller_type)); - - if (player.connected) { - Connect(); - } else { - Disconnect(); - } } void EmulatedController::UnloadInput() { @@ -197,7 +201,8 @@ void EmulatedController::SaveCurrentConfig() { const auto player_index = NpadIdTypeToIndex(npad_id_type); auto& player = Settings::values.players.GetValue()[player_index]; - + player.connected = is_connected; + player.controller_type = MapNPadToSettingsType(npad_type); for (std::size_t index = 0; index < player.buttons.size(); ++index) { player.buttons[index] = button_params[index].Serialize(); } @@ -601,13 +606,50 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t TriggerOnChange(ControllerTriggerType::Battery); } -bool EmulatedController::SetVibration([[maybe_unused]] std::size_t device_index, - [[maybe_unused]] VibrationValue vibration) { - return false; +bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { + if (!output_devices[device_index]) { + return false; + } + + const Input::VibrationStatus status = { + .low_amplitude = vibration.high_amplitude, + .low_frequency = vibration.high_amplitude, + .high_amplitude = vibration.high_amplitude, + .high_frequency = vibration.high_amplitude, + }; + return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } -int EmulatedController::TestVibration(std::size_t device_index) { - return 1; +bool EmulatedController::TestVibration(std::size_t device_index) { + if (!output_devices[device_index]) { + return false; + } + + // Send a slight vibration to test for rumble support + constexpr Input::VibrationStatus status = { + .low_amplitude = 0.001f, + .low_frequency = 160.0f, + .high_amplitude = 0.001f, + .high_frequency = 320.0f, + }; + return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; +} + +void EmulatedController::SetLedPattern() { + for (auto& device : output_devices) { + if (!device) { + continue; + } + + const LedPattern pattern = GetLedPattern(); + const Input::LedStatus status = { + .led_1 = pattern.position1 != 0, + .led_2 = pattern.position2 != 0, + .led_3 = pattern.position3 != 0, + .led_4 = pattern.position4 != 0, + }; + device->SetLED(status); + } } void EmulatedController::Connect() { @@ -655,6 +697,29 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { TriggerOnChange(ControllerTriggerType::Type); } +LedPattern EmulatedController::GetLedPattern() const { + switch (npad_id_type) { + case NpadIdType::Player1: + return LedPattern{1, 0, 0, 0}; + case NpadIdType::Player2: + return LedPattern{1, 1, 0, 0}; + case NpadIdType::Player3: + return LedPattern{1, 1, 1, 0}; + case NpadIdType::Player4: + return LedPattern{1, 1, 1, 1}; + case NpadIdType::Player5: + return LedPattern{1, 0, 0, 1}; + case NpadIdType::Player6: + return LedPattern{1, 0, 1, 0}; + case NpadIdType::Player7: + return LedPattern{1, 0, 1, 1}; + case NpadIdType::Player8: + return LedPattern{0, 1, 1, 0}; + default: + return LedPattern{0, 0, 0, 0}; + } +} + ButtonValues EmulatedController::GetButtonsValues() const { return controller.button_values; } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 94db9b00b..322d2cab0 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -33,12 +33,14 @@ using ControllerMotionDevices = using TriggerDevices = std::array, Settings::NativeTrigger::NumTriggers>; using BatteryDevices = std::array, 2>; +using OutputDevices = std::array, 2>; using ButtonParams = std::array; using StickParams = std::array; using ControllerMotionParams = std::array; using TriggerParams = std::array; using BatteryParams = std::array; +using OutputParams = std::array; using ButtonValues = std::array; using SticksValues = std::array; @@ -94,6 +96,7 @@ struct ControllerStatus { ControllerColors colors_state{}; BatteryLevelState battery_state{}; }; + enum class ControllerTriggerType { Button, Stick, @@ -137,6 +140,9 @@ public: /// Gets the NpadType for this controller. NpadType GetNpadType() const; + /// Gets the NpadType for this controller. + LedPattern GetLedPattern() const; + void Connect(); void Disconnect(); @@ -179,7 +185,9 @@ public: BatteryLevelState GetBattery() const; bool SetVibration(std::size_t device_index, VibrationValue vibration); - int TestVibration(std::size_t device_index); + bool TestVibration(std::size_t device_index); + + void SetLedPattern(); int SetCallback(ControllerUpdateCallback update_callback); void DeleteCallback(int key); @@ -215,13 +223,14 @@ private: ControllerMotionParams motion_params; TriggerParams trigger_params; BatteryParams battery_params; + OutputParams output_params; ButtonDevices button_devices; StickDevices stick_devices; ControllerMotionDevices motion_devices; TriggerDevices trigger_devices; BatteryDevices battery_devices; - // VibrationDevices vibration_devices; + OutputDevices output_devices; mutable std::mutex mutex; std::unordered_map callback_list; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index d3f7930c9..f12a14cb8 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -112,6 +112,8 @@ struct NpadStyleTag { BitField<7, 1, u32> lark; BitField<8, 1, u32> handheld_lark; BitField<9, 1, u32> lucia; + BitField<10, 1, u32> lagoon; + BitField<11, 1, u32> lager; BitField<29, 1, u32> system_ext; BitField<30, 1, u32> system; }; @@ -175,6 +177,22 @@ struct NpadPowerInfo { }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); +struct LedPattern { + explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { + position1.Assign(light1); + position2.Assign(light2); + position3.Assign(light3); + position4.Assign(light4); + } + union { + u64 raw{}; + BitField<0, 1, u64> position1; + BitField<1, 1, u64> position2; + BitField<2, 1, u64> position3; + BitField<3, 1, u64> position4; + }; +}; + // This is nn::hid::NpadButton enum class NpadButton : u64 { None = 0, diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 03cbd42f4..a2e9ddf4d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -796,7 +796,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, } controller.vibration[device_index].device_mounted = - controller.device->TestVibration(device_index) == 1; + controller.device->TestVibration(device_index); } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { @@ -954,31 +954,12 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { return true; } -Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { +Core::HID::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { // These are controllers without led patterns - return LedPattern{0, 0, 0, 0}; - } - switch (npad_id) { - case 0: - return LedPattern{1, 0, 0, 0}; - case 1: - return LedPattern{1, 1, 0, 0}; - case 2: - return LedPattern{1, 1, 1, 0}; - case 3: - return LedPattern{1, 1, 1, 1}; - case 4: - return LedPattern{1, 0, 0, 1}; - case 5: - return LedPattern{1, 0, 1, 0}; - case 6: - return LedPattern{1, 0, 1, 1}; - case 7: - return LedPattern{0, 1, 1, 0}; - default: - return LedPattern{0, 0, 0, 0}; + return Core::HID::LedPattern{0, 0, 0, 0}; } + return controller_data[npad_id].device->GetLedPattern(); } bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 483cae5b6..b0e2f8430 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -115,22 +115,6 @@ public: .freq_high = 320.0f, }; - struct LedPattern { - explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { - position1.Assign(light1); - position2.Assign(light2); - position3.Assign(light3); - position4.Assign(light4); - } - union { - u64 raw{}; - BitField<0, 1, u64> position1; - BitField<1, 1, u64> position2; - BitField<2, 1, u64> position3; - BitField<3, 1, u64> position4; - }; - }; - void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; @@ -186,7 +170,7 @@ public: void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); std::pair GetSixAxisFusionParameters(); void ResetSixAxisFusionParameters(); - LedPattern GetLedPattern(u32 npad_id); + Core::HID::LedPattern GetLedPattern(u32 npad_id); bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); void SetAnalogStickUseCenterClamp(bool use_center_clamp); diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 6721ba4f7..2aa5a16a6 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -322,13 +322,17 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -bool GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); pads[identifier.port].rumble_amplitude = processed_amplitude; - return rumble_enabled; + + if (!rumble_enabled) { + return Input::VibrationError::Disabled; + } + return Input::VibrationError::None; } void GCAdapter::UpdateVibrations() { diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index c0bf1ed7a..dd23dd9f3 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -24,7 +24,7 @@ public: explicit GCAdapter(const std::string input_engine_); ~GCAdapter(); - bool SetRumble(const PadIdentifier& identifier, + Input::VibrationError SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) override; /// Used for automapping features diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index efb4a2106..f7f03c5f2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -506,7 +506,8 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude = [](f32 amplitude) { @@ -519,7 +520,10 @@ bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::Vibratio .high_frequency = vibration.high_frequency, }; - return joystick->RumblePlay(new_vibration); + if (!joystick->RumblePlay(new_vibration)) { + return Input::VibrationError::Unknown; + } + return Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d8d350184..f66b33c77 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -58,7 +58,7 @@ public: std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string direction_name) const override; - bool SetRumble(const PadIdentifier& identifier, + Input::VibrationError SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) override; private: diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 38f150746..89ba4aeb1 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -251,7 +251,8 @@ private: std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 1d6e24c98..87165e022 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -25,7 +25,8 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 2abfaf841..6c9046ffb 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -57,7 +57,9 @@ private: const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; -std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { + +std::unique_ptr TouchFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto button = Input::CreateDeviceFromString(params.Get("button", null_engine)); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 86a8e00d8..8a953c382 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -114,18 +114,24 @@ public: // Disable configuring mode for mapping void EndConfiguration(); - // Sets rumble to a controller - virtual bool SetRumble([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { - return false; - } - // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const Input::LedStatus led_status) { return; } + // Sets rumble to a controller + virtual Input::VibrationError SetRumble([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::VibrationStatus vibration) { + return Input::VibrationError::NotSupported; + } + + // Sets polling mode to a controller + virtual Input::PollingError SetPollingMode([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::PollingMode vibration) { + return Input::PollingError::NotSupported; + } + // Returns the engine name [[nodiscard]] const std::string& GetEngineName() const; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 46a7dd276..781012886 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -592,6 +592,28 @@ private: InputEngine* input_engine; }; +class OutputFromIdentifier final : public Input::OutputDevice { +public: + explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) + : identifier(identifier_), input_engine(input_engine_) {} + + virtual void SetLED( Input::LedStatus led_status) { + input_engine->SetLeds(identifier, led_status); + } + + virtual Input::VibrationError SetVibration(Input::VibrationStatus vibration_status) { + return input_engine->SetRumble(identifier, vibration_status); + } + + virtual Input::PollingError SetPollingMode(Input::PollingMode polling_mode) { + return input_engine->SetPollingMode(identifier, polling_mode); + } + +private: + const PadIdentifier identifier; + InputEngine* input_engine; +}; + std::unique_ptr InputFactory::CreateButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { @@ -825,7 +847,8 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create( + const Common::ParamPackage& params) { if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } @@ -857,4 +880,19 @@ std::unique_ptr InputFactory::Create(const Common::ParamPack return std::make_unique(); } +OutputFactory::OutputFactory(std::shared_ptr input_engine_) + : input_engine(std::move(input_engine_)) {} + +std::unique_ptr OutputFactory::Create( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + input_engine->PreSetController(identifier); + return std::make_unique(identifier, input_engine.get()); +} + } // namespace InputCommon diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 3c1e5b541..16cade5fa 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -16,12 +16,32 @@ class InputEngine; /** * An Input factory. It receives input events and forward them to all input devices it created. */ + +class OutputFactory final : public Input::Factory { +public: + explicit OutputFactory(std::shared_ptr input_engine_); + + /** + * Creates an output device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique ouput device with the parameters specified + */ + std::unique_ptr Create( + const Common::ParamPackage& params) override; + +private: + std::shared_ptr input_engine; +}; + class InputFactory final : public Input::Factory { public: explicit InputFactory(std::shared_ptr input_engine_); /** - * Creates a input device from the parameters given. Identifies the type of input to be returned + * Creates an input device from the parameters given. Identifies the type of input to be returned * if it contains the following parameters: * - button: Contains "button" or "code" * - hat_button: Contains "hat" @@ -32,6 +52,7 @@ public: * - motion: Contains "motion" * - touch: Contains "button", "axis_x" and "axis_y" * - battery: Contains "battery" + * - output: Contains "output" * @param params contains parameters for creating the device: * @param - "code": the code of the keyboard key to bind with the input * @param - "button": same as "code" but for controller buttons @@ -41,10 +62,11 @@ public: * @param - "axis_x": same as axis but specifing horizontal direction * @param - "axis_y": same as axis but specifing vertical direction * @param - "axis_z": same as axis but specifing forward direction - * @param - "battery": Only used as a placeholder to set the input type + * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; private: /** diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 46ca6b76c..b7fe9cb37 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -46,8 +46,10 @@ struct InputSubsystem::Impl { gcadapter = std::make_shared("gcpad"); gcadapter->SetMappingCallback(mapping_callback); - gcadapter_factory = std::make_shared(gcadapter); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_factory); + gcadapter_input_factory = std::make_shared(gcadapter); + gcadapter_output_factory = std::make_shared(gcadapter); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_input_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_output_factory); udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); @@ -62,8 +64,10 @@ struct InputSubsystem::Impl { #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); - sdl_factory = std::make_shared(sdl); - Input::RegisterFactory(sdl->GetEngineName(), sdl_factory); + sdl_input_factory = std::make_shared(sdl); + sdl_output_factory = std::make_shared(sdl); + Input::RegisterFactory(sdl->GetEngineName(), sdl_input_factory); + Input::RegisterFactory(sdl->GetEngineName(), sdl_output_factory); #endif Input::RegisterFactory("touch_from_button", @@ -247,21 +251,27 @@ struct InputSubsystem::Impl { } std::shared_ptr mapping_factory; + std::shared_ptr keyboard; - std::shared_ptr keyboard_factory; std::shared_ptr mouse; - std::shared_ptr mouse_factory; std::shared_ptr gcadapter; - std::shared_ptr gcadapter_factory; std::shared_ptr touch_screen; - std::shared_ptr touch_screen_factory; - std::shared_ptr udp_client; - std::shared_ptr udp_client_factory; std::shared_ptr tas_input; + std::shared_ptr udp_client; + + std::shared_ptr keyboard_factory; + std::shared_ptr mouse_factory; + std::shared_ptr gcadapter_input_factory; + std::shared_ptr touch_screen_factory; + std::shared_ptr udp_client_factory; std::shared_ptr tas_input_factory; + + std::shared_ptr gcadapter_output_factory; + #ifdef HAVE_SDL2 std::shared_ptr sdl; - std::shared_ptr sdl_factory; + std::shared_ptr sdl_input_factory; + std::shared_ptr sdl_output_factory; #endif }; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index adc9706f1..ed9c3facf 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -465,6 +465,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); + emulated_controller->SetNpadType( + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, @@ -540,6 +542,11 @@ void ConfigureInputPlayer::LoadConfiguration() { void ConfigureInputPlayer::ConnectPlayer(bool connected) { ui->groupConnectedController->setChecked(connected); + if (connected) { + emulated_controller->Connect(); + } else { + emulated_controller->Disconnect(); + } } void ConfigureInputPlayer::UpdateInputDeviceCombobox() { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 03d29f194..2ba9d7290 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -24,34 +24,6 @@ PlayerControlPreview::~PlayerControlPreview() { } }; -PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index, - bool player_on) { - if (!player_on) { - return {0, 0, 0, 0}; - } - - switch (index) { - case 0: - return {1, 0, 0, 0}; - case 1: - return {1, 1, 0, 0}; - case 2: - return {1, 1, 1, 0}; - case 3: - return {1, 1, 1, 1}; - case 4: - return {1, 0, 0, 1}; - case 5: - return {1, 0, 1, 0}; - case 6: - return {1, 0, 1, 1}; - case 7: - return {0, 1, 1, 0}; - default: - return {0, 0, 0, 0}; - } -} - void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { if (is_controller_set) { controller->DeleteCallback(callback_key); @@ -160,8 +132,13 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ switch (type) { case Core::HID::ControllerTriggerType::Connected: + is_connected = true; + led_pattern = controller->GetLedPattern(); + needs_redraw = true; + break; case Core::HID::ControllerTriggerType::Disconnected: - is_connected = controller->IsConnected(); + is_connected = false; + led_pattern.raw = 0; needs_redraw = true; break; case Core::HID::ControllerTriggerType::Type: @@ -1853,10 +1830,14 @@ void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) { const float led_size = 5.0f; const QPointF led_position = sideview_center + QPointF(0, -36); int led_count = 0; - for (const auto& color : led_color) { - p.setBrush(color); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - } + p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); } void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { @@ -1949,10 +1930,14 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { const float led_size = 5.0f; const QPointF led_position = sideview_center + QPointF(0, -36); int led_count = 0; - for (const auto& color : led_color) { - p.setBrush(color); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - } + p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); } void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index b44a2e347..16f9748f5 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -59,13 +59,6 @@ private: SR, }; - struct LedPattern { - bool position1; - bool position2; - bool position3; - bool position4; - }; - struct ColorMapping { QColor outline{}; QColor primary{}; @@ -88,7 +81,6 @@ private: QColor deadzone{}; }; - static LedPattern GetColorPattern(std::size_t index, bool player_on); void UpdateColors(); void ResetInputs(); @@ -194,7 +186,7 @@ private: int callback_key; QColor button_color{}; ColorMapping colors{}; - std::array led_color{}; + Core::HID::LedPattern led_pattern{0, 0, 0, 0}; std::size_t player_index{}; Core::HID::EmulatedController* controller; std::size_t button_mapping_index{Settings::NativeButton::NumButtons}; From e0da5c1bbcdf85676f968b63c8ae2587f0464193 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 15 Oct 2021 19:07:47 -0500 Subject: [PATCH 084/291] kraken: Fix errors from rebase and format files --- src/core/hid/emulated_controller.cpp | 6 ++++- src/core/hle/service/hid/hid.cpp | 1 - src/input_common/drivers/gc_adapter.cpp | 3 ++- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.h | 2 +- .../helpers/stick_from_buttons.cpp | 3 +-- src/input_common/helpers/stick_from_buttons.h | 3 +-- .../helpers/touch_from_buttons.cpp | 4 +-- src/input_common/input_engine.h | 10 +++++--- src/input_common/input_poller.cpp | 8 +++--- src/input_common/input_poller.h | 10 +++----- src/input_common/main.cpp | 6 +++-- src/yuzu/applets/qt_controller.h | 1 - src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_input.cpp | 9 ++++--- .../configure_input_player_widget.cpp | 25 +++++++++++-------- .../configure_input_player_widget.h | 16 +++++++++++- src/yuzu/debugger/controller.cpp | 9 +++++-- src/yuzu/debugger/controller.h | 9 ++++++- src/yuzu/main.cpp | 7 +++--- 20 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index b9d16657a..b04ab4cd8 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -91,6 +91,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { + // If you load any device here add the equivalent to the UnloadInput() function const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -113,7 +114,7 @@ void EmulatedController::ReloadInput() { battery_devices[0] = Input::CreateDevice(left_side); battery_devices[1] = Input::CreateDevice(right_side); - button_params[Settings::NativeButton::ZL].Set("output",true); + button_params[Settings::NativeButton::ZL].Set("output", true); output_devices[0] = Input::CreateDevice(button_params[Settings::NativeButton::ZL]); @@ -179,6 +180,9 @@ void EmulatedController::UnloadInput() { for (auto& battery : battery_devices) { battery.reset(); } + for (auto& output : output_devices) { + output.reset(); + } } void EmulatedController::EnableConfiguration() { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 18f29bb78..5391334f4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/input.h" #include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 2aa5a16a6..4a56abb99 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -322,7 +322,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index dd23dd9f3..dd0e4aa1d 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -25,7 +25,7 @@ public: ~GCAdapter(); Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + const Input::VibrationStatus vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index f66b33c77..1ff85f48d 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -59,7 +59,7 @@ public: u8 GetHatButtonId(const std::string direction_name) const override; Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + const Input::VibrationStatus vibration) override; private: void InitJoystick(int joystick_index); diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 89ba4aeb1..38f150746 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -251,8 +251,7 @@ private: std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create( - const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 87165e022..1d6e24c98 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -25,8 +25,7 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 6c9046ffb..2abfaf841 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -57,9 +57,7 @@ private: const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; - -std::unique_ptr TouchFromButton::Create( - const Common::ParamPackage& params) { +std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto button = Input::CreateDeviceFromString(params.Get("button", null_engine)); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 8a953c382..31ce900d7 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -121,14 +121,16 @@ public: } // Sets rumble to a controller - virtual Input::VibrationError SetRumble([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { + virtual Input::VibrationError SetRumble( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::VibrationStatus vibration) { return Input::VibrationError::NotSupported; } // Sets polling mode to a controller - virtual Input::PollingError SetPollingMode([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::PollingMode vibration) { + virtual Input::PollingError SetPollingMode( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::PollingMode vibration) { return Input::PollingError::NotSupported; } diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 781012886..62ade951c 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -597,7 +597,7 @@ public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED( Input::LedStatus led_status) { + virtual void SetLED(Input::LedStatus led_status) { input_engine->SetLeds(identifier, led_status); } @@ -847,8 +847,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create( - const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } @@ -883,8 +882,7 @@ std::unique_ptr InputFactory::Create( OutputFactory::OutputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr OutputFactory::Create( - const Common::ParamPackage& params) { +std::unique_ptr OutputFactory::Create(const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 16cade5fa..1357e104b 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -29,8 +29,7 @@ public: * @param - "pad": slot of the connected controller * @return an unique ouput device with the parameters specified */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: std::shared_ptr input_engine; @@ -41,8 +40,8 @@ public: explicit InputFactory(std::shared_ptr input_engine_); /** - * Creates an input device from the parameters given. Identifies the type of input to be returned - * if it contains the following parameters: + * Creates an input device from the parameters given. Identifies the type of input to be + * returned if it contains the following parameters: * - button: Contains "button" or "code" * - hat_button: Contains "hat" * - analog: Contains "axis" @@ -65,8 +64,7 @@ public: * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: /** diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b7fe9cb37..7807dd38f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -48,8 +48,10 @@ struct InputSubsystem::Impl { gcadapter->SetMappingCallback(mapping_callback); gcadapter_input_factory = std::make_shared(gcadapter); gcadapter_output_factory = std::make_shared(gcadapter); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_input_factory); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_output_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_input_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_output_factory); udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index 98060e6f8..ca09fde04 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -106,7 +106,6 @@ private: Core::Frontend::ControllerParameters parameters; InputCommon::InputSubsystem* input_subsystem; - Core::System& system; std::unique_ptr input_profiles; diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 642a5f966..1eb9d70e5 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -74,7 +74,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, hotkeys_tab->Populate(registry); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - input_tab->Initialize(input_subsystem); + input_tab->Initialize(input_subsystem, system_); general_tab->SetResetCallback([&] { this->close(); }); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 61513865f..a8611f77f 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -146,10 +146,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Co advanced = new ConfigureInputAdvanced(this); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->layout()->addWidget(advanced); - connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] { - CallConfigureDialog(*this, input_subsystem, profiles.get(), - system); - }); + connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, + [this, input_subsystem, &system] { + CallConfigureDialog(*this, input_subsystem, + profiles.get(), system); + }); connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 2ba9d7290..446b72e55 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -19,15 +19,11 @@ PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { } PlayerControlPreview::~PlayerControlPreview() { - if (is_controller_set) { - controller->DeleteCallback(callback_key); - } + UnloadController(); }; void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { - if (is_controller_set) { - controller->DeleteCallback(callback_key); - } + UnloadController(); is_controller_set = true; controller = controller_; Core::HID::ControllerUpdateCallback engine_callback{ @@ -36,14 +32,21 @@ void PlayerControlPreview::SetController(Core::HID::EmulatedController* controll ControllerUpdate(Core::HID::ControllerTriggerType::All); } -void PlayerControlPreview::BeginMappingButton(std::size_t index) { - button_mapping_index = index; +void PlayerControlPreview::UnloadController() { + if (is_controller_set) { + controller->DeleteCallback(callback_key); + is_controller_set = false; + } +} + +void PlayerControlPreview::BeginMappingButton(std::size_t button_id) { + button_mapping_index = button_id; mapping_active = true; } -void PlayerControlPreview::BeginMappingAnalog(std::size_t index) { - button_mapping_index = Settings::NativeButton::LStick + index; - analog_mapping_index = index; +void PlayerControlPreview::BeginMappingAnalog(std::size_t stick_id) { + button_mapping_index = Settings::NativeButton::LStick + stick_id; + analog_mapping_index = stick_id; mapping_active = true; } diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 16f9748f5..333c3fc56 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -25,11 +25,25 @@ public: explicit PlayerControlPreview(QWidget* parent); ~PlayerControlPreview() override; + // Sets the emulated controller to be displayed void SetController(Core::HID::EmulatedController* controller); + + // Disables events from the emulated controller + void UnloadController(); + + // Starts blinking animation at the button specified void BeginMappingButton(std::size_t button_id); - void BeginMappingAnalog(std::size_t button_id); + + // Starts moving animation at the stick specified + void BeginMappingAnalog(std::size_t stick_id); + + // Stops any ongoing animation void EndMapping(); + + // Handles emulated controller events void ControllerUpdate(Core::HID::ControllerTriggerType type); + + // Updates input on sheduled interval void UpdateInput(); protected: diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index d8e41f8b6..3619aed26 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -10,7 +10,8 @@ #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { +ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) + : QWidget(parent, Qt::Dialog) { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -20,7 +21,7 @@ ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(Core::System::GetInstance().HIDCore().GetEmulatedController( + widget->SetController(system.HIDCore().GetEmulatedController( Core::HID::NpadIdType::Player1)); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -45,6 +46,10 @@ QAction* ControllerDialog::toggleViewAction() { return toggle_view_action; } +void ControllerDialog::UnloadController() { + widget->UnloadController(); +} + void ControllerDialog::showEvent(QShowEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 697489cbb..33f617b9b 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -11,6 +11,10 @@ class QHideEvent; class QShowEvent; class PlayerControlPreview; +namespace Core { +class System; +} + namespace InputCommon { class InputSubsystem; } @@ -19,11 +23,14 @@ class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(QWidget* parent = nullptr); + explicit ControllerDialog(Core::System& system, QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); + // Disables events from the emulated controller + void UnloadController(); + protected: void showEvent(QShowEvent* ev) override; void hideEvent(QHideEvent* ev) override; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 19cb5313f..ae997ccfa 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -228,7 +228,7 @@ GMainWindow::GMainWindow() ConnectMenuEvents(); ConnectWidgetEvents(); - Core::System::GetInstance().HIDCore().ReloadInputDevices(); + system->HIDCore().ReloadInputDevices(); const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); @@ -924,7 +924,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(this); + controller_dialog = new ControllerDialog(*system, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -3372,7 +3372,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); hotkey_registry.SaveHotkeys(); - Core::System::GetInstance().HIDCore().UnloadInputDevices(); + controller_dialog->UnloadController(); + system->HIDCore().UnloadInputDevices(); // Shutdown session if the emu thread is active... if (emu_thread != nullptr) { From 72e5920240381cbe775dc38fcdff88cf46b55101 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 17 Oct 2021 00:33:00 -0500 Subject: [PATCH 085/291] core/hid: Documment some files --- src/core/hid/emulated_console.h | 69 +++++++++++--- src/core/hid/emulated_controller.h | 148 +++++++++++++++++++++++++---- src/core/hid/emulated_devices.cpp | 16 +++- src/core/hid/emulated_devices.h | 84 ++++++++++++---- 4 files changed, 265 insertions(+), 52 deletions(-) diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index d9e275042..7d6cf9506 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -38,9 +38,10 @@ struct TouchFinger { Common::Point position{}; u32_le id{}; bool pressed{}; - Core::HID::TouchAttribute attribute{}; + TouchAttribute attribute{}; }; +// Contains all motion related data that is used on the services struct ConsoleMotion { bool is_at_rest{}; Common::Vec3f accel{}; @@ -57,7 +58,7 @@ struct ConsoleStatus { ConsoleMotionValues motion_values{}; TouchValues touch_values{}; - // Data for Nintendo devices; + // Data for HID services ConsoleMotion motion_state{}; TouchFingerState touch_state{}; }; @@ -75,52 +76,90 @@ struct ConsoleUpdateCallback { class EmulatedConsole { public: /** - * TODO: Write description - * - * @param npad_id_type + * Contains all input data related to the console like motion and touch input */ - explicit EmulatedConsole(); + EmulatedConsole(); ~EmulatedConsole(); YUZU_NON_COPYABLE(EmulatedConsole); YUZU_NON_MOVEABLE(EmulatedConsole); - void ReloadFromSettings(); - void ReloadInput(); + /// Removes all callbacks created from input devices void UnloadInput(); + /// Sets the emulated console into configuring mode. Locking all HID service events from being + /// moddified void EnableConfiguration(); + + /// Returns the emulated console to the normal behaivour void DisableConfiguration(); + + /// Returns true if the emulated console is on configuring mode bool IsConfiguring() const; + + /// Reload all input devices + void ReloadInput(); + + /// Overrides current mapped devices with the stored configuration and reloads all input devices + void ReloadFromSettings(); + + /// Saves the current mapped configuration void SaveCurrentConfig(); + + /// Reverts any mapped changes made that weren't saved void RestoreConfig(); + // Returns the current mapped motion device Common::ParamPackage GetMotionParam() const; + /** + * Updates the current mapped motion device + * @param ParamPackage with controller data to be mapped + */ void SetMotionParam(Common::ParamPackage param); + /// Returns the latest status of motion input from the console with parameters ConsoleMotionValues GetMotionValues() const; + + /// Returns the latest status of touch input from the console with parameters TouchValues GetTouchValues() const; + /// Returns the latest status of motion input from the console ConsoleMotion GetMotion() const; + + /// Returns the latest status of touch input from the console TouchFingerState GetTouch() const; + /** + * Adds a callback to the list of events + * @param ConsoleUpdateCallback that will be triggered + * @return an unique key corresponding to the callback index in the list + */ int SetCallback(ConsoleUpdateCallback update_callback); + + /** + * Removes a callback from the list stopping any future events to this object + * @param Key corresponding to the callback index in the list + */ void DeleteCallback(int key); private: /** - * Sets the status of a button. Applies toggle properties to the output. - * - * @param A CallbackStatus and a button index number + * Updates the motion status of the console + * @param A CallbackStatus containing gyro and accelerometer data */ void SetMotion(Input::CallbackStatus callback); + + /** + * Updates the touch status of the console + * @param callback: A CallbackStatus containing the touch position + * @param index: Finger ID to be updated + */ void SetTouch(Input::CallbackStatus callback, std::size_t index); /** - * Triggers a callback that something has changed - * - * @param Input type of the trigger + * Triggers a callback that something has changed on the console status + * @param Input type of the event to trigger */ void TriggerOnChange(ConsoleTriggerType type); @@ -136,6 +175,8 @@ private: mutable std::mutex mutex; std::unordered_map callback_list; int last_callback_key = 0; + + // Stores the current status of all console input ConsoleStatus console; }; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 322d2cab0..096fe1705 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -87,7 +87,7 @@ struct ControllerStatus { BatteryValues battery_values{}; VibrationValues vibration_values{}; - // Data for Nintendo devices + // Data for HID serices NpadButtonState npad_button_state{}; DebugPadButton debug_pad_button_state{}; AnalogSticks analog_stick_state{}; @@ -118,9 +118,8 @@ struct ControllerUpdateCallback { class EmulatedController { public: /** - * TODO: Write description - * - * @param npad_id_type + * Contains all input data related to this controller. Like buttons, joysticks, motion. + * @param Npad id type for this specific controller */ explicit EmulatedController(NpadIdType npad_id_type_); ~EmulatedController(); @@ -128,86 +127,197 @@ public: YUZU_NON_COPYABLE(EmulatedController); YUZU_NON_MOVEABLE(EmulatedController); + /// Converts the controller type from settings to npad type static NpadType MapSettingsTypeToNPad(Settings::ControllerType type); + + /// Converts npad type to the equivalent of controller type from settings static Settings::ControllerType MapNPadToSettingsType(NpadType type); - /// Gets the NpadIdType for this controller. + /// Gets the NpadIdType for this controller NpadIdType GetNpadIdType() const; - /// Sets the NpadType for this controller. + /// Sets the NpadType for this controller void SetNpadType(NpadType npad_type_); - /// Gets the NpadType for this controller. + /// Gets the NpadType for this controller NpadType GetNpadType() const; - /// Gets the NpadType for this controller. - LedPattern GetLedPattern() const; - + /// Sets the connected status to true void Connect(); + + /// Sets the connected status to false void Disconnect(); + /// Returns true if the controller has the connected status bool IsConnected() const; + + /// Returns true if vibration is enabled bool IsVibrationEnabled() const; - void ReloadFromSettings(); - void ReloadInput(); + /// Removes all callbacks created from input devices void UnloadInput(); + /// Sets the emulated console into configuring mode. Locking all HID service events from being + /// moddified void EnableConfiguration(); + + /// Returns the emulated console to the normal behaivour void DisableConfiguration(); + + /// Returns true if the emulated device is on configuring mode bool IsConfiguring() const; + + /// Reload all input devices + void ReloadInput(); + + /// Overrides current mapped devices with the stored configuration and reloads all input devices + void ReloadFromSettings(); + + /// Saves the current mapped configuration void SaveCurrentConfig(); + + /// Reverts any mapped changes made that weren't saved void RestoreConfig(); + /// Returns a vector of mapped devices from the mapped button and stick parameters std::vector GetMappedDevices() const; + // Returns the current mapped button device Common::ParamPackage GetButtonParam(std::size_t index) const; + + // Returns the current mapped stick device Common::ParamPackage GetStickParam(std::size_t index) const; + + // Returns the current mapped motion device Common::ParamPackage GetMotionParam(std::size_t index) const; + /** + * Updates the current mapped button device + * @param ParamPackage with controller data to be mapped + */ void SetButtonParam(std::size_t index, Common::ParamPackage param); + + /** + * Updates the current mapped stick device + * @param ParamPackage with controller data to be mapped + */ void SetStickParam(std::size_t index, Common::ParamPackage param); + + /** + * Updates the current mapped motion device + * @param ParamPackage with controller data to be mapped + */ void SetMotionParam(std::size_t index, Common::ParamPackage param); + /// Returns the latest button status from the controller with parameters ButtonValues GetButtonsValues() const; + + /// Returns the latest analog stick status from the controller with parameters SticksValues GetSticksValues() const; + + /// Returns the latest trigger status from the controller with parameters TriggerValues GetTriggersValues() const; + + /// Returns the latest motion status from the controller with parameters ControllerMotionValues GetMotionValues() const; + + /// Returns the latest color status from the controller with parameters ColorValues GetColorsValues() const; + + /// Returns the latest battery status from the controller with parameters BatteryValues GetBatteryValues() const; + /// Returns the latest status of button input for the npad service NpadButtonState GetNpadButtons() const; + + /// Returns the latest status of button input for the debug pad service DebugPadButton GetDebugPadButtons() const; + + /// Returns the latest status of stick input from the mouse AnalogSticks GetSticks() const; + + /// Returns the latest status of trigger input from the mouse NpadGcTriggerState GetTriggers() const; + + /// Returns the latest status of motion input from the mouse MotionState GetMotions() const; + + /// Returns the latest color value from the controller ControllerColors GetColors() const; + + /// Returns the latest battery status from the controller BatteryLevelState GetBattery() const; + /* + * Sends a specific vibration to the output device + * @return returns true if vibration had no errors + */ bool SetVibration(std::size_t device_index, VibrationValue vibration); + + /* + * Sends a small vibration to the output device + * @return returns true if SetVibration was successfull + */ bool TestVibration(std::size_t device_index); + /// Returns the led pattern corresponding to this emulated controller + LedPattern GetLedPattern() const; + + /// Asks the output device to change the player led pattern void SetLedPattern(); + /** + * Adds a callback to the list of events + * @param ConsoleUpdateCallback that will be triggered + * @return an unique key corresponding to the callback index in the list + */ int SetCallback(ControllerUpdateCallback update_callback); + + /** + * Removes a callback from the list stopping any future events to this object + * @param Key corresponding to the callback index in the list + */ void DeleteCallback(int key); private: /** - * Sets the status of a button. Applies toggle properties to the output. - * - * @param A CallbackStatus and a button index number + * Updates the button status of the controller + * @param callback: A CallbackStatus containing the button status + * @param index: Button ID of the to be updated */ void SetButton(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the analog stick status of the controller + * @param callback: A CallbackStatus containing the analog stick status + * @param index: stick ID of the to be updated + */ void SetStick(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the trigger status of the controller + * @param callback: A CallbackStatus containing the trigger status + * @param index: trigger ID of the to be updated + */ void SetTrigger(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the motion status of the controller + * @param callback: A CallbackStatus containing gyro and accelerometer data + * @param index: motion ID of the to be updated + */ void SetMotion(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the battery status of the controller + * @param callback: A CallbackStatus containing the battery status + * @param index: Button ID of the to be updated + */ void SetBattery(Input::CallbackStatus callback, std::size_t index); /** - * Triggers a callback that something has changed - * - * @param Input type of the trigger + * Triggers a callback that something has changed on the controller status + * @param Input type of the event to trigger */ void TriggerOnChange(ControllerTriggerType type); @@ -235,6 +345,8 @@ private: mutable std::mutex mutex; std::unordered_map callback_list; int last_callback_key = 0; + + // Stores the current status of all controller input ControllerStatus controller; }; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 3caf90714..54a753d8a 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -114,7 +114,7 @@ Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) con return mouse_button_params[index]; } -void EmulatedDevices::SetButtonParam(std::size_t index, Common::ParamPackage param) { +void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) { if (index >= mouse_button_params.size()) { return; } @@ -132,7 +132,7 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz auto& current_status = device_status.keyboard_values[index]; current_status.toggle = new_status.toggle; - // Update button status with current + // Update button status with current status if (!current_status.toggle) { current_status.locked = false; if (current_status.value != new_status.value) { @@ -147,7 +147,7 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz value_changed = true; } - // Unlock button ready for next press + // Unlock button, ready for next press if (!new_status.value && current_status.locked) { current_status.locked = false; } @@ -168,7 +168,7 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz // interface_status.keyboard_state.a.Assign(current_status.value); // break; // .... - //} + // } TriggerOnChange(DeviceTriggerType::Keyboard); } @@ -303,6 +303,14 @@ void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t TriggerOnChange(DeviceTriggerType::Mouse); } +KeyboardValues EmulatedDevices::GetKeyboardValues() const { + return device_status.keyboard_values; +} + +KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const { + return device_status.keyboard_moddifier_values; +} + MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { return device_status.mouse_button_values; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 6f728eff5..c6c19fae4 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -45,7 +45,7 @@ struct DeviceStatus { KeyboardModifierValues keyboard_moddifier_values{}; MouseButtonValues mouse_button_values{}; - // Data for Nintendo devices + // Data for HID serices KeyboardKey keyboard_state{}; KeyboardModifier keyboard_moddifier_state{}; MouseButton mouse_button_state{}; @@ -65,58 +65,108 @@ struct InterfaceUpdateCallback { class EmulatedDevices { public: /** - * TODO: Write description - * - * @param npad_id_type + * Contains all input data related to external devices that aren't necesarily a controller + * like keyboard and mouse */ - explicit EmulatedDevices(); + EmulatedDevices(); ~EmulatedDevices(); YUZU_NON_COPYABLE(EmulatedDevices); YUZU_NON_MOVEABLE(EmulatedDevices); - void ReloadFromSettings(); - void ReloadInput(); + /// Removes all callbacks created from input devices void UnloadInput(); + /// Sets the emulated console into configuring mode. Locking all HID service events from being + /// moddified void EnableConfiguration(); + + /// Returns the emulated console to the normal behaivour void DisableConfiguration(); + + /// Returns true if the emulated device is on configuring mode bool IsConfiguring() const; + + /// Reload all input devices + void ReloadInput(); + + /// Overrides current mapped devices with the stored configuration and reloads all input devices + void ReloadFromSettings(); + + /// Saves the current mapped configuration void SaveCurrentConfig(); + + /// Reverts any mapped changes made that weren't saved void RestoreConfig(); - std::vector GetMappedDevices() const; - + /// Returns the current mapped motion device Common::ParamPackage GetMouseButtonParam(std::size_t index) const; - void SetButtonParam(std::size_t index, Common::ParamPackage param); + /** + * Updates the current mapped mouse button device + * @param ParamPackage with controller data to be mapped + */ + void SetMouseButtonParam(std::size_t index, Common::ParamPackage param); + /// Returns the latest status of button input from the keyboard with parameters KeyboardValues GetKeyboardValues() const; + + /// Returns the latest status of button input from the keyboard modifiers with parameters KeyboardModifierValues GetKeyboardModdifierValues() const; + + /// Returns the latest status of button input from the mouse with parameters MouseButtonValues GetMouseButtonsValues() const; + /// Returns the latest status of button input from the keyboard KeyboardKey GetKeyboard() const; + + /// Returns the latest status of button input from the keyboard modifiers KeyboardModifier GetKeyboardModifier() const; + + /// Returns the latest status of button input from the mouse MouseButton GetMouseButtons() const; + + /// Returns the latest mouse coordinates MousePosition GetMousePosition() const; + /** + * Adds a callback to the list of events + * @param ConsoleUpdateCallback that will be triggered + * @return an unique key corresponding to the callback index in the list + */ int SetCallback(InterfaceUpdateCallback update_callback); + + /** + * Removes a callback from the list stopping any future events to this object + * @param Key corresponding to the callback index in the list + */ void DeleteCallback(int key); private: /** - * Sets the status of a button. Applies toggle properties to the output. - * - * @param A CallbackStatus and a button index number + * Updates the touch status of the console + * @param callback: A CallbackStatus containing the key status + * @param index: key ID to be updated */ void SetKeyboardButton(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the touch status of the console + * @param callback: A CallbackStatus containing the modifier key status + * @param index: modifier key ID to be updated + */ void SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the touch status of the console + * @param callback: A CallbackStatus containing the button status + * @param index: Button ID of the to be updated + */ void SetMouseButton(Input::CallbackStatus callback, std::size_t index); /** - * Triggers a callback that something has changed - * - * @param Input type of the trigger + * Triggers a callback that something has changed on the device status + * @param Input type of the event to trigger */ void TriggerOnChange(DeviceTriggerType type); @@ -131,6 +181,8 @@ private: mutable std::mutex mutex; std::unordered_map callback_list; int last_callback_key = 0; + + // Stores the current status of all external device input DeviceStatus device_status; }; From 4d308fd0b4fc8f14754c47811e751bf068b330b8 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 18 Oct 2021 23:15:46 -0500 Subject: [PATCH 086/291] hid: Fix controller connection/disconnection --- src/core/hid/emulated_console.cpp | 1 - src/core/hid/emulated_controller.cpp | 98 +++++++++++++++---- src/core/hid/emulated_controller.h | 18 +++- src/core/hid/hid_types.h | 8 +- .../hid/controllers/controller_base.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 77 ++++++++++----- src/core/hle/service/hid/controllers/npad.h | 3 + src/yuzu/configuration/configure_input.cpp | 1 + .../configuration/configure_input_player.cpp | 81 +++++++++++++-- .../configure_input_player_widget.cpp | 2 +- 10 files changed, 226 insertions(+), 65 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index c65d05041..7f7c8fd59 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -53,7 +53,6 @@ void EmulatedConsole::ReloadInput() { touch_button_params.Set("x", x); touch_button_params.Set("y", y); touch_button_params.Set("touch_id", static_cast(index)); - LOG_ERROR(Common, "{} ", touch_button_params.Serialize()); touch_devices[index] = Input::CreateDeviceFromString(touch_button_params.Serialize()); if (!touch_devices[index]) { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index b04ab4cd8..7ef6ef118 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -54,6 +54,7 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type } void EmulatedController::ReloadFromSettings() { + //LOG_ERROR(Service_HID, "reload config from settings {}", NpadIdTypeToIndex(npad_id_type)); const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; @@ -91,6 +92,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { + //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto left_side = button_params[Settings::NativeButton::ZL]; @@ -187,11 +189,29 @@ void EmulatedController::UnloadInput() { void EmulatedController::EnableConfiguration() { is_configuring = true; - SaveCurrentConfig(); + temporary_is_connected = is_connected; + temporary_npad_type = npad_type; } void EmulatedController::DisableConfiguration() { is_configuring = false; + + // Apply temporary npad type to the real controller + if (temporary_npad_type != npad_type) { + if (is_connected) { + Disconnect(); + } + SetNpadType(temporary_npad_type); + } + + // Apply temporary connected status to the real controller + if (temporary_is_connected != is_connected) { + if (temporary_is_connected) { + Connect(); + return; + } + Disconnect(); + } } bool EmulatedController::IsConfiguring() const { @@ -199,10 +219,6 @@ bool EmulatedController::IsConfiguring() const { } void EmulatedController::SaveCurrentConfig() { - if (!is_configuring) { - return; - } - const auto player_index = NpadIdTypeToIndex(npad_id_type); auto& player = Settings::values.players.GetValue()[player_index]; player.connected = is_connected; @@ -657,26 +673,47 @@ void EmulatedController::SetLedPattern() { } void EmulatedController::Connect() { - std::lock_guard lock{mutex}; - if (is_connected) { - LOG_WARNING(Service_HID, "Tried to turn on a connected controller {}", npad_id_type); - return; + { + std::lock_guard lock{mutex}; + if (is_configuring) { + temporary_is_connected = true; + TriggerOnChange(ControllerTriggerType::Connected); + return; + } + + if (is_connected) { + return; + } + is_connected = true; } - is_connected = true; + LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Connected); } void EmulatedController::Disconnect() { - std::lock_guard lock{mutex}; - if (!is_connected) { - LOG_WARNING(Service_HID, "Tried to turn off a disconnected controller {}", npad_id_type); - return; + { + std::lock_guard lock{mutex}; + if (is_configuring) { + temporary_is_connected = false; + LOG_ERROR(Service_HID, "Disconnected temporal controller {}", + NpadIdTypeToIndex(npad_id_type)); + TriggerOnChange(ControllerTriggerType::Disconnected); + return; + } + + if (!is_connected) { + return; + } + is_connected = false; } - is_connected = false; + LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Disconnected); } -bool EmulatedController::IsConnected() const { +bool EmulatedController::IsConnected(bool temporary) const { + if (temporary) { + return temporary_is_connected; + } return is_connected; } @@ -688,16 +725,35 @@ NpadIdType EmulatedController::GetNpadIdType() const { return npad_id_type; } -NpadType EmulatedController::GetNpadType() const { +NpadType EmulatedController::GetNpadType(bool temporary) const { + if (temporary) { + return temporary_npad_type; + } return npad_type; } void EmulatedController::SetNpadType(NpadType npad_type_) { - std::lock_guard lock{mutex}; - if (npad_type == npad_type_) { - return; + { + std::lock_guard lock{mutex}; + + if (is_configuring) { + if (temporary_npad_type == npad_type_) { + return; + } + temporary_npad_type = npad_type_; + TriggerOnChange(ControllerTriggerType::Type); + return; + } + + if (npad_type == npad_type_) { + return; + } + if (is_connected) { + LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", + NpadIdTypeToIndex(npad_id_type)); + } + npad_type = npad_type_; } - npad_type = npad_type_; TriggerOnChange(ControllerTriggerType::Type); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 096fe1705..6a6dc1892 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -139,8 +139,12 @@ public: /// Sets the NpadType for this controller void SetNpadType(NpadType npad_type_); - /// Gets the NpadType for this controller - NpadType GetNpadType() const; + /** + * Gets the NpadType for this controller + * @param Returns the temporary value if true + * @return NpadType set on the controller + */ + NpadType GetNpadType(bool temporary = false) const; /// Sets the connected status to true void Connect(); @@ -148,8 +152,12 @@ public: /// Sets the connected status to false void Disconnect(); - /// Returns true if the controller has the connected status - bool IsConnected() const; + /** + * Is the emulated connected + * @param Returns the temporary value if true + * @return true if the controller has the connected status + */ + bool IsConnected(bool temporary = false) const; /// Returns true if vibration is enabled bool IsVibrationEnabled() const; @@ -323,7 +331,9 @@ private: NpadIdType npad_id_type; NpadType npad_type{NpadType::None}; + NpadType temporary_npad_type{NpadType::None}; bool is_connected{false}; + bool temporary_is_connected{false}; bool is_configuring{false}; bool is_vibration_enabled{true}; f32 motion_sensitivity{0.01f}; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index f12a14cb8..539436283 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -47,9 +47,9 @@ constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { return 6; case NpadIdType::Player8: return 7; - case NpadIdType::Other: - return 8; case NpadIdType::Handheld: + return 8; + case NpadIdType::Other: return 9; default: return 0; @@ -76,9 +76,9 @@ constexpr NpadIdType IndexToNpadIdType(size_t index) { case 7: return NpadIdType::Player8; case 8: - return NpadIdType::Other; - case 9: return NpadIdType::Handheld; + case 9: + return NpadIdType::Other; default: return NpadIdType::Invalid; } diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 9d1e6db6a..74a394784 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -11,7 +11,7 @@ ControllerBase::~ControllerBase() = default; void ControllerBase::ActivateController() { if (is_activated) { - OnRelease(); + return; } is_activated = true; OnInit(); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index a2e9ddf4d..144abab65 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -125,18 +125,22 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, return; } + auto& controller = controller_data[controller_idx]; + const auto is_connected = controller.device->IsConnected(); + const auto npad_type = controller.device->GetNpadType(); switch (type) { case Core::HID::ControllerTriggerType::Connected: - InitNewlyAddedController(controller_idx); - break; case Core::HID::ControllerTriggerType::Disconnected: - DisconnectNpadAtIndex(controller_idx); + if (is_connected == controller.is_connected) { + return; + } + UpdateControllerAt(npad_type, controller_idx, is_connected); break; case Core::HID::ControllerTriggerType::Type: { - auto& controller = controller_data[controller_idx]; - if (controller.device->IsConnected()) { - LOG_ERROR(Service_HID, "Controller type changed without turning off the controller"); + if (npad_type == controller.npad_type) { + return; } + // UpdateControllerAt(npad_type, controller_idx, is_connected); break; } default: @@ -146,6 +150,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { auto& controller = controller_data[controller_idx]; + LOG_ERROR(Service_HID, "Connect {} {}", controller_idx, controller.is_connected); const auto controller_type = controller.device->GetNpadType(); auto& shared_memory = controller.shared_memory_entry; if (controller_type == Core::HID::NpadType::None) { @@ -235,20 +240,23 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.battery_level_left = battery_level.left.battery_level; shared_memory.battery_level_right = battery_level.right.battery_level; + controller.is_connected = true; + controller.device->Connect(); SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); + WriteEmptyEntry(controller.shared_memory_entry); } void Controller_NPad::OnInit() { + if (!IsControllerActivated()) { + return; + } + for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; controller.styleset_changed_event = service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } - if (!IsControllerActivated()) { - return; - } - if (system.HIDCore().GetSupportedStyleTag().raw == 0) { // We want to support all controllers Core::HID::NpadStyleTag style{}; @@ -277,20 +285,33 @@ void Controller_NPad::OnInit() { for (auto& controller : controller_data) { NPadGenericState dummy_pad_state{}; auto& npad = controller.shared_memory_entry; - for (std::size_t i = 0; i < 17; ++i) { - dummy_pad_state.sampling_number = - npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); - npad.handheld_lifo.WriteNextEntry(dummy_pad_state); - npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); - npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); - npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); - npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); - npad.palma_lifo.WriteNextEntry(dummy_pad_state); + for (std::size_t i = 0; i < 19; ++i) { + WriteEmptyEntry(npad); } } } +void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { + NPadGenericState dummy_pad_state{}; + NpadGcTriggerState dummy_gc_state{}; + dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; + npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; + npad.handheld_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; + npad.palma_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; + npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); + dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; + npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); +} + void Controller_NPad::OnRelease() { for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; @@ -359,6 +380,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (!IsControllerActivated()) { return; } + for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; auto& npad = controller.shared_memory_entry; @@ -366,6 +388,9 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* const auto& controller_type = controller.device->GetNpadType(); if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { + // Refresh shared memory + std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), + &controller.shared_memory_entry, sizeof(NpadInternalState)); continue; } const u32 npad_index = static_cast(i); @@ -830,14 +855,14 @@ void Controller_NPad::AddNewControllerAt(Core::HID::NpadType controller, std::si void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index, bool connected) { - auto& controller = controller_data[npad_index].device; + auto& controller = controller_data[npad_index]; if (!connected) { DisconnectNpadAtIndex(npad_index); return; } - controller->SetNpadType(type); - controller->Connect(); + controller.device->SetNpadType(type); + controller.device->Connect(); InitNewlyAddedController(npad_index); } @@ -847,14 +872,13 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) { void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { auto& controller = controller_data[npad_index]; + LOG_ERROR(Service_HID, "Disconnect {} {}", npad_index, controller.is_connected); for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { // Send an empty vibration to stop any vibrations. VibrateControllerAtIndex(npad_index, device_idx, {}); controller.vibration[device_idx].device_mounted = false; } - controller.device->Disconnect(); - auto& shared_memory_entry = controller.shared_memory_entry; shared_memory_entry.style_set.raw = 0; // Zero out shared_memory_entry.device_type.raw = 0; @@ -868,7 +892,10 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory_entry.footer_type = AppletFooterUiType::None; + controller.is_connected = false; + controller.device->Disconnect(); SignalStyleSetChangedEvent(IndexToNPad(npad_index)); + WriteEmptyEntry(controller.shared_memory_entry); } void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index b0e2f8430..d805ccb97 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -417,6 +417,8 @@ private: std::array vibration{}; bool unintended_home_button_input_protection{}; + bool is_connected{}; + Core::HID::NpadType npad_type{Core::HID::NpadType::None}; // Current pad state NPadGenericState npad_pad_state{}; @@ -435,6 +437,7 @@ private: void InitNewlyAddedController(std::size_t controller_idx); bool IsControllerSupported(Core::HID::NpadType controller) const; void RequestPadStateUpdate(u32 npad_id); + void WriteEmptyEntry(NpadInternalState& npad); std::atomic press_state{}; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index a8611f77f..67faa8be8 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -114,6 +114,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Co player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); player_tabs[i]->layout()->addWidget(player_controllers[i]); connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) { + // Ensures that the controllers are always connected in sequential order if (is_connected) { for (std::size_t index = 0; index <= i; ++index) { player_connected[index]->setChecked(is_connected); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index ed9c3facf..81310a5b3 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -143,8 +143,26 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i timeout_timer(std::make_unique()), poll_timer(std::make_unique()), bottom_row(bottom_row), system{system_} { - emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index); - emulated_controller->EnableConfiguration(); + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + emulated_controller_p1->SaveCurrentConfig(); + emulated_controller_p1->EnableConfiguration(); + emulated_controller_hanheld->SaveCurrentConfig(); + emulated_controller_hanheld->EnableConfiguration(); + if (emulated_controller_hanheld->IsConnected(true)) { + emulated_controller_p1->Disconnect(); + emulated_controller = emulated_controller_hanheld; + } else { + emulated_controller = emulated_controller_p1; + } + } else { + emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index); + emulated_controller->SaveCurrentConfig(); + emulated_controller->EnableConfiguration(); + } ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); @@ -460,13 +478,36 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int) { + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this, player_index](int) { UpdateControllerAvailableButtons(); UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - emulated_controller->SetNpadType( - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); + const Core::HID::NpadType type = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + bool is_connected = emulated_controller->IsConnected(true); + + emulated_controller_p1->SetNpadType(type); + emulated_controller_hanheld->SetNpadType(type); + if (is_connected) { + if (type == Core::HID::NpadType::Handheld) { + emulated_controller_p1->Disconnect(); + emulated_controller_hanheld->Connect(); + emulated_controller = emulated_controller_hanheld; + } else { + emulated_controller_hanheld->Disconnect(); + emulated_controller_p1->Connect(); + emulated_controller = emulated_controller_p1; + } + } + ui->controllerFrame->SetController(emulated_controller); + } + emulated_controller->SetNpadType(type); }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, @@ -504,11 +545,35 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } ConfigureInputPlayer::~ConfigureInputPlayer() { - emulated_controller->DisableConfiguration(); + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + emulated_controller_p1->DisableConfiguration(); + emulated_controller_hanheld->DisableConfiguration(); + } else { + emulated_controller->DisableConfiguration(); + } }; void ConfigureInputPlayer::ApplyConfiguration() { + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + emulated_controller_p1->DisableConfiguration(); + emulated_controller_p1->SaveCurrentConfig(); + emulated_controller_p1->EnableConfiguration(); + emulated_controller_hanheld->DisableConfiguration(); + emulated_controller_hanheld->SaveCurrentConfig(); + emulated_controller_hanheld->EnableConfiguration(); + return; + } + emulated_controller->DisableConfiguration(); emulated_controller->SaveCurrentConfig(); + emulated_controller->EnableConfiguration(); } void ConfigureInputPlayer::showEvent(QShowEvent* event) { @@ -535,9 +600,9 @@ void ConfigureInputPlayer::RetranslateUI() { void ConfigureInputPlayer::LoadConfiguration() { UpdateUI(); UpdateInputDeviceCombobox(); - const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType()); + const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType(true)); ui->comboControllerType->setCurrentIndex(comboBoxIndex); - ui->groupConnectedController->setChecked(emulated_controller->IsConnected()); + ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); } void ConfigureInputPlayer::ConnectPlayer(bool connected) { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 446b72e55..3b79b6076 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -145,7 +145,7 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ needs_redraw = true; break; case Core::HID::ControllerTriggerType::Type: - controller_type = controller->GetNpadType(); + controller_type = controller->GetNpadType(true); needs_redraw = true; break; case Core::HID::ControllerTriggerType::Color: From 601ac43495904f3f7666d79a800a8b4eda5a8461 Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 19 Oct 2021 00:12:24 -0500 Subject: [PATCH 087/291] core/hid: Only signal when needed --- src/common/input.h | 1 + src/core/hid/emulated_controller.cpp | 263 +++++++++--------- src/core/hid/emulated_controller.h | 6 +- src/core/hid/input_converter.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 6 +- src/input_common/drivers/gc_adapter.cpp | 75 ++++- src/input_common/drivers/gc_adapter.h | 6 +- src/input_common/drivers/keyboard.cpp | 2 +- src/input_common/drivers/sdl_driver.cpp | 22 +- src/input_common/drivers/tas_input.cpp | 2 +- .../configure_input_player_widget.cpp | 12 +- 11 files changed, 242 insertions(+), 155 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 3a28b77a7..8871a9d07 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -30,6 +30,7 @@ enum class InputType { }; enum class BatteryLevel { + None, Empty, Critical, Low, diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7ef6ef118..e102c9437 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -94,7 +94,6 @@ void EmulatedController::ReloadFromSettings() { void EmulatedController::ReloadInput() { //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function - const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -337,120 +336,130 @@ void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t i if (index >= controller.button_values.size()) { return; } - std::lock_guard lock{mutex}; - bool value_changed = false; - const auto new_status = TransformToButton(callback); - auto& current_status = controller.button_values[index]; - current_status.toggle = new_status.toggle; + { + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = controller.button_values[index]; + current_status.toggle = new_status.toggle; - // Update button status with current - if (!current_status.toggle) { - current_status.locked = false; - if (current_status.value != new_status.value) { - current_status.value = new_status.value; - value_changed = true; - } - } else { - // Toggle button and lock status - if (new_status.value && !current_status.locked) { - current_status.locked = true; - current_status.value = !current_status.value; - value_changed = true; - } - - // Unlock button ready for next press - if (!new_status.value && current_status.locked) { + // Update button status with current + if (!current_status.toggle) { current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } + } + + if (!value_changed) { + return; + } + + if (is_configuring) { + controller.npad_button_state.raw = NpadButton::None; + controller.debug_pad_button_state.raw = 0; + TriggerOnChange(ControllerTriggerType::Button, false); + return; + } + + switch (index) { + case Settings::NativeButton::A: + controller.npad_button_state.a.Assign(current_status.value); + controller.debug_pad_button_state.a.Assign(current_status.value); + break; + case Settings::NativeButton::B: + controller.npad_button_state.b.Assign(current_status.value); + controller.debug_pad_button_state.b.Assign(current_status.value); + break; + case Settings::NativeButton::X: + controller.npad_button_state.x.Assign(current_status.value); + controller.debug_pad_button_state.x.Assign(current_status.value); + break; + case Settings::NativeButton::Y: + controller.npad_button_state.y.Assign(current_status.value); + controller.debug_pad_button_state.y.Assign(current_status.value); + break; + case Settings::NativeButton::LStick: + controller.npad_button_state.stick_l.Assign(current_status.value); + break; + case Settings::NativeButton::RStick: + controller.npad_button_state.stick_r.Assign(current_status.value); + break; + case Settings::NativeButton::L: + controller.npad_button_state.l.Assign(current_status.value); + controller.debug_pad_button_state.l.Assign(current_status.value); + break; + case Settings::NativeButton::R: + controller.npad_button_state.r.Assign(current_status.value); + controller.debug_pad_button_state.r.Assign(current_status.value); + break; + case Settings::NativeButton::ZL: + controller.npad_button_state.zl.Assign(current_status.value); + controller.debug_pad_button_state.zl.Assign(current_status.value); + break; + case Settings::NativeButton::ZR: + controller.npad_button_state.zr.Assign(current_status.value); + controller.debug_pad_button_state.zr.Assign(current_status.value); + break; + case Settings::NativeButton::Plus: + controller.npad_button_state.plus.Assign(current_status.value); + controller.debug_pad_button_state.plus.Assign(current_status.value); + break; + case Settings::NativeButton::Minus: + controller.npad_button_state.minus.Assign(current_status.value); + controller.debug_pad_button_state.minus.Assign(current_status.value); + break; + case Settings::NativeButton::DLeft: + controller.npad_button_state.left.Assign(current_status.value); + controller.debug_pad_button_state.d_left.Assign(current_status.value); + break; + case Settings::NativeButton::DUp: + controller.npad_button_state.up.Assign(current_status.value); + controller.debug_pad_button_state.d_up.Assign(current_status.value); + break; + case Settings::NativeButton::DRight: + controller.npad_button_state.right.Assign(current_status.value); + controller.debug_pad_button_state.d_right.Assign(current_status.value); + break; + case Settings::NativeButton::DDown: + 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: + controller.npad_button_state.left_sl.Assign(current_status.value); + controller.npad_button_state.right_sl.Assign(current_status.value); + break; + case Settings::NativeButton::SR: + controller.npad_button_state.left_sr.Assign(current_status.value); + controller.npad_button_state.right_sr.Assign(current_status.value); + break; + case Settings::NativeButton::Home: + case Settings::NativeButton::Screenshot: + break; } } - - if (!value_changed) { - return; + if (!is_connected) { + if (npad_id_type == NpadIdType::Player1 && npad_type != NpadType::Handheld) { + Connect(); + } + if (npad_id_type == NpadIdType::Handheld && npad_type == NpadType::Handheld) { + Connect(); + } } - - if (is_configuring) { - controller.npad_button_state.raw = NpadButton::None; - controller.debug_pad_button_state.raw = 0; - TriggerOnChange(ControllerTriggerType::Button); - return; - } - - switch (index) { - case Settings::NativeButton::A: - controller.npad_button_state.a.Assign(current_status.value); - controller.debug_pad_button_state.a.Assign(current_status.value); - break; - case Settings::NativeButton::B: - controller.npad_button_state.b.Assign(current_status.value); - controller.debug_pad_button_state.b.Assign(current_status.value); - break; - case Settings::NativeButton::X: - controller.npad_button_state.x.Assign(current_status.value); - controller.debug_pad_button_state.x.Assign(current_status.value); - break; - case Settings::NativeButton::Y: - controller.npad_button_state.y.Assign(current_status.value); - controller.debug_pad_button_state.y.Assign(current_status.value); - break; - case Settings::NativeButton::LStick: - controller.npad_button_state.stick_l.Assign(current_status.value); - break; - case Settings::NativeButton::RStick: - controller.npad_button_state.stick_r.Assign(current_status.value); - break; - case Settings::NativeButton::L: - controller.npad_button_state.l.Assign(current_status.value); - controller.debug_pad_button_state.l.Assign(current_status.value); - break; - case Settings::NativeButton::R: - controller.npad_button_state.r.Assign(current_status.value); - controller.debug_pad_button_state.r.Assign(current_status.value); - break; - case Settings::NativeButton::ZL: - controller.npad_button_state.zl.Assign(current_status.value); - controller.debug_pad_button_state.zl.Assign(current_status.value); - break; - case Settings::NativeButton::ZR: - controller.npad_button_state.zr.Assign(current_status.value); - controller.debug_pad_button_state.zr.Assign(current_status.value); - break; - case Settings::NativeButton::Plus: - controller.npad_button_state.plus.Assign(current_status.value); - controller.debug_pad_button_state.plus.Assign(current_status.value); - break; - case Settings::NativeButton::Minus: - controller.npad_button_state.minus.Assign(current_status.value); - controller.debug_pad_button_state.minus.Assign(current_status.value); - break; - case Settings::NativeButton::DLeft: - controller.npad_button_state.left.Assign(current_status.value); - controller.debug_pad_button_state.d_left.Assign(current_status.value); - break; - case Settings::NativeButton::DUp: - controller.npad_button_state.up.Assign(current_status.value); - controller.debug_pad_button_state.d_up.Assign(current_status.value); - break; - case Settings::NativeButton::DRight: - controller.npad_button_state.right.Assign(current_status.value); - controller.debug_pad_button_state.d_right.Assign(current_status.value); - break; - case Settings::NativeButton::DDown: - 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: - controller.npad_button_state.left_sl.Assign(current_status.value); - controller.npad_button_state.right_sl.Assign(current_status.value); - break; - case Settings::NativeButton::SR: - controller.npad_button_state.left_sr.Assign(current_status.value); - controller.npad_button_state.right_sr.Assign(current_status.value); - break; - case Settings::NativeButton::Home: - case Settings::NativeButton::Screenshot: - break; - } - TriggerOnChange(ControllerTriggerType::Button); + TriggerOnChange(ControllerTriggerType::Button, true); } void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) { @@ -463,7 +472,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in if (is_configuring) { controller.analog_stick_state.left = {}; controller.analog_stick_state.right = {}; - TriggerOnChange(ControllerTriggerType::Stick); + TriggerOnChange(ControllerTriggerType::Stick, false); return; } @@ -489,7 +498,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in break; } - TriggerOnChange(ControllerTriggerType::Stick); + TriggerOnChange(ControllerTriggerType::Stick, true); } void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) { @@ -502,7 +511,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t if (is_configuring) { controller.gc_trigger_state.left = 0; controller.gc_trigger_state.right = 0; - TriggerOnChange(ControllerTriggerType::Trigger); + TriggerOnChange(ControllerTriggerType::Trigger, false); return; } @@ -520,7 +529,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t break; } - TriggerOnChange(ControllerTriggerType::Trigger); + TriggerOnChange(ControllerTriggerType::Trigger, true); } void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) { @@ -546,7 +555,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i emulated.UpdateOrientation(raw_status.delta_timestamp); if (is_configuring) { - TriggerOnChange(ControllerTriggerType::Motion); + TriggerOnChange(ControllerTriggerType::Motion, false); return; } @@ -557,7 +566,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i motion.orientation = emulated.GetOrientation(); motion.is_at_rest = emulated.IsMoving(motion_sensitivity); - TriggerOnChange(ControllerTriggerType::Motion); + TriggerOnChange(ControllerTriggerType::Motion, true); } void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) { @@ -568,7 +577,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t controller.battery_values[index] = TransformToBattery(callback); if (is_configuring) { - TriggerOnChange(ControllerTriggerType::Battery); + TriggerOnChange(ControllerTriggerType::Battery, false); return; } @@ -593,6 +602,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t case Input::BatteryLevel::Empty: battery_level = 0; break; + case Input::BatteryLevel::None: case Input::BatteryLevel::Full: default: is_powered = true; @@ -623,7 +633,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t }; break; } - TriggerOnChange(ControllerTriggerType::Battery); + TriggerOnChange(ControllerTriggerType::Battery, true); } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { @@ -677,7 +687,7 @@ void EmulatedController::Connect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = true; - TriggerOnChange(ControllerTriggerType::Connected); + TriggerOnChange(ControllerTriggerType::Connected,false); return; } @@ -687,7 +697,7 @@ void EmulatedController::Connect() { is_connected = true; } LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Connected); + TriggerOnChange(ControllerTriggerType::Connected,true); } void EmulatedController::Disconnect() { @@ -697,7 +707,7 @@ void EmulatedController::Disconnect() { temporary_is_connected = false; LOG_ERROR(Service_HID, "Disconnected temporal controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected); + TriggerOnChange(ControllerTriggerType::Disconnected,false); return; } @@ -707,7 +717,7 @@ void EmulatedController::Disconnect() { is_connected = false; } LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected); + TriggerOnChange(ControllerTriggerType::Disconnected,true); } bool EmulatedController::IsConnected(bool temporary) const { @@ -741,7 +751,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { return; } temporary_npad_type = npad_type_; - TriggerOnChange(ControllerTriggerType::Type); + TriggerOnChange(ControllerTriggerType::Type,false); return; } @@ -754,7 +764,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { } npad_type = npad_type_; } - TriggerOnChange(ControllerTriggerType::Type); + TriggerOnChange(ControllerTriggerType::Type,true); } LedPattern EmulatedController::GetLedPattern() const { @@ -844,9 +854,12 @@ BatteryLevelState EmulatedController::GetBattery() const { return controller.battery_state; } -void EmulatedController::TriggerOnChange(ControllerTriggerType type) { +void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_service_update) { for (const std::pair poller_pair : callback_list) { const ControllerUpdateCallback& poller = poller_pair.second; + if (!is_service_update && poller.is_service) { + continue; + } if (poller.on_change) { poller.on_change(type); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 6a6dc1892..3a0b20cf8 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -113,6 +113,7 @@ enum class ControllerTriggerType { struct ControllerUpdateCallback { std::function on_change; + bool is_service; }; class EmulatedController { @@ -325,9 +326,10 @@ private: /** * Triggers a callback that something has changed on the controller status - * @param Input type of the event to trigger + * @param type: Input type of the event to trigger + * @param is_service_update: indicates if this event should be sended to only services */ - void TriggerOnChange(ControllerTriggerType type); + void TriggerOnChange(ControllerTriggerType type, bool is_service_update); NpadIdType npad_id_type; NpadType npad_type{NpadType::None}; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5834622e9..128a48ec9 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -10,7 +10,7 @@ namespace Core::HID { Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { - Input::BatteryStatus battery{}; + Input::BatteryStatus battery{Input::BatteryStatus::None}; switch (callback.type) { case Input::InputType::Analog: case Input::InputType::Trigger: { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 144abab65..6b9d6d11c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -104,7 +104,10 @@ Controller_NPad::Controller_NPad(Core::System& system_, controller.vibration[0].latest_vibration_value = DEFAULT_VIBRATION_VALUE; controller.vibration[1].latest_vibration_value = DEFAULT_VIBRATION_VALUE; Core::HID::ControllerUpdateCallback engine_callback{ - [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }}; + .on_change = [this, + i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, + .is_service = true, + }; controller.callback_key = controller.device->SetCallback(engine_callback); } } @@ -283,7 +286,6 @@ void Controller_NPad::OnInit() { // Prefill controller buffers for (auto& controller : controller_data) { - NPadGenericState dummy_pad_state{}; auto& npad = controller.shared_memory_entry; for (std::size_t i = 0; i < 19; ++i) { WriteEmptyEntry(npad); diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 4a56abb99..4fb6ab5af 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -150,7 +150,10 @@ void GCAdapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { return; } // Device changed reset device and set new type - pads[port] = {}; + pads[port].axis_origin = {}; + pads[port].reset_origin_counter = {}; + pads[port].enable_vibration = {}; + pads[port].rumble_amplitude = {}; pads[port].type = pad_type; } @@ -396,12 +399,11 @@ std::vector GCAdapter::GetInputDevices() const { if (!DeviceConnected(port)) { continue; } - const std::string name = fmt::format("Gamecube Controller {}", port + 1); - devices.emplace_back(Common::ParamPackage{ - {"engine", "gcpad"}, - {"display", std::move(name)}, - {"port", std::to_string(port)}, - }); + Common::ParamPackage identifier{}; + identifier.Set("engine", GetEngineName()); + identifier.Set("display", fmt::format("Gamecube Controller {}", port + 1)); + identifier.Set("port", static_cast(port)); + devices.emplace_back(identifier); } return devices; } @@ -431,7 +433,8 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p ButtonMapping mapping{}; for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); button_params.Set("port", params.Get("port", 0)); button_params.Set("button", static_cast(gcadapter_button)); mapping.insert_or_assign(switch_button, std::move(button_params)); @@ -444,7 +447,8 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, }; for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); button_params.Set("port", params.Get("port", 0)); button_params.Set("button", static_cast(gcadapter_buton)); button_params.Set("axis", static_cast(gcadapter_axis)); @@ -463,13 +467,13 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p AnalogMapping mapping = {}; Common::ParamPackage left_analog_params; - left_analog_params.Set("engine", "gcpad"); + left_analog_params.Set("engine", GetEngineName()); left_analog_params.Set("port", params.Get("port", 0)); left_analog_params.Set("axis_x", static_cast(PadAxes::StickX)); left_analog_params.Set("axis_y", static_cast(PadAxes::StickY)); mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); Common::ParamPackage right_analog_params; - right_analog_params.Set("engine", "gcpad"); + right_analog_params.Set("engine", GetEngineName()); right_analog_params.Set("port", params.Get("port", 0)); right_analog_params.Set("axis_x", static_cast(PadAxes::SubstickX)); right_analog_params.Set("axis_y", static_cast(PadAxes::SubstickY)); @@ -477,9 +481,56 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p return mapping; } +std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { + PadButton button = static_cast(params.Get("button", 0)); + switch (button) { + case PadButton::ButtonLeft: + return "left"; + break; + case PadButton::ButtonRight: + return "right"; + break; + case PadButton::ButtonDown: + return "down"; + break; + case PadButton::ButtonUp: + return "up"; + break; + case PadButton::TriggerZ: + return "Z"; + break; + case PadButton::TriggerR: + return "R"; + break; + case PadButton::TriggerL: + return "L"; + break; + case PadButton::ButtonA: + return "A"; + break; + case PadButton::ButtonB: + return "B"; + break; + case PadButton::ButtonX: + return "X"; + break; + case PadButton::ButtonY: + return "Y"; + break; + case PadButton::ButtonStart: + return "start"; + break; + default: + return "Unkown GC"; + } +} + std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Button {}", params.Get("button", 0)); + return fmt::format("Button {}", GetUIButtonName(params)); + } + if (params.Has("axis")) { + return fmt::format("Axis {}", params.Get("axis",0)); } return "Bad GC Adapter"; diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index dd0e4aa1d..b82e4803d 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -105,8 +105,12 @@ private: void Reset(); void UpdateVibrations(); - // Updates vibration state of all controllers + + /// Updates vibration state of all controllers void SendVibrations(); + + std::string GetUIButtonName(const Common::ParamPackage& params) const; + std::unique_ptr usb_adapter_handle; std::array pads; diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index b00a4b8d9..85a781a30 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -26,7 +26,7 @@ void Keyboard::ReleaseAllKeys() { std::vector Keyboard::GetInputDevices() const { std::vector devices; devices.emplace_back(Common::ParamPackage{ - {"engine", "keyboard"}, + {"engine", GetEngineName()}, {"display", "Keyboard Only"}, }); return devices; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index f7f03c5f2..cee2d965f 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -305,6 +305,7 @@ void SDLDriver::InitJoystick(int joystick_index) { if (joystick_map.find(guid) == joystick_map.end()) { auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); + SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick_map[guid].emplace_back(std::move(joystick)); return; } @@ -322,6 +323,7 @@ void SDLDriver::InitJoystick(int joystick_index) { const int port = static_cast(joystick_guid_list.size()); auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); + SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick_guid_list.emplace_back(std::move(joystick)); } @@ -472,7 +474,7 @@ std::vector SDLDriver::GetInputDevices() const { const std::string name = fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); devices.emplace_back(Common::ParamPackage{ - {"engine", "sdl"}, + {"engine", GetEngineName()}, {"display", std::move(name)}, {"guid", joystick->GetGUID()}, {"port", std::to_string(joystick->GetPort())}, @@ -495,7 +497,7 @@ std::vector SDLDriver::GetInputDevices() const { const std::string name = fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); devices.emplace_back(Common::ParamPackage{ - {"engine", "sdl"}, + {"engine", GetEngineName()}, {"display", std::move(name)}, {"guid", joystick->GetGUID()}, {"guid2", joystick2->GetGUID()}, @@ -527,7 +529,8 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { - Common::ParamPackage params({{"engine", "sdl"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("axis", axis); @@ -538,7 +541,8 @@ Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std:: Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, s32 button) const { - Common::ParamPackage params({{"engine", "sdl"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("button", button); @@ -547,8 +551,8 @@ Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std:: Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, u8 value) const { - Common::ParamPackage params({{"engine", "sdl"}}); - + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("hat", hat); @@ -557,7 +561,9 @@ Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::str } Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { - Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); + params.Set("motion", 0); params.Set("port", port); params.Set("guid", std::move(guid)); return params; @@ -583,7 +589,7 @@ Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identif int axis_y, float offset_x, float offset_y) const { Common::ParamPackage params; - params.Set("engine", "sdl"); + params.Set("engine", GetEngineName()); params.Set("port", static_cast(identifier.port)); params.Set("guid", identifier.guid.Format()); params.Set("axis_x", axis_x); diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 5e2101b27..7e7a1d58f 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -127,7 +127,7 @@ void Tas::WriteTasFile(std::u8string file_name) { std::string output_text; for (size_t frame = 0; frame < record_commands.size(); frame++) { const TASCommand& line = record_commands[frame]; - output_text += fmt::format("{} {} {} {} {}\n", frame, WriteCommandButtons(line.buttons), + output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); } const auto bytes_written = Common::FS::WriteStringToFile( diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 3b79b6076..93f7eddc9 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -27,7 +27,9 @@ void PlayerControlPreview::SetController(Core::HID::EmulatedController* controll is_controller_set = true; controller = controller_; Core::HID::ControllerUpdateCallback engine_callback{ - [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }}; + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, + .is_service = false, + }; callback_key = controller->SetCallback(engine_callback); ControllerUpdate(Core::HID::ControllerTriggerType::All); } @@ -810,7 +812,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); // Draw battery - DrawBattery(p, center + QPoint(-30, -165), battery_values[0]); + DrawBattery(p, center + QPoint(-30, -160), battery_values[0]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { @@ -2655,6 +2657,9 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery) { + if (battery == Input::BatteryLevel::None) { + return; + } p.setPen(colors.outline); p.setBrush(colors.transparent); p.drawRect(center.x(), center.y(), 56, 20); @@ -2669,6 +2674,7 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte p.drawRect(center.x() + 42, center.y(), 14, 20); p.drawRect(center.x() + 28, center.y(), 14, 20); p.drawRect(center.x() + 14, center.y(), 14, 20); + p.drawRect(center.x(), center.y(), 14, 20); break; case Input::BatteryLevel::Medium: p.drawRect(center.x() + 28, center.y(), 14, 20); @@ -2685,6 +2691,8 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte case Input::BatteryLevel::Empty: p.drawRect(center.x(), center.y(), 5, 20); break; + default: + break; } } From c3ff0a8ac0d1c3f9c0791b5263dae53c06ad6048 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 20 Oct 2021 14:41:56 -0500 Subject: [PATCH 088/291] core/hid: Fix rumble too strong at 1% --- src/common/input.h | 7 +++++ src/core/hid/emulated_controller.cpp | 34 ++++++++++++++++--------- src/input_common/drivers/sdl_driver.cpp | 20 ++++++++++++++- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 8871a9d07..cdacd4689 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -60,6 +60,12 @@ enum class PollingError { Unknown, }; +// Hint for amplification curve to be used +enum class VibrationAmplificationType { + Linear, + Exponential, +}; + struct AnalogProperties { float deadzone{}; float range{1.0f}; @@ -126,6 +132,7 @@ struct VibrationStatus { f32 low_frequency{}; f32 high_amplitude{}; f32 high_frequency{}; + VibrationAmplificationType type; }; struct LedStatus { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index e102c9437..7b0c4a49b 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -54,7 +54,6 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type } void EmulatedController::ReloadFromSettings() { - //LOG_ERROR(Service_HID, "reload config from settings {}", NpadIdTypeToIndex(npad_id_type)); const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; @@ -92,7 +91,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { - //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); + // LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -640,12 +639,22 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v if (!output_devices[device_index]) { return false; } + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + const f32 strength = static_cast(player.vibration_strength) / 100.0f; + + // Exponential amplification is too strong at low amplitudes. Switch to a linear + // amplification if strength is set below 0.7f + const Input::VibrationAmplificationType type = + strength > 0.7f ? Input::VibrationAmplificationType::Exponential + : Input::VibrationAmplificationType::Linear; const Input::VibrationStatus status = { - .low_amplitude = vibration.high_amplitude, - .low_frequency = vibration.high_amplitude, - .high_amplitude = vibration.high_amplitude, - .high_frequency = vibration.high_amplitude, + .low_amplitude = std::min(vibration.low_amplitude * strength, 1.0f), + .low_frequency = vibration.low_frequency, + .high_amplitude = std::min(vibration.high_amplitude * strength, 1.0f), + .high_frequency = vibration.high_frequency, + .type = type, }; return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } @@ -661,6 +670,7 @@ bool EmulatedController::TestVibration(std::size_t device_index) { .low_frequency = 160.0f, .high_amplitude = 0.001f, .high_frequency = 320.0f, + .type = Input::VibrationAmplificationType::Linear, }; return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } @@ -687,7 +697,7 @@ void EmulatedController::Connect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = true; - TriggerOnChange(ControllerTriggerType::Connected,false); + TriggerOnChange(ControllerTriggerType::Connected, false); return; } @@ -697,7 +707,7 @@ void EmulatedController::Connect() { is_connected = true; } LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Connected,true); + TriggerOnChange(ControllerTriggerType::Connected, true); } void EmulatedController::Disconnect() { @@ -707,7 +717,7 @@ void EmulatedController::Disconnect() { temporary_is_connected = false; LOG_ERROR(Service_HID, "Disconnected temporal controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected,false); + TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } @@ -717,7 +727,7 @@ void EmulatedController::Disconnect() { is_connected = false; } LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected,true); + TriggerOnChange(ControllerTriggerType::Disconnected, true); } bool EmulatedController::IsConnected(bool temporary) const { @@ -751,7 +761,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { return; } temporary_npad_type = npad_type_; - TriggerOnChange(ControllerTriggerType::Type,false); + TriggerOnChange(ControllerTriggerType::Type, false); return; } @@ -764,7 +774,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { } npad_type = npad_type_; } - TriggerOnChange(ControllerTriggerType::Type,true); + TriggerOnChange(ControllerTriggerType::Type, true); } LedPattern EmulatedController::GetLedPattern() const { diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index cee2d965f..d56351815 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -107,6 +107,14 @@ public: return false; } + + bool HasHDRumble() const { + if (sdl_controller) { + return (SDL_GameControllerGetType(sdl_controller.get()) == + SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO); + } + return false; + } /** * The Pad identifier of the joystick */ @@ -515,16 +523,26 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, const auto process_amplitude = [](f32 amplitude) { return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; }; - const Input::VibrationStatus new_vibration{ + const Input::VibrationStatus exponential_vibration{ .low_amplitude = process_amplitude(vibration.low_amplitude), .low_frequency = vibration.low_frequency, .high_amplitude = process_amplitude(vibration.high_amplitude), .high_frequency = vibration.high_frequency, + .type = Input::VibrationAmplificationType::Exponential, }; + Input::VibrationStatus new_vibration{}; + + if (vibration.type == Input::VibrationAmplificationType::Linear || joystick->HasHDRumble()) { + new_vibration = vibration; + } else { + new_vibration = exponential_vibration; + } + if (!joystick->RumblePlay(new_vibration)) { return Input::VibrationError::Unknown; } + return Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, From af55dd193533be577d0a3d01f93a4a3a2c27cd5d Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 20 Oct 2021 17:53:14 -0500 Subject: [PATCH 089/291] configuration: Migrate controller settings to emulated controller --- src/core/hid/emulated_controller.cpp | 1 - src/core/hid/emulated_controller.h | 2 +- src/core/hid/hid_core.cpp | 21 +++ src/core/hid/hid_core.h | 10 +- .../service/am/applets/applet_controller.cpp | 12 +- src/input_common/main.cpp | 10 ++ src/yuzu/applets/qt_controller.cpp | 143 +++++++----------- src/yuzu/applets/qt_controller.h | 14 +- src/yuzu/applets/qt_software_keyboard.cpp | 21 +-- src/yuzu/configuration/configure_input.cpp | 17 ++- .../configure_input_player_widget.cpp | 4 +- src/yuzu/main.cpp | 11 +- 12 files changed, 140 insertions(+), 126 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7b0c4a49b..662260327 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -91,7 +91,6 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { - // LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 3a0b20cf8..f3ee70726 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -329,7 +329,7 @@ private: * @param type: Input type of the event to trigger * @param is_service_update: indicates if this event should be sended to only services */ - void TriggerOnChange(ControllerTriggerType type, bool is_service_update); + void TriggerOnChange(ControllerTriggerType type, bool is_service_update); NpadIdType npad_id_type; NpadType npad_type{NpadType::None}; diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index ee76db110..bd17081bd 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -111,6 +111,27 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const { return supported_style_tag; } +s8 HIDCore::GetPlayerCount() const { + s8 active_players = 0; + for (std::size_t player_index = 0; player_index < 8; player_index++) { + const auto* controller = GetEmulatedControllerByIndex(player_index); + if (controller->IsConnected()) { + active_players++; + } + } + return active_players; +} + +NpadIdType HIDCore::GetFirstNpadId() const { + for (std::size_t player_index = 0; player_index < 10; player_index++) { + const auto* controller = GetEmulatedControllerByIndex(player_index); + if (controller->IsConnected()) { + return controller->GetNpadIdType(); + } + } + return NpadIdType::Player1; +} + void HIDCore::ReloadInputDevices() { player_1->ReloadFromSettings(); player_2->ReloadFromSettings(); diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index f11f48b61..196466a72 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -35,10 +35,16 @@ public: void SetSupportedStyleTag(NpadStyleTag style_tag); NpadStyleTag GetSupportedStyleTag() const; - // Reloads all input devices from settings + /// Counts the connected players from P1-P8 + s8 GetPlayerCount() const; + + /// Returns the first connected npad id + NpadIdType GetFirstNpadId() const; + + /// Reloads all input devices from settings void ReloadInputDevices(); - // Removes all callbacks from input common + /// Removes all callbacks from input common void UnloadInputDevices(); private: diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index c1b6cd126..658265a00 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -243,19 +243,11 @@ void Controller::Execute() { void Controller::ConfigurationComplete() { ControllerSupportResultInfo result_info{}; - const auto& players = Settings::values.players.GetValue(); - // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. // Otherwise, only count connected players from P1-P8. - result_info.player_count = - is_single_mode - ? 1 - : static_cast(std::count_if(players.begin(), players.end() - 2, - [](const auto& player) { return player.connected; })); + result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount(); - result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance( - players.begin(), std::find_if(players.begin(), players.end(), - [](const auto& player) { return player.connected; }))); + result_info.selected_id = static_cast(system.HIDCore().GetFirstNpadId()); result_info.result = 0; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 7807dd38f..b048783c9 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -32,12 +32,17 @@ struct InputSubsystem::Impl { keyboard = std::make_shared("keyboard"); keyboard->SetMappingCallback(mapping_callback); keyboard_factory = std::make_shared(keyboard); + keyboard_output_factory = std::make_shared(keyboard); Input::RegisterFactory(keyboard->GetEngineName(), keyboard_factory); + Input::RegisterFactory(keyboard->GetEngineName(), + keyboard_output_factory); mouse = std::make_shared("mouse"); mouse->SetMappingCallback(mapping_callback); mouse_factory = std::make_shared(mouse); + mouse_output_factory = std::make_shared(mouse); Input::RegisterFactory(mouse->GetEngineName(), mouse_factory); + Input::RegisterFactory(mouse->GetEngineName(), mouse_output_factory); touch_screen = std::make_shared("touch"); touch_screen_factory = std::make_shared(touch_screen); @@ -61,7 +66,9 @@ struct InputSubsystem::Impl { tas_input = std::make_shared("tas"); tas_input->SetMappingCallback(mapping_callback); tas_input_factory = std::make_shared(tas_input); + tas_output_factory = std::make_shared(tas_input); Input::RegisterFactory(tas_input->GetEngineName(), tas_input_factory); + Input::RegisterFactory(tas_input->GetEngineName(), tas_output_factory); #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); @@ -268,7 +275,10 @@ struct InputSubsystem::Impl { std::shared_ptr udp_client_factory; std::shared_ptr tas_input_factory; + std::shared_ptr keyboard_output_factory; + std::shared_ptr mouse_output_factory; std::shared_ptr gcadapter_output_factory; + std::shared_ptr tas_output_factory; #ifdef HAVE_SDL2 std::shared_ptr sdl; diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 2cd5ed718..32cb5b5ff 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -9,6 +9,8 @@ #include "common/param_package.h" #include "common/string_util.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_types.h" #include "core/hle/lock.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" @@ -26,48 +28,31 @@ namespace { constexpr std::size_t HANDHELD_INDEX = 8; -constexpr std::array, 8> led_patterns{{ - {true, false, false, false}, - {true, true, false, false}, - {true, true, true, false}, - {true, true, true, true}, - {true, false, false, true}, - {true, false, true, false}, - {true, false, true, true}, - {false, true, true, false}, -}}; - -void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, - bool connected, Core::System& system) { - if (!system.IsPoweredOn()) { - return; +void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadType controller_type, bool connected) { + if (controller->IsConnected()) { + controller->Disconnect(); + } + controller->SetNpadType(controller_type); + if (connected) { + controller->Connect(); } - - auto& npad = - system.ServiceManager() - .GetService("hid") - ->GetAppletResource() - ->GetController(Service::HID::HidController::NPad); - - npad.UpdateControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad(controller_type), - npad_index, connected); } // Returns true if the given controller type is compatible with the given parameters. -bool IsControllerCompatible(Settings::ControllerType controller_type, +bool IsControllerCompatible(Core::HID::NpadType controller_type, Core::Frontend::ControllerParameters parameters) { switch (controller_type) { - case Settings::ControllerType::ProController: + case Core::HID::NpadType::ProController: return parameters.allow_pro_controller; - case Settings::ControllerType::DualJoyconDetached: + case Core::HID::NpadType::JoyconDual: return parameters.allow_dual_joycons; - case Settings::ControllerType::LeftJoycon: + case Core::HID::NpadType::JoyconLeft: return parameters.allow_left_joycon; - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: return parameters.allow_right_joycon; - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::Handheld: return parameters.enable_single_mode && parameters.allow_handheld; - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::GameCube: return parameters.allow_gamecube_controller; default: return false; @@ -198,7 +183,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( connect(emulated_controllers[i], qOverload(&QComboBox::currentIndexChanged), [this, i](int index) { UpdateDockedState(GetControllerTypeFromIndex(index, i) == - Settings::ControllerType::Handheld); + Core::HID::NpadType::Handheld); }); } } @@ -251,17 +236,17 @@ void QtControllerSelectorDialog::ApplyConfiguration() { } void QtControllerSelectorDialog::LoadConfiguration() { + const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - const auto connected = - Settings::values.players.GetValue()[index].connected || - (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); + const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); + const auto connected = controller->IsConnected() || (index == 0 && handheld->IsConnected()); player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); - emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( - Settings::values.players.GetValue()[index].controller_type, index)); + emulated_controllers[index]->setCurrentIndex( + GetIndexFromControllerType(controller->GetNpadType(), index)); } - UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); + UpdateDockedState(handheld->IsConnected()); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -417,33 +402,32 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index emulated_controllers[player_index]->clear(); pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::ProController); + Core::HID::NpadType::ProController); emulated_controllers[player_index]->addItem(tr("Pro Controller")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::DualJoyconDetached); + Core::HID::NpadType::JoyconDual); emulated_controllers[player_index]->addItem(tr("Dual Joycons")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::LeftJoycon); + Core::HID::NpadType::JoyconLeft); emulated_controllers[player_index]->addItem(tr("Left Joycon")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::RightJoycon); + Core::HID::NpadType::JoyconRight); emulated_controllers[player_index]->addItem(tr("Right Joycon")); if (player_index == 0) { pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::Handheld); + Core::HID::NpadType::Handheld); emulated_controllers[player_index]->addItem(tr("Handheld")); } - pairs.emplace_back(emulated_controllers[player_index]->count(), - Settings::ControllerType::GameCube); + pairs.emplace_back(emulated_controllers[player_index]->count(), Core::HID::NpadType::GameCube); emulated_controllers[player_index]->addItem(tr("GameCube Controller")); } -Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( +Core::HID::NpadType QtControllerSelectorDialog::GetControllerTypeFromIndex( int index, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -451,13 +435,13 @@ Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( [index](const auto& pair) { return pair.first == index; }); if (it == pairs.end()) { - return Settings::ControllerType::ProController; + return Core::HID::NpadType::ProController; } return it->second; } -int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, +int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadType type, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -481,16 +465,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) const QString stylesheet = [this, player_index] { switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), player_index)) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::GameCube: return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); - case Settings::ControllerType::DualJoyconDetached: + case Core::HID::NpadType::JoyconDual: return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); - case Settings::ControllerType::LeftJoycon: + case Core::HID::NpadType::JoyconLeft: return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::Handheld: return QStringLiteral("image: url(:/controller/applet_handheld%0); "); default: return QString{}; @@ -518,54 +502,42 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) } void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { - auto& player = Settings::values.players.GetValue()[player_index]; + auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); const auto controller_type = GetControllerTypeFromIndex( emulated_controllers[player_index]->currentIndex(), player_index); const auto player_connected = player_groupboxes[player_index]->isChecked() && - controller_type != Settings::ControllerType::Handheld; + controller_type != Core::HID::NpadType::Handheld; - if (player.controller_type == controller_type && player.connected == player_connected) { + if (controller->GetNpadType() == controller_type && + controller->IsConnected() == player_connected) { // Set vibration devices in the event that the input device has changed. ConfigureVibration::SetVibrationDevices(player_index); return; } // Disconnect the controller first. - UpdateController(controller_type, player_index, false, system); - - player.controller_type = controller_type; - player.connected = player_connected; + UpdateController(controller, controller_type, false); ConfigureVibration::SetVibrationDevices(player_index); // Handheld if (player_index == 0) { - auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; - if (controller_type == Settings::ControllerType::Handheld) { - handheld = player; + if (controller_type == Core::HID::NpadType::Handheld) { + auto* handheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + UpdateController(handheld, Core::HID::NpadType::Handheld, + player_groupboxes[player_index]->isChecked()); } - handheld.connected = player_groupboxes[player_index]->isChecked() && - controller_type == Settings::ControllerType::Handheld; - UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system); } - if (!player.connected) { - return; - } - - // This emulates a delay between disconnecting and reconnecting controllers as some games - // do not respond to a change in controller type if it was instantaneous. - using namespace std::chrono_literals; - std::this_thread::sleep_for(60ms); - - UpdateController(controller_type, player_index, player_connected, system); + UpdateController(controller, controller_type, player_connected); } void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { if (!player_groupboxes[player_index]->isChecked() || GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), - player_index) == Settings::ControllerType::Handheld) { + player_index) == Core::HID::NpadType::Handheld) { led_patterns_boxes[player_index][0]->setChecked(false); led_patterns_boxes[player_index][1]->setChecked(false); led_patterns_boxes[player_index][2]->setChecked(false); @@ -573,10 +545,12 @@ void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { return; } - led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]); - led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]); - led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]); - led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]); + const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); + const auto led_pattern = controller->GetLedPattern(); + led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1); + led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2); + led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3); + led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4); } void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) { @@ -656,10 +630,9 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { } for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { + auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); // Disconnect any unsupported players here and disable or hide them if applicable. - Settings::values.players.GetValue()[index].connected = false; - UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false, - system); + UpdateController(controller, controller->GetNpadType(), false); // Hide the player widgets when max_supported_controllers is less than or equal to 4. if (max_supported_players <= 4) { player_widgets[index]->hide(); diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index ca09fde04..dd981f479 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -23,10 +23,6 @@ namespace InputCommon { class InputSubsystem; } -namespace Settings { -enum class ControllerType; -} - namespace Ui { class QtControllerSelectorDialog; } @@ -35,6 +31,10 @@ namespace Core { class System; } +namespace Core::HID { +enum class NpadType : u8; +} + class QtControllerSelectorDialog final : public QDialog { Q_OBJECT @@ -74,10 +74,10 @@ private: void SetEmulatedControllers(std::size_t player_index); // Gets the Controller Type for a given controller combobox index per player. - Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; + Core::HID::NpadType GetControllerTypeFromIndex(int index, std::size_t player_index) const; // Gets the controller combobox index for a given Controller Type per player. - int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; + int GetIndexFromControllerType(Core::HID::NpadType type, std::size_t player_index) const; // Updates the controller icons per player. void UpdateControllerIcon(std::size_t player_index); @@ -139,7 +139,7 @@ private: std::array emulated_controllers; /// Pairs of emulated controller index and Controller Type enum per player. - std::array>, NUM_PLAYERS> + std::array>, NUM_PLAYERS> index_controller_type_pairs; // Labels representing the number of connected controllers diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index 7e8731232..3d91f8034 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -10,6 +10,8 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hid/input_interpreter.h" #include "ui_qt_software_keyboard.h" @@ -796,9 +798,10 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() { } void QtSoftwareKeyboardDialog::SetControllerImage() { - const auto controller_type = Settings::values.players.GetValue()[8].connected - ? Settings::values.players.GetValue()[8].controller_type - : Settings::values.players.GetValue()[0].controller_type; + const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + const auto controller_type = + handheld->IsConnected() ? handheld->GetNpadType() : player_1->GetNpadType(); const QString theme = [] { if (QIcon::themeName().contains(QStringLiteral("dark")) || @@ -810,8 +813,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { }(); switch (controller_type) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::GameCube: + case Core::HID::NpadType::ProController: + case Core::HID::NpadType::GameCube: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -819,7 +822,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); break; - case Settings::ControllerType::DualJoyconDetached: + case Core::HID::NpadType::JoyconDual: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -827,7 +830,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); break; - case Settings::ControllerType::LeftJoycon: + case Core::HID::NpadType::JoyconLeft: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); @@ -838,7 +841,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); break; - case Settings::ControllerType::RightJoycon: + case Core::HID::NpadType::JoyconRight: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); @@ -849,7 +852,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); break; - case Settings::ControllerType::Handheld: + case Core::HID::NpadType::Handheld: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 67faa8be8..dece27fde 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -211,8 +211,10 @@ void ConfigureInput::RetranslateUI() { } void ConfigureInput::LoadConfiguration() { + const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + LoadPlayerControllerIndices(); - UpdateDockedState(Settings::values.players.GetValue()[8].connected); + UpdateDockedState(handheld->IsConnected()); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -220,9 +222,16 @@ void ConfigureInput::LoadConfiguration() { void ConfigureInput::LoadPlayerControllerIndices() { for (std::size_t i = 0; i < player_connected.size(); ++i) { - const auto connected = Settings::values.players.GetValue()[i].connected || - (i == 0 && Settings::values.players.GetValue()[8].connected); - player_connected[i]->setChecked(connected); + if (i == 0) { + auto* handheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + if (handheld->IsConnected()) { + player_connected[i]->setChecked(true); + continue; + } + } + const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(i); + player_connected[i]->setChecked(controller->IsConnected()); } } diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 93f7eddc9..be87204fc 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -104,8 +104,8 @@ void PlayerControlPreview::UpdateColors() { colors.left = colors.primary; colors.right = colors.primary; // Possible alternative to set colors from settings - // colors.left = QColor(Settings::values.players.GetValue()[player_index].body_color_left); - // colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right); + // colors.left = QColor(controller->GetColors().left.body); + // colors.right = QColor(controller->GetColors().right.body); } void PlayerControlPreview::ResetInputs() { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index ae997ccfa..46a5f62ad 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -832,15 +832,16 @@ void GMainWindow::InitializeWidgets() { dock_status_button->setFocusPolicy(Qt::NoFocus); connect(dock_status_button, &QPushButton::clicked, [&] { const bool is_docked = Settings::values.use_docked_mode.GetValue(); - auto& controller_type = Settings::values.players.GetValue()[0].controller_type; + auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - if (!is_docked && controller_type == Settings::ControllerType::Handheld) { + if (!is_docked && handheld->IsConnected()) { QMessageBox::warning(this, tr("Invalid config detected"), tr("Handheld controller can't be used on docked mode. Pro " "controller will be selected.")); - controller_type = Settings::ControllerType::ProController; - ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system); - configure_dialog.ApplyConfiguration(); + handheld->Disconnect(); + player_1->SetNpadType(Core::HID::NpadType::ProController); + player_1->Connect(); } Settings::values.use_docked_mode.SetValue(!is_docked); From 85052b8662d9512077780f717fb2e168390ed705 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 20 Oct 2021 23:18:04 -0500 Subject: [PATCH 090/291] service/hid: Fix gesture input --- src/core/hid/emulated_console.cpp | 55 ++++---- src/core/hid/emulated_console.h | 3 + src/core/hid/emulated_controller.cpp | 4 - .../hle/service/hid/controllers/gesture.cpp | 124 ++++++++++-------- .../hle/service/hid/controllers/gesture.h | 29 +++- src/input_common/drivers/gc_adapter.cpp | 4 +- src/input_common/drivers/udp_client.cpp | 27 ++++ src/yuzu/main.cpp | 2 +- 8 files changed, 158 insertions(+), 90 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 7f7c8fd59..e82cf5990 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -20,27 +20,21 @@ void EmulatedConsole::ReloadFromSettings() { ReloadInput(); } -void EmulatedConsole::ReloadInput() { - motion_devices = Input::CreateDevice(motion_params); - if (motion_devices) { - Input::InputCallback motion_callback{ - [this](Input::CallbackStatus callback) { SetMotion(callback); }}; - motion_devices->SetCallback(motion_callback); - } - - // TODO: Fix this mess +void EmulatedConsole::SetTouchParams() { + // TODO(german77): Support any number of fingers std::size_t index = 0; - const std::string mouse_device_string = - fmt::format("engine:mouse,axis_x:10,axis_y:11,button:{}", index); - touch_devices[index] = Input::CreateDeviceFromString(mouse_device_string); - Input::InputCallback trigger_callbackk{ - [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; - touch_devices[index]->SetCallback(trigger_callbackk); - index++; + // Hardcode mouse, touchscreen and cemuhook parameters + touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; + touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; + const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons; + for (const auto& config_entry : touch_buttons) { Common::ParamPackage params{config_entry}; Common::ParamPackage touch_button_params; @@ -53,15 +47,32 @@ void EmulatedConsole::ReloadInput() { touch_button_params.Set("x", x); touch_button_params.Set("y", y); touch_button_params.Set("touch_id", static_cast(index)); - touch_devices[index] = - Input::CreateDeviceFromString(touch_button_params.Serialize()); - if (!touch_devices[index]) { + touch_params[index] = touch_button_params; + index++; + if (index >= touch_params.size()) { + return; + } + } +} + +void EmulatedConsole::ReloadInput() { + SetTouchParams(); + motion_devices = Input::CreateDevice(motion_params); + if (motion_devices) { + Input::InputCallback motion_callback{ + [this](Input::CallbackStatus callback) { SetMotion(callback); }}; + motion_devices->SetCallback(motion_callback); + } + + std::size_t index = 0; + for (auto& touch_device : touch_devices) { + touch_device = Input::CreateDevice(touch_params[index]); + if (!touch_device) { continue; } - - Input::InputCallback trigger_callback{ + Input::InputCallback touch_callback{ [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; - touch_devices[index]->SetCallback(trigger_callback); + touch_device->SetCallback(touch_callback); index++; } } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 7d6cf9506..c48d25794 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -144,6 +144,9 @@ public: void DeleteCallback(int key); private: + /// Creates and stores the touch params + void SetTouchParams(); + /** * Updates the motion status of the console * @param A CallbackStatus containing gyro and accelerometer data diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 662260327..1ff3022c5 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -705,7 +705,6 @@ void EmulatedController::Connect() { } is_connected = true; } - LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Connected, true); } @@ -714,8 +713,6 @@ void EmulatedController::Disconnect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = false; - LOG_ERROR(Service_HID, "Disconnected temporal controller {}", - NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } @@ -725,7 +722,6 @@ void EmulatedController::Disconnect() { } is_connected = false; } - LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Disconnected, true); } diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 2f98cc54b..a26ce5383 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -28,12 +28,10 @@ constexpr f32 Square(s32 num) { Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) { console = system.HIDCore().GetEmulatedConsole(); } - Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; + shared_memory.header.entry_count = 0; force_update = true; } @@ -41,27 +39,27 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - // TODO FIND WTF IS WRONG HERE!!!!!!!! - return; + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; - std::memcpy(data, &gesture_lifo, sizeof(gesture_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } ReadTouchInput(); GestureProperties gesture = GetGestureProperties(); - f32 time_difference = - static_cast(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); + f32 time_difference = static_cast(shared_memory.header.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = gesture_lifo.timestamp; + last_update_timestamp = shared_memory.header.timestamp; UpdateGestureSharedMemory(data, size, gesture, time_difference); } @@ -77,7 +75,7 @@ void Controller_Gesture::ReadTouchInput() { bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; if (force_update) { force_update = false; return true; @@ -105,16 +103,24 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureType type = GestureType::Idle; GestureAttribute attributes{}; - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - // Reset next state to default - next_state.sampling_number = last_entry.sampling_number + 1; - next_state.delta = {}; - next_state.vel_x = 0; - next_state.vel_y = 0; - next_state.direction = GestureDirection::None; - next_state.rotation_angle = 0; - next_state.scale = 0; + if (shared_memory.header.entry_count < 16) { + shared_memory.header.entry_count++; + } + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + + // Reset values to default + cur_entry.delta = {}; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = GestureDirection::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -127,21 +133,20 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, } // Apply attributes - next_state.detection_count = gesture.detection_count; - next_state.type = type; - next_state.attributes = attributes; - next_state.pos = gesture.mid_point; - next_state.point_count = static_cast(gesture.active_points); - next_state.points = gesture.points; + cur_entry.detection_count = gesture.detection_count; + cur_entry.type = type; + cur_entry.attributes = attributes; + cur_entry.pos = gesture.mid_point; + cur_entry.point_count = static_cast(gesture.active_points); + cur_entry.points = gesture.points; last_gesture = gesture; - gesture_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); gesture.detection_count++; type = GestureType::Touch; @@ -155,7 +160,7 @@ void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& typ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); // Promote to pan type if touch moved for (size_t id = 0; id < MAX_POINTS; id++) { @@ -190,7 +195,7 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Gestu void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, GestureAttribute& attributes, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); if (last_gesture_props.active_points != 0) { switch (last_entry.type) { @@ -240,18 +245,19 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); - next_state.delta = gesture.mid_point - last_entry.pos; - next_state.vel_x = static_cast(next_state.delta.x) / time_difference; - next_state.vel_y = static_cast(next_state.delta.y) / time_difference; + cur_entry.delta = gesture.mid_point - last_entry.pos; + cur_entry.vel_x = static_cast(cur_entry.delta.x) / time_difference; + cur_entry.vel_y = static_cast(cur_entry.delta.y) / time_difference; last_pan_time_difference = time_difference; // Promote to pinch type if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > pinch_threshold) { type = GestureType::Pinch; - next_state.scale = gesture.average_distance / last_gesture_props.average_distance; + cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; } const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / @@ -259,21 +265,22 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, // Promote to rotate type if (std::abs(angle_between_two_lines) > angle_threshold) { type = GestureType::Rotate; - next_state.scale = 0; - next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + cur_entry.scale = 0; + cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; } } void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - next_state.vel_x = + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); + cur_entry.vel_x = static_cast(last_entry.delta.x) / (last_pan_time_difference + time_difference); - next_state.vel_y = + cur_entry.vel_y = static_cast(last_entry.delta.y) / (last_pan_time_difference + time_difference); const f32 curr_vel = - std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); + std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); // Set swipe event with parameters if (curr_vel > swipe_threshold) { @@ -283,33 +290,42 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, // End panning without swipe type = GestureType::Complete; - next_state.vel_x = 0; - next_state.vel_y = 0; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; force_update = true; } void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); type = GestureType::Swipe; gesture = last_gesture_props; force_update = true; - next_state.delta = last_entry.delta; + cur_entry.delta = last_entry.delta; - if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { - if (next_state.delta.x > 0) { - next_state.direction = GestureDirection::Right; + if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { + if (cur_entry.delta.x > 0) { + cur_entry.direction = GestureDirection::Right; return; } - next_state.direction = GestureDirection::Left; + cur_entry.direction = GestureDirection::Left; return; } - if (next_state.delta.y > 0) { - next_state.direction = GestureDirection::Down; + if (cur_entry.delta.y > 0) { + cur_entry.direction = GestureDirection::Down; return; } - next_state.direction = GestureDirection::Up; + cur_entry.direction = GestureDirection::Up; +} + +Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { + return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; +} + +const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { + return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 8e6f315a4..6128fb0ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -71,6 +71,7 @@ private: // This is nn::hid::GestureState struct GestureState { s64_le sampling_number; + s64_le sampling_number2; s64_le detection_count; GestureType type; GestureDirection direction; @@ -84,7 +85,21 @@ private: s32_le point_count; std::array, 4> points; }; - static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); + static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); + + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array gesture_states; + }; + static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); struct Finger { Common::Point pos{}; @@ -137,17 +152,17 @@ private: void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type); + // Retrieves the last gesture entry, as indicated by shared memory indices. + [[nodiscard]] GestureState& GetLastGestureEntry(); + [[nodiscard]] const GestureState& GetLastGestureEntry() const; + // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - // This is nn::hid::detail::GestureLifo - Lifo gesture_lifo{}; - static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); - GestureState next_state{}; - - std::array fingers{}; + SharedMemory shared_memory{}; Core::HID::EmulatedConsole* console; + std::array fingers{}; GestureProperties last_gesture{}; s64_le last_update_timestamp{}; s64_le last_tap_timestamp{}; diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 4fb6ab5af..25b66f528 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -209,7 +209,7 @@ void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_ pads[port].axis_origin[index] = axis_value; pads[port].reset_origin_counter++; } - const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 110.0f; + const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 100.0f; SetAxis(pads[port].identifier, static_cast(index), axis_status); } } @@ -530,7 +530,7 @@ std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { return fmt::format("Button {}", GetUIButtonName(params)); } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis",0)); + return fmt::format("Axis {}", params.Get("axis", 0)); } return "Bad GC Adapter"; diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 6fcc3a01b..f0c0a6b8b 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -243,6 +243,33 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { }; const PadIdentifier identifier = GetPadIdentifier(pad_index); SetMotion(identifier, 0, motion); + + for (std::size_t id = 0; id < data.touch.size(); ++id) { + const auto touch_pad = data.touch[id]; + const int touch_id = static_cast(client * 2 + id); + + // TODO: Use custom calibration per device + const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); + const u16 min_x = static_cast(touch_param.Get("min_x", 100)); + const u16 min_y = static_cast(touch_param.Get("min_y", 50)); + const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); + const u16 max_y = static_cast(touch_param.Get("max_y", 850)); + + const f32 x = + static_cast(std::clamp(static_cast(touch_pad.x), min_x, max_x) - min_x) / + static_cast(max_x - min_x); + const f32 y = + static_cast(std::clamp(static_cast(touch_pad.y), min_y, max_y) - min_y) / + static_cast(max_y - min_y); + + if (touch_pad.is_active) { + SetAxis(identifier, touch_id * 2, x); + SetAxis(identifier, touch_id * 2 + 1, y); + SetButton(identifier, touch_id, true); + continue; + } + SetButton(identifier, touch_id, false); + } } void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 46a5f62ad..022d11cc4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2973,7 +2973,7 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie QString GMainWindow::GetTasStateDescription() const { auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); switch (tas_status) { - case InputCommon::TasInput::TasState::Running : + case InputCommon::TasInput::TasState::Running: return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); case InputCommon::TasInput::TasState::Recording: return tr("TAS state: Recording %1").arg(total_tas_frames); From 95cf66b6559c3e7a1eb40be919f16217566ffdbc Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 21 Oct 2021 00:49:09 -0500 Subject: [PATCH 091/291] service/hid: Use ring buffer for gestures --- .../hle/service/hid/controllers/gesture.cpp | 107 ++++++++---------- .../hle/service/hid/controllers/gesture.h | 24 +--- 2 files changed, 52 insertions(+), 79 deletions(-) diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index a26ce5383..a82d04b3b 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -31,7 +31,8 @@ Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(s Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - shared_memory.header.entry_count = 0; + gesture_lifo.entry_count = 0; + gesture_lifo.last_entry_index = 0; force_update = true; } @@ -39,27 +40,25 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + gesture_lifo.entry_count = 0; + gesture_lifo.last_entry_index = 0; + std::memcpy(data, &gesture_lifo, sizeof(gesture_lifo)); return; } ReadTouchInput(); GestureProperties gesture = GetGestureProperties(); - f32 time_difference = static_cast(shared_memory.header.timestamp - last_update_timestamp) / - (1000 * 1000 * 1000); + f32 time_difference = + static_cast(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = shared_memory.header.timestamp; + last_update_timestamp = gesture_lifo.timestamp; UpdateGestureSharedMemory(data, size, gesture, time_difference); } @@ -75,7 +74,7 @@ void Controller_Gesture::ReadTouchInput() { bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); if (force_update) { force_update = false; return true; @@ -103,24 +102,16 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureType type = GestureType::Idle; GestureAttribute attributes{}; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - if (shared_memory.header.entry_count < 16) { - shared_memory.header.entry_count++; - } - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - // Reset values to default - cur_entry.delta = {}; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; - cur_entry.direction = GestureDirection::None; - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + // Reset next state to default + next_state.sampling_number = last_entry.sampling_number + 1; + next_state.delta = {}; + next_state.vel_x = 0; + next_state.vel_y = 0; + next_state.direction = GestureDirection::None; + next_state.rotation_angle = 0; + next_state.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -133,15 +124,16 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, } // Apply attributes - cur_entry.detection_count = gesture.detection_count; - cur_entry.type = type; - cur_entry.attributes = attributes; - cur_entry.pos = gesture.mid_point; - cur_entry.point_count = static_cast(gesture.active_points); - cur_entry.points = gesture.points; + next_state.detection_count = gesture.detection_count; + next_state.type = type; + next_state.attributes = attributes; + next_state.pos = gesture.mid_point; + next_state.point_count = static_cast(gesture.active_points); + next_state.points = gesture.points; last_gesture = gesture; - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + gesture_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); } void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, @@ -245,19 +237,18 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - cur_entry.delta = gesture.mid_point - last_entry.pos; - cur_entry.vel_x = static_cast(cur_entry.delta.x) / time_difference; - cur_entry.vel_y = static_cast(cur_entry.delta.y) / time_difference; + next_state.delta = gesture.mid_point - last_entry.pos; + next_state.vel_x = static_cast(next_state.delta.x) / time_difference; + next_state.vel_y = static_cast(next_state.delta.y) / time_difference; last_pan_time_difference = time_difference; // Promote to pinch type if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > pinch_threshold) { type = GestureType::Pinch; - cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; + next_state.scale = gesture.average_distance / last_gesture_props.average_distance; } const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / @@ -265,22 +256,21 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, // Promote to rotate type if (std::abs(angle_between_two_lines) > angle_threshold) { type = GestureType::Rotate; - cur_entry.scale = 0; - cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + next_state.scale = 0; + next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; } } void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - cur_entry.vel_x = + next_state.vel_x = static_cast(last_entry.delta.x) / (last_pan_time_difference + time_difference); - cur_entry.vel_y = + next_state.vel_y = static_cast(last_entry.delta.y) / (last_pan_time_difference + time_difference); const f32 curr_vel = - std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); // Set swipe event with parameters if (curr_vel > swipe_threshold) { @@ -290,42 +280,37 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, // End panning without swipe type = GestureType::Complete; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + next_state.vel_x = 0; + next_state.vel_y = 0; force_update = true; } void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); type = GestureType::Swipe; gesture = last_gesture_props; force_update = true; - cur_entry.delta = last_entry.delta; + next_state.delta = last_entry.delta; - if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { - if (cur_entry.delta.x > 0) { - cur_entry.direction = GestureDirection::Right; + if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { + if (next_state.delta.x > 0) { + next_state.direction = GestureDirection::Right; return; } - cur_entry.direction = GestureDirection::Left; + next_state.direction = GestureDirection::Left; return; } - if (cur_entry.delta.y > 0) { - cur_entry.direction = GestureDirection::Down; + if (next_state.delta.y > 0) { + next_state.direction = GestureDirection::Down; return; } - cur_entry.direction = GestureDirection::Up; -} - -Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + next_state.direction = GestureDirection::Up; } const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + return gesture_lifo.ReadCurrentEntry().state; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 6128fb0ad..6f5abaa4f 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -71,7 +71,6 @@ private: // This is nn::hid::GestureState struct GestureState { s64_le sampling_number; - s64_le sampling_number2; s64_le detection_count; GestureType type; GestureDirection direction; @@ -85,21 +84,7 @@ private: s32_le point_count; std::array, 4> points; }; - static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); - - struct CommonHeader { - s64_le timestamp; - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - struct SharedMemory { - CommonHeader header; - std::array gesture_states; - }; - static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); + static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); struct Finger { Common::Point pos{}; @@ -153,13 +138,16 @@ private: GestureType& type); // Retrieves the last gesture entry, as indicated by shared memory indices. - [[nodiscard]] GestureState& GetLastGestureEntry(); [[nodiscard]] const GestureState& GetLastGestureEntry() const; // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - SharedMemory shared_memory{}; + // This is nn::hid::detail::GestureLifo + Lifo gesture_lifo{}; + static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); + GestureState next_state{}; + Core::HID::EmulatedConsole* console; std::array fingers{}; From b5e72de753ae4de5c5fae7087abb00dc4242451d Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 21 Oct 2021 13:56:52 -0500 Subject: [PATCH 092/291] kraken: Address comments from review review fixes --- src/core/frontend/applets/controller.cpp | 51 ++++++++----------- src/core/frontend/applets/controller.h | 8 +-- src/core/hid/emulated_console.cpp | 2 - src/core/hid/emulated_controller.cpp | 12 +++-- src/core/hid/emulated_controller.h | 1 - src/core/hid/hid_core.cpp | 4 +- src/core/hid/hid_core.h | 3 ++ src/core/hle/service/am/applets/applets.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 10 ++-- src/core/hle/service/hid/controllers/npad.h | 2 +- src/core/hle/service/hid/hid.cpp | 3 +- src/input_common/drivers/udp_client.cpp | 2 + src/input_common/drivers/udp_client.h | 4 +- src/input_common/helpers/stick_from_buttons.h | 1 - src/input_common/main.cpp | 7 ++- 15 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index ca1edce15..30500ef1e 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -5,16 +5,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/frontend/applets/controller.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" namespace Core::Frontend { ControllerApplet::~ControllerApplet() = default; -DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) - : service_manager{service_manager_} {} +DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) + : hid_core{hid_core_} {} DefaultControllerApplet::~DefaultControllerApplet() = default; @@ -22,24 +22,20 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb const ControllerParameters& parameters) const { LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); - auto& npad = - service_manager.GetService("hid") - ->GetAppletResource() - ->GetController(Service::HID::HidController::NPad); - - auto& players = Settings::values.players.GetValue(); - const std::size_t min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players; // Disconnect Handheld first. - npad.DisconnectNpadAtIndex(8); + auto* handheld =hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); + handheld->Disconnect(); // Deduce the best configuration based on the input parameters. - for (std::size_t index = 0; index < players.size() - 2; ++index) { + for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) { + auto* controller = hid_core.GetEmulatedControllerByIndex(index); + // First, disconnect all controllers regardless of the value of keep_controllers_connected. // This makes it easy to connect the desired controllers. - npad.DisconnectNpadAtIndex(index); + controller->Disconnect(); // Only connect the minimum number of required players. if (index >= min_supported_players) { @@ -49,32 +45,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb // Connect controllers based on the following priority list from highest to lowest priority: // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld if (parameters.allow_pro_controller) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::ProController), - index); + controller->SetNpadType(Core::HID::NpadType::ProController); + controller->Connect(); } else if (parameters.allow_dual_joycons) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::DualJoyconDetached), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconDual); + controller->Connect(); } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { // Assign left joycons to even player indices and right joycons to odd player indices. // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and // a right Joycon for Player 2 in 2 Player Assist mode. if (index % 2 == 0) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::LeftJoycon), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconLeft); + controller->Connect(); } else { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::RightJoycon), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconRight); + controller->Connect(); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && !Settings::values.use_docked_mode.GetValue()) { // We should *never* reach here under any normal circumstances. - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::Handheld), - index); + controller->SetNpadType(Core::HID::NpadType::Handheld); + controller->Connect(); } else { UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); } diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index b0626a0f9..014bc8901 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -8,8 +8,8 @@ #include "common/common_types.h" -namespace Service::SM { -class ServiceManager; +namespace Core::HID { +class HIDCore; } namespace Core::Frontend { @@ -44,14 +44,14 @@ public: class DefaultControllerApplet final : public ControllerApplet { public: - explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); + explicit DefaultControllerApplet(HID::HIDCore& hid_core_); ~DefaultControllerApplet() override; void ReconfigureControllers(std::function callback, const ControllerParameters& parameters) const override; private: - Service::SM::ServiceManager& service_manager; + HID::HIDCore& hid_core; }; } // namespace Core::Frontend diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index e82cf5990..540fd107b 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included -#include - #include "core/hid/emulated_console.h" #include "core/hid/input_converter.h" diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 1ff3022c5..d59758e99 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included -#include - #include "core/hid/emulated_controller.h" #include "core/hid/input_converter.h" @@ -635,6 +633,9 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { + if (device_index >= output_devices.size()) { + return false; + } if (!output_devices[device_index]) { return false; } @@ -659,6 +660,9 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v } bool EmulatedController::TestVibration(std::size_t device_index) { + if (device_index >= output_devices.size()) { + return false; + } if (!output_devices[device_index]) { return false; } @@ -733,7 +737,9 @@ bool EmulatedController::IsConnected(bool temporary) const { } bool EmulatedController::IsVibrationEnabled() const { - return is_vibration_enabled; + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + return player.vibration_enabled; } NpadIdType EmulatedController::GetNpadIdType() const { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index f3ee70726..50f21ccd9 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -337,7 +337,6 @@ private: bool is_connected{false}; bool temporary_is_connected{false}; bool is_configuring{false}; - bool is_vibration_enabled{true}; f32 motion_sensitivity{0.01f}; ButtonParams button_params; diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index bd17081bd..cc1b3c295 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -113,7 +113,7 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const { s8 HIDCore::GetPlayerCount() const { s8 active_players = 0; - for (std::size_t player_index = 0; player_index < 8; player_index++) { + for (std::size_t player_index = 0; player_index < available_controllers -2; player_index++) { const auto* controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { active_players++; @@ -123,7 +123,7 @@ s8 HIDCore::GetPlayerCount() const { } NpadIdType HIDCore::GetFirstNpadId() const { - for (std::size_t player_index = 0; player_index < 10; player_index++) { + for (std::size_t player_index = 0; player_index < available_controllers; player_index++) { const auto* controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { return controller->GetNpadIdType(); diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 196466a72..a4a66a3a4 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -47,6 +47,9 @@ public: /// Removes all callbacks from input common void UnloadInputDevices(); + /// Number of emulated controllers + const std::size_t available_controllers{10}; + private: std::unique_ptr player_1; std::unique_ptr player_2; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7320b1c0f..134ac1ee2 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -231,7 +231,7 @@ void AppletManager::SetDefaultAppletFrontendSet() { void AppletManager::SetDefaultAppletsIfMissing() { if (frontend.controller == nullptr) { frontend.controller = - std::make_unique(system.ServiceManager()); + std::make_unique(system.HIDCore()); } if (frontend.error == nullptr) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 6b9d6d11c..62b324080 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -608,15 +608,15 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_fullkey_state.sampling_number = npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_handheld_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_left_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_right_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_left_lifo_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_right_lifo_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index d805ccb97..1c6ea6f88 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -342,7 +342,7 @@ private: INSERT_PADDING_BYTES(0x4); }; - // This is nn::hid::server::NpadGcTriggerState + // This is nn::hid::system::AppletFooterUiType enum class AppletFooterUiType : u8 { None = 0, HandheldNone = 1, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5391334f4..ac48f96d3 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" @@ -34,7 +33,7 @@ namespace Service::HID { // Updating period for each HID device. -// Period time is obtained by measuring the number of samples in a second +// Period time is obtained by measuring the number of samples in a second on HW using a homebrew constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index f0c0a6b8b..192ab336b 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -268,6 +268,8 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { SetButton(identifier, touch_id, true); continue; } + SetAxis(identifier, touch_id * 2, 0); + SetAxis(identifier, touch_id * 2 + 1, 0); SetButton(identifier, touch_id, false); } } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 58b2e921d..639325b17 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -1,6 +1,6 @@ -// Copyright 2021 yuzu Emulator Project +// Copyright 2018 Citra Emulator Project // Licensed under GPLv2 or any later version -// Refer to the license.txt file included +// Refer to the license.txt file included. #pragma once diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 1d6e24c98..82dff5ca8 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -1,4 +1,3 @@ - // Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b048783c9..8f7ce59b7 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -87,25 +87,30 @@ struct InputSubsystem::Impl { void Shutdown() { Input::UnregisterFactory(keyboard->GetEngineName()); + Input::UnregisterFactory(keyboard->GetEngineName()); keyboard.reset(); Input::UnregisterFactory(mouse->GetEngineName()); + Input::UnregisterFactory(mouse->GetEngineName()); mouse.reset(); Input::UnregisterFactory(touch_screen->GetEngineName()); touch_screen.reset(); Input::UnregisterFactory(gcadapter->GetEngineName()); + Input::UnregisterFactory(gcadapter->GetEngineName()); gcadapter.reset(); Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); Input::UnregisterFactory(tas_input->GetEngineName()); + Input::UnregisterFactory(tas_input->GetEngineName()); tas_input.reset(); #ifdef HAVE_SDL2 Input::UnregisterFactory(sdl->GetEngineName()); + Input::UnregisterFactory(sdl->GetEngineName()); sdl.reset(); #endif @@ -124,8 +129,6 @@ struct InputSubsystem::Impl { devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); auto gcadapter_devices = gcadapter->GetInputDevices(); devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); - auto tas_input_devices = tas_input->GetInputDevices(); - devices.insert(devices.end(), tas_input_devices.begin(), tas_input_devices.end()); #ifdef HAVE_SDL2 auto sdl_devices = sdl->GetInputDevices(); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); From 21819da8cd7da60be8f8ba82dc940c2496a5317e Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 22 Oct 2021 12:34:44 -0500 Subject: [PATCH 093/291] yuzu: Fix loading input profiles --- src/core/hid/motion_input.cpp | 2 ++ src/yuzu/configuration/configure_input_player.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp index 93f37b77b..c25fea966 100644 --- a/src/core/hid/motion_input.cpp +++ b/src/core/hid/motion_input.cpp @@ -73,6 +73,8 @@ void MotionInput::UpdateRotation(u64 elapsed_time) { rotations += gyro * sample_period; } +// Based on Madgwick's implementation of Mayhony's AHRS algorithm. +// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs void MotionInput::UpdateOrientation(u64 elapsed_time) { if (!IsCalibrated(0.1f)) { ResetOrientation(); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 81310a5b3..cd33b5711 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -598,8 +598,15 @@ void ConfigureInputPlayer::RetranslateUI() { } void ConfigureInputPlayer::LoadConfiguration() { + emulated_controller->ReloadFromSettings(); + UpdateUI(); UpdateInputDeviceCombobox(); + + if (debug) { + return; + } + const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType(true)); ui->comboControllerType->setCurrentIndex(comboBoxIndex); ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); From e2e5f1beaf602f801bdd93d24c3cfc7862131890 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 22 Oct 2021 22:31:37 -0500 Subject: [PATCH 094/291] service/hid: Match shared memory closer to HW --- src/core/hle/service/hid/controllers/npad.cpp | 58 +++++++++++++------ src/core/hle/service/hid/controllers/npad.h | 43 +++++++++++--- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 62b324080..aad298364 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -123,8 +123,8 @@ Controller_NPad::~Controller_NPad() { void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) { if (type == Core::HID::ControllerTriggerType::All) { - ControllerUpdate(Core::HID::ControllerTriggerType::Type, controller_idx); ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); + ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); return; } @@ -139,11 +139,15 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, } UpdateControllerAt(npad_type, controller_idx, is_connected); break; - case Core::HID::ControllerTriggerType::Type: { - if (npad_type == controller.npad_type) { + case Core::HID::ControllerTriggerType::Battery: { + if (!controller.is_connected) { return; } - // UpdateControllerAt(npad_type, controller_idx, is_connected); + auto& shared_memory = controller.shared_memory_entry; + const auto& battery_level = controller.device->GetBattery(); + shared_memory.battery_level_dual = battery_level.dual.battery_level; + shared_memory.battery_level_left = battery_level.left.battery_level; + shared_memory.battery_level_right = battery_level.right.battery_level; break; } default: @@ -153,7 +157,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { auto& controller = controller_data[controller_idx]; - LOG_ERROR(Service_HID, "Connect {} {}", controller_idx, controller.is_connected); + LOG_WARNING(Service_HID, "Connect {} {}", controller_idx, controller.is_connected); const auto controller_type = controller.device->GetNpadType(); auto& shared_memory = controller.shared_memory_entry; if (controller_type == Core::HID::NpadType::None) { @@ -277,20 +281,29 @@ void Controller_NPad::OnInit() { std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), npad_id_list.size() * sizeof(u32)); - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i].device; - if (controller->IsConnected()) { - AddNewControllerAt(controller->GetNpadType(), i); - } - } - // Prefill controller buffers for (auto& controller : controller_data) { auto& npad = controller.shared_memory_entry; + npad.fullkey_color = { + .attribute = ColorAttribute::NoController, + }; + npad.joycon_color = { + .attribute = ColorAttribute::NoController, + }; + // HW seems to initialize the first 19 entries for (std::size_t i = 0; i < 19; ++i) { WriteEmptyEntry(npad); } } + + // Connect controllers + for (auto& controller : controller_data) { + const auto& device = controller.device; + if (device->IsConnected()) { + const std::size_t index = Core::HID::NpadIdTypeToIndex(device->GetNpadIdType()); + AddNewControllerAt(device->GetNpadType(), index); + } + } } void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { @@ -618,8 +631,14 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_right_lifo_state.sampling_number = npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); - npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { + // This buffer only is updated on handheld on HW + npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + } else { + // Hanheld doesn't update this buffer on HW + npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); + } + npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); @@ -864,7 +883,6 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t n } controller.device->SetNpadType(type); - controller.device->Connect(); InitNewlyAddedController(npad_index); } @@ -874,7 +892,7 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) { void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { auto& controller = controller_data[npad_index]; - LOG_ERROR(Service_HID, "Disconnect {} {}", npad_index, controller.is_connected); + LOG_WARNING(Service_HID, "Disconnect {} {}", npad_index, controller.is_connected); for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { // Send an empty vibration to stop any vibrations. VibrateControllerAtIndex(npad_index, device_idx, {}); @@ -889,8 +907,12 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { shared_memory_entry.battery_level_dual = 0; shared_memory_entry.battery_level_left = 0; shared_memory_entry.battery_level_right = 0; - shared_memory_entry.fullkey_color = {}; - shared_memory_entry.joycon_color = {}; + shared_memory_entry.fullkey_color = { + .attribute = ColorAttribute::NoController, + }; + shared_memory_entry.joycon_color = { + .attribute = ColorAttribute::NoController, + }; shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory_entry.footer_type = AppletFooterUiType::None; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 1c6ea6f88..7c534a32f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -334,10 +334,7 @@ private: }; }; - struct NfcXcdHandle { - INSERT_PADDING_BYTES(0x60); - }; - + // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); }; @@ -368,6 +365,31 @@ private: Lagon = 21, }; + // This is nn::hid::NpadLarkType + enum class NpadLarkType : u32 { + Invalid, + H1, + H2, + NL, + NR, + }; + + // This is nn::hid::NpadLuciaType + enum class NpadLuciaType : u32 { + Invalid, + J, + E, + U, + }; + + // This is nn::hid::NpadLagerType + enum class NpadLagerType : u32 { + Invalid, + J, + E, + U, + }; + // This is nn::hid::detail::NpadInternalState struct NpadInternalState { Core::HID::NpadStyleTag style_set; @@ -396,11 +418,16 @@ private: Core::HID::BatteryLevel battery_level_right; AppletFooterUiAttributes footer_attributes; AppletFooterUiType footer_type; - // nfc_states needs to be checked switchbrew doesn't match with HW - NfcXcdHandle nfc_states; - INSERT_PADDING_BYTES(0x18); // Unknown + // GetXcdHandleForNpadWithNfc needs to be checked switchbrew doesn't match with HW + INSERT_PADDING_BYTES(0x78); // Unknown Lifo gc_trigger_lifo; - INSERT_PADDING_BYTES(0xc1f); // Unknown + NpadLarkType lark_type_l; + NpadLarkType lark_type_r; + NpadLuciaType lucia_type; + NpadLagerType lager_type; + INSERT_PADDING_BYTES( + 0x8); // FW 13.x Investigate there is some sort of bitflag related to joycons + INSERT_PADDING_BYTES(0xc08); // Unknown }; static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); From b564f024f0be5023cf13fb2fca953ea6c1feeeb6 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 22 Oct 2021 23:04:06 -0500 Subject: [PATCH 095/291] Morph review first wave --- src/core/core.h | 2 +- src/core/frontend/applets/controller.cpp | 5 +- src/core/hid/emulated_console.cpp | 4 +- src/core/hid/emulated_console.h | 10 ++-- src/core/hid/emulated_controller.cpp | 6 +-- src/core/hid/emulated_controller.h | 22 ++++----- src/core/hid/emulated_devices.cpp | 4 +- src/core/hid/hid_core.cpp | 8 ++-- src/core/hid/hid_types.h | 48 +++++++++---------- src/core/hid/input_converter.cpp | 12 ++--- .../service/hid/controllers/console_sixaxis.h | 14 +++--- .../hle/service/hid/controllers/debug_pad.h | 4 +- .../hle/service/hid/controllers/gesture.cpp | 9 ++-- .../hle/service/hid/controllers/gesture.h | 33 ++++++------- .../hle/service/hid/controllers/keyboard.h | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 4 +- src/core/hle/service/hid/controllers/npad.h | 22 ++++----- .../hle/service/hid/controllers/stubbed.h | 8 ++-- .../service/hid/controllers/touchscreen.cpp | 4 +- .../hle/service/hid/controllers/touchscreen.h | 14 ++---- src/core/hle/service/hid/controllers/xpad.h | 6 +-- src/core/hle/service/hid/ring_lifo.h | 10 ++-- .../configure_input_player_widget.cpp | 2 +- 23 files changed, 117 insertions(+), 136 deletions(-) diff --git a/src/core/core.h b/src/core/core.h index 5a031efb0..645e5c241 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -289,7 +289,7 @@ public: /// Provides a constant reference to the kernel instance. [[nodiscard]] const Kernel::KernelCore& Kernel() const; - /// Gets a mutable reference to the HID interface + /// Gets a mutable reference to the HID interface. [[nodiscard]] HID::HIDCore& HIDCore(); /// Gets an immutable reference to the HID interface. diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 30500ef1e..212ace892 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -13,8 +13,7 @@ namespace Core::Frontend { ControllerApplet::~ControllerApplet() = default; -DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) - : hid_core{hid_core_} {} +DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {} DefaultControllerApplet::~DefaultControllerApplet() = default; @@ -26,7 +25,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb parameters.enable_single_mode ? 1 : parameters.min_players; // Disconnect Handheld first. - auto* handheld =hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); handheld->Disconnect(); // Deduce the best configuration based on the input parameters. diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 540fd107b..d1d4a5355 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -6,7 +6,7 @@ #include "core/hid/input_converter.h" namespace Core::HID { -EmulatedConsole::EmulatedConsole() {} +EmulatedConsole::EmulatedConsole() = default; EmulatedConsole::~EmulatedConsole() = default; @@ -191,7 +191,7 @@ TouchFingerState EmulatedConsole::GetTouch() const { } void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const ConsoleUpdateCallback& poller = poller_pair.second; if (poller.on_change) { poller.on_change(type); diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index c48d25794..f26f24f2e 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -20,7 +20,7 @@ namespace Core::HID { struct ConsoleMotionInfo { - Input::MotionStatus raw_status; + Input::MotionStatus raw_status{}; MotionInput emulated{}; }; @@ -34,21 +34,21 @@ using ConsoleMotionValues = ConsoleMotionInfo; using TouchValues = std::array; struct TouchFinger { - u64_le last_touch{}; + u64 last_touch{}; Common::Point position{}; - u32_le id{}; - bool pressed{}; + u32 id{}; TouchAttribute attribute{}; + bool pressed{}; }; // Contains all motion related data that is used on the services struct ConsoleMotion { - bool is_at_rest{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Vec3f rotation{}; std::array orientation{}; Common::Quaternion quaternion{}; + bool is_at_rest{}; }; using TouchFingerState = std::array; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index d59758e99..228f80183 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -865,10 +865,10 @@ BatteryLevelState EmulatedController::GetBattery() const { return controller.battery_state; } -void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_service_update) { - for (const std::pair poller_pair : callback_list) { +void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { + for (const auto& poller_pair : callback_list) { const ControllerUpdateCallback& poller = poller_pair.second; - if (!is_service_update && poller.is_service) { + if (!is_npad_service_update && poller.is_npad_service) { continue; } if (poller.on_change) { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 50f21ccd9..d66768549 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -20,7 +20,7 @@ namespace Core::HID { struct ControllerMotionInfo { - Input::MotionStatus raw_status; + Input::MotionStatus raw_status{}; MotionInput emulated{}; }; @@ -51,28 +51,28 @@ using BatteryValues = std::array; using VibrationValues = std::array; struct AnalogSticks { - AnalogStickState left; - AnalogStickState right; + AnalogStickState left{}; + AnalogStickState right{}; }; struct ControllerColors { - NpadControllerColor fullkey; - NpadControllerColor left; - NpadControllerColor right; + NpadControllerColor fullkey{}; + NpadControllerColor left{}; + NpadControllerColor right{}; }; struct BatteryLevelState { - NpadPowerInfo dual; - NpadPowerInfo left; - NpadPowerInfo right; + NpadPowerInfo dual{}; + NpadPowerInfo left{}; + NpadPowerInfo right{}; }; struct ControllerMotion { - bool is_at_rest; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Vec3f rotation{}; std::array orientation{}; + bool is_at_rest{}; }; using MotionState = std::array; @@ -113,7 +113,7 @@ enum class ControllerTriggerType { struct ControllerUpdateCallback { std::function on_change; - bool is_service; + bool is_npad_service; }; class EmulatedController { diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 54a753d8a..1c4065cd8 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -9,7 +9,7 @@ namespace Core::HID { -EmulatedDevices::EmulatedDevices() {} +EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; @@ -332,7 +332,7 @@ MousePosition EmulatedDevices::GetMousePosition() const { } void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InterfaceUpdateCallback& poller = poller_pair.second; if (poller.on_change) { poller.on_change(type); diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index cc1b3c295..3cb26e1e7 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -113,8 +113,8 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const { s8 HIDCore::GetPlayerCount() const { s8 active_players = 0; - for (std::size_t player_index = 0; player_index < available_controllers -2; player_index++) { - const auto* controller = GetEmulatedControllerByIndex(player_index); + for (std::size_t player_index = 0; player_index < available_controllers - 2; ++player_index) { + const auto* const controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { active_players++; } @@ -123,8 +123,8 @@ s8 HIDCore::GetPlayerCount() const { } NpadIdType HIDCore::GetFirstNpadId() const { - for (std::size_t player_index = 0; player_index < available_controllers; player_index++) { - const auto* controller = GetEmulatedControllerByIndex(player_index); + for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) { + const auto* const controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { return controller->GetNpadIdType(); } diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 539436283..59ec593b8 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -100,7 +100,7 @@ enum class NpadType : u8 { // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> fullkey; BitField<1, 1, u32> handheld; @@ -132,35 +132,35 @@ static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size" // This is nn::hid::TouchState struct TouchState { - u64_le delta_time; + u64 delta_time; TouchAttribute attribute; - u32_le finger; - Common::Point position; - u32_le diameter_x; - u32_le diameter_y; - u32_le rotation_angle; + u32 finger; + Common::Point position; + u32 diameter_x; + u32 diameter_y; + u32 rotation_angle; }; static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); // This is nn::hid::NpadControllerColor struct NpadControllerColor { - u32_le body; - u32_le button; + u32 body; + u32 button; }; static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); // This is nn::hid::AnalogStickState struct AnalogStickState { - s32_le x; - s32_le y; + s32 x; + s32 y; }; static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size"); // This is nn::hid::server::NpadGcTriggerState struct NpadGcTriggerState { - s64_le sampling_number{}; - s32_le left{}; - s32_le right{}; + s64 sampling_number{}; + s32 left{}; + s32 right{}; }; static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); @@ -286,7 +286,7 @@ static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect siz // This is nn::hid::DebugPadButton struct DebugPadButton { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> a; BitField<1, 1, u32> b; BitField<2, 1, u32> x; @@ -345,7 +345,7 @@ static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incor // This is nn::hid::KeyboardModifier struct KeyboardModifier { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> control; BitField<1, 1, u32> shift; BitField<2, 1, u32> left_alt; @@ -383,7 +383,7 @@ static_assert(sizeof(MouseButton) == 0x4, "MouseButton is an invalid size"); // This is nn::hid::MouseAttribute struct MouseAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> transferable; BitField<1, 1, u32> is_connected; }; @@ -392,13 +392,13 @@ static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size" // This is nn::hid::detail::MouseState struct MouseState { - s64_le sampling_number; - s32_le x; - s32_le y; - s32_le delta_x; - s32_le delta_y; - s32_le delta_wheel_x; - s32_le delta_wheel_y; + s64 sampling_number; + s32 x; + s32 y; + s32 delta_x; + s32 delta_y; + s32 delta_wheel_x; + s32 delta_wheel_y; MouseButton button; MouseAttribute attribute; }; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 128a48ec9..b3c8913ce 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -142,8 +142,8 @@ Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { } SanitizeStick(status.x, status.y, true); - const Input::AnalogProperties& properties_x = status.x.properties; - const Input::AnalogProperties& properties_y = status.y.properties; + const auto& properties_x = status.x.properties; + const auto& properties_y = status.y.properties; const float x = status.x.value; const float y = status.y.value; @@ -213,7 +213,7 @@ Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { } SanitizeAnalog(status.analog, true); - const Input::AnalogProperties& properties = status.analog.properties; + const auto& properties = status.analog.properties; float& value = status.analog.value; // Set button status @@ -231,7 +231,7 @@ Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { } void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { - const Input::AnalogProperties& properties = analog.properties; + const auto& properties = analog.properties; float& raw_value = analog.raw_value; float& value = analog.value; @@ -271,8 +271,8 @@ void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { } void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value) { - const Input::AnalogProperties& properties_x = analog_x.properties; - const Input::AnalogProperties& properties_y = analog_y.properties; + const auto& properties_x = analog_x.properties; + const auto& properties_y = analog_y.properties; float& raw_x = analog_x.raw_value; float& raw_y = analog_y.raw_value; float& x = analog_x.value; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 6d18d2ce0..95729e6b2 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -35,8 +35,8 @@ public: private: struct SevenSixAxisState { INSERT_PADDING_WORDS(4); // unused - s64_le sampling_number{}; - s64_le sampling_number2{}; + s64 sampling_number{}; + s64 sampling_number2{}; u64 unknown{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; @@ -45,10 +45,10 @@ private: static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); struct CommonHeader { - s64_le timestamp; - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; + s64 timestamp; + s64 total_entry_count; + s64 last_entry_index; + s64 entry_count; }; static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); @@ -61,7 +61,7 @@ private: // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { - u64_le sampling_number{}; + u64 sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; f32 verticalization_error{}; Common::Vec3f gyro_bias{}; diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 11b6c669b..bd0f15eaa 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -38,7 +38,7 @@ private: // This is nn::hid::DebugPadAttribute struct DebugPadAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> connected; }; }; @@ -46,7 +46,7 @@ private: // This is nn::hid::DebugPadState struct DebugPadState { - s64_le sampling_number; + s64 sampling_number; DebugPadAttribute attribute; Core::HID::DebugPadButton pad_state; Core::HID::AnalogStickState r_stick; diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index a82d04b3b..7a7bc68a2 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -65,10 +65,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u void Controller_Gesture::ReadTouchInput() { const auto touch_status = console->GetTouch(); for (std::size_t id = 0; id < fingers.size(); ++id) { - const Core::HID::TouchFinger& status = touch_status[id]; - Finger& finger = fingers[id]; - finger.pos = status.position; - finger.pressed = status.pressed; + fingers[id] = touch_status[id]; } } @@ -315,14 +312,14 @@ const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry( Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { GestureProperties gesture; - std::array active_fingers; + std::array active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); gesture.active_points = static_cast(std::distance(active_fingers.begin(), end_iter)); for (size_t id = 0; id < gesture.active_points; ++id) { - const auto& [active_x, active_y] = active_fingers[id].pos; + const auto& [active_x, active_y] = active_fingers[id].position; gesture.points[id] = { .x = static_cast(active_x * Layout::ScreenUndocked::Width), .y = static_cast(active_y * Layout::ScreenUndocked::Height), diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 6f5abaa4f..58139a5cf 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -60,7 +60,7 @@ private: // This is nn::hid::GestureAttribute struct GestureAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<4, 1, u32> is_new_touch; BitField<8, 1, u32> is_double_tap; @@ -70,33 +70,28 @@ private: // This is nn::hid::GestureState struct GestureState { - s64_le sampling_number; - s64_le detection_count; + s64 sampling_number; + s64 detection_count; GestureType type; GestureDirection direction; - Common::Point pos; - Common::Point delta; + Common::Point pos; + Common::Point delta; f32 vel_x; f32 vel_y; GestureAttribute attributes; f32 scale; f32 rotation_angle; - s32_le point_count; - std::array, 4> points; + s32 point_count; + std::array, 4> points; }; static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); - struct Finger { - Common::Point pos{}; - bool pressed{}; - }; - struct GestureProperties { - std::array, MAX_POINTS> points{}; + std::array, MAX_POINTS> points{}; std::size_t active_points{}; - Common::Point mid_point{}; - s64_le detection_count{}; - u64_le delta_time{}; + Common::Point mid_point{}; + s64 detection_count{}; + u64 delta_time{}; f32 average_distance{}; f32 angle{}; }; @@ -150,10 +145,10 @@ private: Core::HID::EmulatedConsole* console; - std::array fingers{}; + std::array fingers{}; GestureProperties last_gesture{}; - s64_le last_update_timestamp{}; - s64_le last_tap_timestamp{}; + s64 last_update_timestamp{}; + s64 last_tap_timestamp{}; f32 last_pan_time_difference{}; bool force_update{false}; bool enable_press_and_tap{false}; diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 6919e092a..aba4f123e 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -37,7 +37,7 @@ public: private: // This is nn::hid::detail::KeyboardState struct KeyboardState { - s64_le sampling_number; + s64 sampling_number; Core::HID::KeyboardModifier modifier; Core::HID::KeyboardKey key; }; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index aad298364..7bf31f63a 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -106,7 +106,7 @@ Controller_NPad::Controller_NPad(Core::System& system_, Core::HID::ControllerUpdateCallback engine_callback{ .on_change = [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, - .is_service = true, + .is_npad_service = true, }; controller.callback_key = controller.device->SetCallback(engine_callback); } @@ -157,7 +157,6 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { auto& controller = controller_data[controller_idx]; - LOG_WARNING(Service_HID, "Connect {} {}", controller_idx, controller.is_connected); const auto controller_type = controller.device->GetNpadType(); auto& shared_memory = controller.shared_memory_entry; if (controller_type == Core::HID::NpadType::None) { @@ -892,7 +891,6 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) { void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { auto& controller = controller_data[npad_index]; - LOG_WARNING(Service_HID, "Disconnect {} {}", npad_index, controller.is_connected); for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { // Send an empty vibration to stop any vibrations. VibrateControllerAtIndex(npad_index, device_idx, {}); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 7c534a32f..0a2dc6992 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -195,7 +195,7 @@ public: private: // This is nn::hid::detail::ColorAttribute - enum class ColorAttribute : u32_le { + enum class ColorAttribute : u32 { Ok = 0, ReadError = 1, NoController = 2, @@ -220,7 +220,7 @@ private: // This is nn::hid::NpadAttribute struct NpadAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -251,7 +251,7 @@ private: // This is nn::hid::SixAxisSensorAttribute struct SixAxisSensorAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_interpolated; }; @@ -260,8 +260,8 @@ private: // This is nn::hid::SixAxisSensorState struct SixAxisSensorState { - s64_le delta_time{}; - s64_le sampling_number{}; + s64 delta_time{}; + s64 sampling_number{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Vec3f rotation{}; @@ -273,16 +273,16 @@ private: // This is nn::hid::server::NpadGcTriggerState struct NpadGcTriggerState { - s64_le sampling_number{}; - s32_le l_analog{}; - s32_le r_analog{}; + s64 sampling_number{}; + s32 l_analog{}; + s32 r_analog{}; }; static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); // This is nn::hid::NpadSystemProperties struct NPadSystemProperties { union { - s64_le raw{}; + s64 raw{}; BitField<0, 1, s64> is_charging_joy_dual; BitField<1, 1, s64> is_charging_joy_left; BitField<2, 1, s64> is_charging_joy_right; @@ -303,7 +303,7 @@ private: // This is nn::hid::NpadSystemButtonProperties struct NpadSystemButtonProperties { union { - s32_le raw{}; + s32 raw{}; BitField<0, 1, s32> is_home_button_protection_enabled; }; }; @@ -313,7 +313,7 @@ private: // This is nn::hid::system::DeviceType struct DeviceType { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, s32> fullkey; BitField<1, 1, s32> debug_pad; BitField<2, 1, s32> handheld_left; diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 29f95a100..10aecad4c 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -26,10 +26,10 @@ public: private: struct CommonHeader { - s64_le timestamp; - s64_le total_entry_count; - s64_le last_entry_index; - s64_le entry_count; + s64 timestamp; + s64 total_entry_count; + s64 last_entry_index; + s64 entry_count; }; static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index e0a44d06b..5ba8d96a8 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -66,7 +66,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin } } - std::array active_fingers; + std::array active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); const auto active_fingers_count = @@ -76,7 +76,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; - next_state.entry_count = static_cast(active_fingers_count); + next_state.entry_count = static_cast(active_fingers_count); for (std::size_t id = 0; id < MAX_FINGERS; ++id) { auto& touch_entry = next_state.states[id]; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index bcf79237d..fa4dfa1a2 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -50,27 +50,19 @@ private: // This is nn::hid::TouchScreenState struct TouchScreenState { - s64_le sampling_number; - s32_le entry_count; + s64 sampling_number; + s32 entry_count; INSERT_PADDING_BYTES(4); // Reserved std::array states; }; static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); - struct Finger { - u64_le last_touch{}; - Common::Point position; - u32_le id{}; - bool pressed{}; - Core::HID::TouchAttribute attribute; - }; - // This is nn::hid::detail::TouchScreenLifo Lifo touch_screen_lifo{}; static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); TouchScreenState next_state{}; - std::array fingers; + std::array fingers; Core::HID::EmulatedConsole* console; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index a5421f93b..75e0d2911 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -31,7 +31,7 @@ private: // This is nn::hid::BasicXpadAttributeSet struct BasicXpadAttributeSet { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -45,7 +45,7 @@ private: // This is nn::hid::BasicXpadButtonSet struct BasicXpadButtonSet { union { - u32_le raw{}; + u32 raw{}; // Button states BitField<0, 1, u32> a; BitField<1, 1, u32> b; @@ -93,7 +93,7 @@ private: // This is nn::hid::detail::BasicXpadState struct BasicXpadState { - s64_le sampling_number; + s64 sampling_number; BasicXpadAttributeSet attributes; BasicXpadButtonSet pad_states; Core::HID::AnalogStickState l_stick; diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 1cc2a194f..f68d82762 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -12,16 +12,16 @@ constexpr std::size_t max_entry_size = 17; template struct AtomicStorage { - s64_le sampling_number; + s64 sampling_number; State state; }; template struct Lifo { - s64_le timestamp{}; - s64_le total_entry_count = max_entry_size; - s64_le last_entry_index{}; - s64_le entry_count{}; + s64 timestamp{}; + s64 total_entry_count = max_entry_size; + s64 last_entry_index{}; + s64 entry_count{}; std::array, max_entry_size> entries{}; const AtomicStorage& ReadCurrentEntry() const { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index be87204fc..3f179150d 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -28,7 +28,7 @@ void PlayerControlPreview::SetController(Core::HID::EmulatedController* controll controller = controller_; Core::HID::ControllerUpdateCallback engine_callback{ .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, - .is_service = false, + .is_npad_service = false, }; callback_key = controller->SetCallback(engine_callback); ControllerUpdate(Core::HID::ControllerTriggerType::All); From cc651c7c99f04c60f1c3422fb9edc8b11e82cd51 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 01:02:56 -0500 Subject: [PATCH 096/291] web_applet: Replace HIDButton with NpadButton --- src/yuzu/applets/qt_controller.cpp | 3 +- src/yuzu/applets/qt_web_browser.cpp | 61 ++++++++++++++++------------- src/yuzu/applets/qt_web_browser.h | 12 +++--- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 32cb5b5ff..59289c6a5 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -28,7 +28,8 @@ namespace { constexpr std::size_t HANDHELD_INDEX = 8; -void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadType controller_type, bool connected) { +void UpdateController(Core::HID::EmulatedController* controller, + Core::HID::NpadType controller_type, bool connected) { if (controller->IsConnected()) { controller->Disconnect(); } diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 8e190f9fe..cb3c5d826 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -16,6 +16,7 @@ #include "common/fs/path_util.h" #include "common/param_package.h" #include "core/core.h" +#include "core/hid/hid_types.h" #include "core/hid/input_interpreter.h" #include "input_common/drivers/keyboard.h" #include "input_common/main.h" @@ -28,19 +29,19 @@ namespace { -constexpr int HIDButtonToKey(HIDButton button) { +constexpr int HIDButtonToKey(Core::HID::NpadButton button) { switch (button) { - case HIDButton::DLeft: - case HIDButton::LStickLeft: + case Core::HID::NpadButton::Left: + case Core::HID::NpadButton::StickLLeft: return Qt::Key_Left; - case HIDButton::DUp: - case HIDButton::LStickUp: + case Core::HID::NpadButton::Up: + case Core::HID::NpadButton::StickLUp: return Qt::Key_Up; - case HIDButton::DRight: - case HIDButton::LStickRight: + case Core::HID::NpadButton::Right: + case Core::HID::NpadButton::StickLRight: return Qt::Key_Right; - case HIDButton::DDown: - case HIDButton::LStickDown: + case Core::HID::NpadButton::Down: + case Core::HID::NpadButton::StickLDown: return Qt::Key_Down; default: return 0; @@ -209,25 +210,25 @@ void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) { } } -template +template void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { page()->runJavaScript( QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast(button)), [this, button](const QVariant& variant) { if (variant.toBool()) { switch (button) { - case HIDButton::A: + case Core::HID::NpadButton::A: SendMultipleKeyPressEvents(); break; - case HIDButton::B: + case Core::HID::NpadButton::B: SendKeyPressEvent(Qt::Key_B); break; - case HIDButton::X: + case Core::HID::NpadButton::X: SendKeyPressEvent(Qt::Key_X); break; - case HIDButton::Y: + case Core::HID::NpadButton::Y: SendKeyPressEvent(Qt::Key_Y); break; default: @@ -245,9 +246,9 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { (f(T), ...); } -template +template void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { SendKeyPressEvent(HIDButtonToKey(button)); } @@ -256,9 +257,9 @@ void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { (f(T), ...); } -template +template void QtNXWebEngineView::HandleWindowKeyButtonHold() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonHeld(button)) { SendKeyPressEvent(HIDButtonToKey(button)); } @@ -309,17 +310,21 @@ void QtNXWebEngineView::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleWindowFooterButtonPressedOnce(); + HandleWindowFooterButtonPressedOnce(); - HandleWindowKeyButtonPressedOnce(); + HandleWindowKeyButtonPressedOnce< + Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, + Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, + Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, + Core::HID::NpadButton::StickLDown>(); - HandleWindowKeyButtonHold(); + HandleWindowKeyButtonHold< + Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, + Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, + Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, + Core::HID::NpadButton::StickLDown>(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index 7e9f703fc..fa18aecac 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -16,8 +16,6 @@ #include "core/frontend/applets/web_browser.h" -enum class HIDButton : u8; - class GMainWindow; class InputInterpreter; class UrlRequestInterceptor; @@ -26,6 +24,10 @@ namespace Core { class System; } +namespace Core::HID { +enum class NpadButton : u64; +} + namespace InputCommon { class InputSubsystem; } @@ -114,7 +116,7 @@ private: * * @tparam HIDButton The list of buttons contained in yuzu_key_callbacks */ - template + template void HandleWindowFooterButtonPressedOnce(); /** @@ -123,7 +125,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleWindowKeyButtonPressedOnce(); /** @@ -132,7 +134,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleWindowKeyButtonHold(); /** From 464c4d26ac8e7af6302390684445b357e5cda4e4 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 11:22:20 -0500 Subject: [PATCH 097/291] settings: Fix mouse and keyboard mappings --- src/core/hid/emulated_controller.cpp | 8 +- src/core/hid/emulated_devices.cpp | 19 ++- src/core/hid/emulated_devices.h | 3 + src/input_common/drivers/mouse.cpp | 17 ++- src/input_common/drivers/mouse.h | 1 + src/input_common/input_engine.cpp | 2 + src/input_common/main.cpp | 3 + .../configuration/configure_input_player.cpp | 143 +++++++----------- .../configuration/configure_vibration.cpp | 4 +- src/yuzu/debugger/controller.cpp | 3 +- 10 files changed, 100 insertions(+), 103 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 228f80183..bd0b89c05 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -246,7 +246,7 @@ std::vector EmulatedController::GetMappedDevices() const { devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { return param.Get("engine", "") == param_.Get("engine", "") && param.Get("guid", "") == param_.Get("guid", "") && - param.Get("port", "") == param_.Get("port", ""); + param.Get("port", 0) == param_.Get("port", 0); }); if (devices_it != devices.end()) { continue; @@ -254,7 +254,7 @@ std::vector EmulatedController::GetMappedDevices() const { Common::ParamPackage device{}; device.Set("engine", param.Get("engine", "")); device.Set("guid", param.Get("guid", "")); - device.Set("port", param.Get("port", "")); + device.Set("port", param.Get("port", 0)); devices.push_back(device); } @@ -269,7 +269,7 @@ std::vector EmulatedController::GetMappedDevices() const { devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { return param.Get("engine", "") == param_.Get("engine", "") && param.Get("guid", "") == param_.Get("guid", "") && - param.Get("port", "") == param_.Get("port", ""); + param.Get("port", 0) == param_.Get("port", 0); }); if (devices_it != devices.end()) { continue; @@ -277,7 +277,7 @@ std::vector EmulatedController::GetMappedDevices() const { Common::ParamPackage device{}; device.Set("engine", param.Get("engine", "")); device.Set("guid", param.Get("guid", "")); - device.Set("port", param.Get("port", "")); + device.Set("port", param.Get("port", 0)); devices.push_back(device); } return devices; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 1c4065cd8..5afd83f62 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -162,17 +162,22 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz return; } - // TODO(german77): Do this properly - // switch (index) { - // case Settings::NativeKeyboard::A: - // interface_status.keyboard_state.a.Assign(current_status.value); - // break; - // .... - // } + UpdateKey(index, current_status.value); TriggerOnChange(DeviceTriggerType::Keyboard); } +void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { + constexpr u8 KEYS_PER_BYTE = 8; + auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; + const u8 mask = 1 << (key_index % KEYS_PER_BYTE); + if (status) { + entry = entry | mask; + } else { + entry = entry & ~mask; + } +} + void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_moddifier_values.size()) { return; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index c6c19fae4..7ed95eac6 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -143,6 +143,9 @@ public: void DeleteCallback(int key); private: + /// Helps assigning a value to keyboard_state + void UpdateKey(std::size_t key_index, bool status); + /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the key status diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 2c2432fb7..1c32b54be 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -121,12 +121,27 @@ void Mouse::StopPanning() { std::vector Mouse::GetInputDevices() const { std::vector devices; devices.emplace_back(Common::ParamPackage{ - {"engine", "keyboard"}, + {"engine", GetEngineName()}, {"display", "Keyboard/Mouse"}, }); return devices; } +AnalogMapping Mouse::GetAnalogMappingForDevice( + [[maybe_unused]] const Common::ParamPackage& params) { + // Only overwrite different buttons from default + AnalogMapping mapping = {}; + Common::ParamPackage right_analog_params; + right_analog_params.Set("engine", GetEngineName()); + right_analog_params.Set("axis_x", 0); + right_analog_params.Set("axis_y", 1); + right_analog_params.Set("threshold", 0.5f); + right_analog_params.Set("range", 1.0f); + right_analog_params.Set("deadzone", 0.0f); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + return mapping; +} + std::string Mouse::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { return fmt::format("Mouse {}", params.Get("button", 0)); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index e8355751a..d3178b1a9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -55,6 +55,7 @@ public: void ReleaseAllButtons(); std::vector GetInputDevices() const override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; std::string GetUIName(const Common::ParamPackage& params) const override; private: diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 1534f24b0..9cfe0f232 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -202,6 +202,8 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but if (!configuring || !mapping_callback.on_data) { return; } + + PreSetButton(identifier, button); if (value == GetButton(identifier, button)) { return; } diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 8f7ce59b7..07d514ad7 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -143,6 +143,9 @@ struct InputSubsystem::Impl { return {}; } const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return mouse->GetAnalogMappingForDevice(params); + } if (engine == gcadapter->GetEngineName()) { return gcadapter->GetAnalogMappingForDevice(params); } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index cd33b5711..416096333 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -478,37 +478,39 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this, player_index](int) { - UpdateControllerAvailableButtons(); - UpdateControllerEnabledButtons(); - UpdateControllerButtonNames(); - UpdateMotionButtons(); - const Core::HID::NpadType type = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), + [this, player_index](int) { + UpdateControllerAvailableButtons(); + UpdateControllerEnabledButtons(); + UpdateControllerButtonNames(); + UpdateMotionButtons(); + const Core::HID::NpadType type = + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); - if (player_index == 0) { - auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - bool is_connected = emulated_controller->IsConnected(true); + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + bool is_connected = emulated_controller->IsConnected(true); - emulated_controller_p1->SetNpadType(type); - emulated_controller_hanheld->SetNpadType(type); - if (is_connected) { - if (type == Core::HID::NpadType::Handheld) { - emulated_controller_p1->Disconnect(); - emulated_controller_hanheld->Connect(); - emulated_controller = emulated_controller_hanheld; - } else { - emulated_controller_hanheld->Disconnect(); - emulated_controller_p1->Connect(); - emulated_controller = emulated_controller_p1; + emulated_controller_p1->SetNpadType(type); + emulated_controller_hanheld->SetNpadType(type); + if (is_connected) { + if (type == Core::HID::NpadType::Handheld) { + emulated_controller_p1->Disconnect(); + emulated_controller_hanheld->Connect(); + emulated_controller = emulated_controller_hanheld; + } else { + emulated_controller_hanheld->Disconnect(); + emulated_controller_p1->Connect(); + emulated_controller = emulated_controller_p1; + } + } + ui->controllerFrame->SetController(emulated_controller); } - } - ui->controllerFrame->SetController(emulated_controller); - } - emulated_controller->SetNpadType(type); - }); + emulated_controller->SetNpadType(type); + }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, &ConfigureInputPlayer::UpdateMappingWithDefaults); @@ -555,7 +557,7 @@ ConfigureInputPlayer::~ConfigureInputPlayer() { } else { emulated_controller->DisableConfiguration(); } -}; +} void ConfigureInputPlayer::ApplyConfiguration() { if (player_index == 0) { @@ -642,7 +644,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { const auto first_engine = devices[0].Get("engine", ""); const auto first_guid = devices[0].Get("guid", ""); - const auto first_port = devices[0].Get("port", ""); + const auto first_port = devices[0].Get("port", 0); if (devices.size() == 1) { const auto devices_it = @@ -650,7 +652,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { [first_engine, first_guid, first_port](const Common::ParamPackage param) { return param.Get("engine", "") == first_engine && param.Get("guid", "") == first_guid && - param.Get("port", "") == first_port; + param.Get("port", 0) == first_port; }); const int device_index = devices_it != input_devices.end() @@ -662,7 +664,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { const auto second_engine = devices[1].Get("engine", ""); const auto second_guid = devices[1].Get("guid", ""); - const auto second_port = devices[1].Get("port", ""); + const auto second_port = devices[1].Get("port", 0); const bool is_keyboard_mouse = (first_engine == "keyboard" || first_engine == "mouse") && (second_engine == "keyboard" || second_engine == "mouse"); @@ -684,7 +686,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { param.Get("guid2", "") == second_guid) || (param.Get("guid", "") == second_guid && param.Get("guid2", "") == first_guid); return param.Get("engine", "") == first_engine && is_guid_valid && - param.Get("port", "") == first_port; + param.Get("port", 0) == first_port; }); const int device_index = devices_it != input_devices.end() @@ -1096,8 +1098,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { emulated_controller->SetMotionParam(motion_id, {}); } - // Reset keyboard bindings - if (ui->comboDevices->currentIndex() == 1) { + // Reset keyboard or mouse bindings + if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { emulated_controller->SetButtonParam( button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( @@ -1122,63 +1124,30 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { Config::default_motions[motion_id])}); } - UpdateUI(); - return; - } - - // Reset keyboard with mouse bindings - if (ui->comboDevices->currentIndex() == 2) { - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { - emulated_controller->SetButtonParam( - button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_buttons[button_id])}); + // If mouse is selected we want to override with mappings from the driver + if (ui->comboDevices->currentIndex() == 1) { + UpdateUI(); + return; } - - Common::ParamPackage left_analog_param{}; - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { - Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[Settings::NativeAnalog::LStick][sub_button_id])}; - SetAnalogParam(params, left_analog_param, analog_sub_buttons[sub_button_id]); - } - left_analog_param.Set("modifier", - InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[Settings::NativeAnalog::LStick])); - emulated_controller->SetStickParam(Settings::NativeAnalog::LStick, left_analog_param); - - Common::ParamPackage right_analog_param{}; - right_analog_param.Set("engine", "mouse"); - right_analog_param.Set("port", 0); - right_analog_param.Set("axis_x", 0); - right_analog_param.Set("axis_y", 1); - emulated_controller->SetStickParam(Settings::NativeAnalog::RStick, - std::move(right_analog_param)); - - for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - emulated_controller->SetMotionParam( - motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_motions[motion_id])}); - } - - UpdateUI(); - return; } // Reset controller bindings const auto& device = input_devices[ui->comboDevices->currentIndex()]; - auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); - auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); - auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); - for (std::size_t i = 0; i < button_mapping.size(); ++i) { - emulated_controller->SetButtonParam( - i, button_mapping[static_cast(i)]); + auto button_mappings = input_subsystem->GetButtonMappingForDevice(device); + auto analog_mappings = input_subsystem->GetAnalogMappingForDevice(device); + auto motion_mappings = input_subsystem->GetMotionMappingForDevice(device); + + for (const auto& button_mapping : button_mappings) { + const std::size_t index = button_mapping.first; + emulated_controller->SetButtonParam(index, button_mapping.second); } - for (std::size_t i = 0; i < analog_mapping.size(); ++i) { - emulated_controller->SetStickParam( - i, analog_mapping[static_cast(i)]); + for (const auto& analog_mapping : analog_mappings) { + const std::size_t index = analog_mapping.first; + emulated_controller->SetStickParam(index, analog_mapping.second); } - for (std::size_t i = 0; i < motion_mapping.size(); ++i) { - emulated_controller->SetMotionParam( - i, motion_mapping[static_cast(i)]); + for (const auto& motion_mapping : motion_mappings) { + const std::size_t index = motion_mapping.first; + emulated_controller->SetMotionParam(index, motion_mapping.second); } UpdateUI(); @@ -1237,7 +1206,7 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) } // Keyboard/Mouse - if (ui->comboDevices->currentIndex() == 2) { + if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; } @@ -1245,7 +1214,7 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) return params.Get("engine", "") == current_input_device.Get("engine", "") && (params.Get("guid", "") == current_input_device.Get("guid", "") || params.Get("guid", "") == current_input_device.Get("guid2", "")) && - params.Get("port", "") == current_input_device.Get("port", ""); + params.Get("port", 0) == current_input_device.Get("port", 0); } void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index 46a0f3025..f1ce7205d 100644 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp @@ -97,7 +97,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { const auto engine = param.Get("engine", ""); const auto guid = param.Get("guid", ""); - const auto port = param.Get("port", ""); + const auto port = param.Get("port", 0); if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") { continue; @@ -105,7 +105,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { vibration_param_str += fmt::format("engine:{}", engine); - if (!port.empty()) { + if (port != 0) { vibration_param_str += fmt::format(",port:{}", port); } if (!guid.empty()) { diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 3619aed26..f93a46421 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -21,8 +21,7 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(system.HIDCore().GetEmulatedController( - Core::HID::NpadIdType::Player1)); + widget->SetController(system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1)); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(widget); From f01dac3bf934657059b77bae3630201110f83e3d Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 20:27:00 -0500 Subject: [PATCH 098/291] service/hid: Fix memory allocated incorrectly --- src/core/hle/service/hid/controllers/debug_pad.cpp | 6 +++--- src/core/hle/service/hid/controllers/gesture.cpp | 2 +- src/core/hle/service/hid/controllers/keyboard.cpp | 2 +- src/core/hle/service/hid/controllers/mouse.cpp | 2 +- src/core/hle/service/hid/controllers/xpad.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index b2b4edf51..5b1946f13 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -12,7 +12,7 @@ #include "core/hle/service/hid/controllers/debug_pad.h" namespace Service::HID { - +constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; constexpr s32 HID_JOYSTICK_MAX = 0x7fff; [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; @@ -32,7 +32,7 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, if (!IsControllerActivated()) { debug_pad_lifo.entry_count = 0; debug_pad_lifo.last_entry_index = 0; - std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); return; } @@ -51,7 +51,7 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, } debug_pad_lifo.WriteNextEntry(next_state); - std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 7a7bc68a2..47760b4f8 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -43,7 +43,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u if (!IsControllerActivated()) { gesture_lifo.entry_count = 0; gesture_lifo.last_entry_index = 0; - std::memcpy(data, &gesture_lifo, sizeof(gesture_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index db0f56b92..632679a17 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -29,7 +29,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, if (!IsControllerActivated()) { keyboard_lifo.entry_count = 0; keyboard_lifo.last_entry_index = 0; - std::memcpy(data, &keyboard_lifo, sizeof(keyboard_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 2f607bfe9..6d3bd0a2b 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -29,7 +29,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (!IsControllerActivated()) { mouse_lifo.entry_count = 0; mouse_lifo.last_entry_index = 0; - std::memcpy(data, &mouse_lifo, sizeof(mouse_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 29a412ff9..aa9f044f1 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -22,7 +22,7 @@ void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (!IsControllerActivated()) { basic_xpad_lifo.entry_count = 0; basic_xpad_lifo.last_entry_index = 0; - std::memcpy(data, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); return; } From c6c32daf40ae1c720f0a2897c538bb1117371ea5 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 20:28:54 -0500 Subject: [PATCH 099/291] input_common: Add manual update options to input devices --- src/common/input.h | 10 ++++++++++ src/core/hid/emulated_controller.cpp | 9 +++++++++ .../helpers/stick_from_buttons.cpp | 16 +++++++++++++++ .../helpers/touch_from_buttons.cpp | 1 + src/input_common/input_poller.cpp | 20 +++++++++++++++++++ 5 files changed, 56 insertions(+) diff --git a/src/common/input.h b/src/common/input.h index cdacd4689..cb84f1005 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -164,6 +164,16 @@ class InputDevice { public: virtual ~InputDevice() = default; + // Request input device to update if necessary + virtual void SoftUpdate() { + return; + } + + // Force input device to update data regarless of the current state + virtual void ForceUpdate() { + return; + } + void SetCallback(InputCallback callback_) { callback = std::move(callback_); } diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index bd0b89c05..48add394b 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -122,6 +122,7 @@ void EmulatedController::ReloadInput() { Input::InputCallback button_callback{ [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; button_devices[index]->SetCallback(button_callback); + button_devices[index]->ForceUpdate(); } for (std::size_t index = 0; index < stick_devices.size(); ++index) { @@ -131,6 +132,7 @@ void EmulatedController::ReloadInput() { Input::InputCallback stick_callback{ [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; stick_devices[index]->SetCallback(stick_callback); + stick_devices[index]->ForceUpdate(); } for (std::size_t index = 0; index < trigger_devices.size(); ++index) { @@ -140,6 +142,7 @@ void EmulatedController::ReloadInput() { Input::InputCallback trigger_callback{ [this, index](Input::CallbackStatus callback) { SetTrigger(callback, index); }}; trigger_devices[index]->SetCallback(trigger_callback); + trigger_devices[index]->ForceUpdate(); } for (std::size_t index = 0; index < battery_devices.size(); ++index) { @@ -149,6 +152,7 @@ void EmulatedController::ReloadInput() { Input::InputCallback battery_callback{ [this, index](Input::CallbackStatus callback) { SetBattery(callback, index); }}; battery_devices[index]->SetCallback(battery_callback); + battery_devices[index]->ForceUpdate(); } for (std::size_t index = 0; index < motion_devices.size(); ++index) { @@ -158,6 +162,7 @@ void EmulatedController::ReloadInput() { Input::InputCallback motion_callback{ [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; motion_devices[index]->SetCallback(motion_callback); + motion_devices[index]->ForceUpdate(); } } @@ -843,6 +848,10 @@ AnalogSticks EmulatedController::GetSticks() const { if (is_configuring) { return {}; } + // Some drivers like stick from buttons need constant refreshing + for (auto& device : stick_devices) { + device->SoftUpdate(); + } return controller.analog_stick_state; } diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 38f150746..9101f11ce 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -200,6 +200,22 @@ public: TriggerOnChange(status); } + void ForceUpdate() override{ + up->ForceUpdate(); + down->ForceUpdate(); + left->ForceUpdate(); + right->ForceUpdate(); + modifier->ForceUpdate(); + } + + void SoftUpdate() override { + Input::CallbackStatus status{ + .type = Input::InputType::Stick, + .stick_status = GetStatus(), + }; + TriggerOnChange(status); + } + Input::StickStatus GetStatus() const { Input::StickStatus status{}; status.x.properties = properties; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 2abfaf841..bb2bad5b1 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -17,6 +17,7 @@ public: Input::InputCallback button_up_callback{ [this](Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; button->SetCallback(button_up_callback); + button->ForceUpdate(); } Input::TouchStatus GetStatus(bool pressed) const { diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 62ade951c..024bd28ef 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -45,6 +45,16 @@ public: }; } + void ForceUpdate() { + const Input::CallbackStatus status{ + .type = Input::InputType::Button, + .button_status = GetStatus(), + }; + + last_button_value = status.button_status.value; + TriggerOnChange(status); + } + void OnChange() { const Input::CallbackStatus status{ .type = Input::InputType::Button, @@ -96,6 +106,16 @@ public: }; } + void ForceUpdate() { + const Input::CallbackStatus status{ + .type = Input::InputType::Button, + .button_status = GetStatus(), + }; + + last_button_value = status.button_status.value; + TriggerOnChange(status); + } + void OnChange() { const Input::CallbackStatus status{ .type = Input::InputType::Button, From 064ddacf49aa7155e26add55983b81fdda997077 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 23:23:54 -0500 Subject: [PATCH 100/291] core/hid: Rework battery mappings --- src/core/hid/emulated_controller.cpp | 50 +++++++++++-------- src/core/hid/emulated_controller.h | 28 +++++++---- src/core/hid/emulated_devices.cpp | 2 +- src/core/hid/input_converter.cpp | 4 ++ src/core/hle/service/hid/controllers/npad.cpp | 11 +++- .../helpers/stick_from_buttons.cpp | 2 +- src/input_common/input_poller.cpp | 39 +++++++++++++-- .../configuration/configure_input_player.cpp | 2 +- .../configure_input_player_widget.cpp | 17 +++---- 9 files changed, 109 insertions(+), 46 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 48add394b..83ced5635 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -87,11 +87,23 @@ void EmulatedController::ReloadFromSettings() { ReloadInput(); } +void EmulatedController::LoadDevices() { + const auto left_joycon = button_params[Settings::NativeButton::ZL]; + const auto right_joycon = button_params[Settings::NativeButton::ZR]; -void EmulatedController::ReloadInput() { - // If you load any device here add the equivalent to the UnloadInput() function - const auto left_side = button_params[Settings::NativeButton::ZL]; - const auto right_side = button_params[Settings::NativeButton::ZR]; + // Triggers for GC controllers + trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; + trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR]; + + battery_params[LeftIndex] = left_joycon; + battery_params[RightIndex] = right_joycon; + battery_params[LeftIndex].Set("battery", true); + battery_params[RightIndex].Set("battery", true); + + output_params[LeftIndex] = left_joycon; + output_params[RightIndex] = right_joycon; + output_params[LeftIndex].Set("output", true); + output_params[RightIndex].Set("output", true); std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, button_params.begin() + Settings::NativeButton::BUTTON_NS_END, @@ -102,19 +114,17 @@ void EmulatedController::ReloadInput() { std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, motion_devices.begin(), Input::CreateDevice); + std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), + Input::CreateDevice); + std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(), + Input::CreateDevice); + std::transform(output_params.begin(), output_params.end(), output_devices.begin(), + Input::CreateDevice); +} - trigger_devices[0] = - Input::CreateDevice(button_params[Settings::NativeButton::ZL]); - trigger_devices[1] = - Input::CreateDevice(button_params[Settings::NativeButton::ZR]); - - battery_devices[0] = Input::CreateDevice(left_side); - battery_devices[1] = Input::CreateDevice(right_side); - - button_params[Settings::NativeButton::ZL].Set("output", true); - output_devices[0] = - Input::CreateDevice(button_params[Settings::NativeButton::ZL]); - +void EmulatedController::ReloadInput() { + // If you load any device here add the equivalent to the UnloadInput() function + LoadDevices(); for (std::size_t index = 0; index < button_devices.size(); ++index) { if (!button_devices[index]) { continue; @@ -241,7 +251,7 @@ void EmulatedController::RestoreConfig() { ReloadFromSettings(); } -std::vector EmulatedController::GetMappedDevices() const { +std::vector EmulatedController::GetMappedDevices(DeviceIndex device_index) const { std::vector devices; for (const auto& param : button_params) { if (!param.Has("engine")) { @@ -612,21 +622,21 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t } switch (index) { - case 0: + case LeftIndex: controller.battery_state.left = { .is_powered = is_powered, .is_charging = is_charging, .battery_level = battery_level, }; break; - case 1: + case RightIndex: controller.battery_state.right = { .is_powered = is_powered, .is_charging = is_charging, .battery_level = battery_level, }; break; - case 2: + case DualIndex: controller.battery_state.dual = { .is_powered = is_powered, .is_charging = is_charging, diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d66768549..eb705a241 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -18,7 +18,7 @@ #include "core/hid/motion_input.h" namespace Core::HID { - +const std::size_t max_emulated_controllers = 2; struct ControllerMotionInfo { Input::MotionStatus raw_status{}; MotionInput emulated{}; @@ -32,23 +32,23 @@ using ControllerMotionDevices = std::array, Settings::NativeMotion::NumMotions>; using TriggerDevices = std::array, Settings::NativeTrigger::NumTriggers>; -using BatteryDevices = std::array, 2>; -using OutputDevices = std::array, 2>; +using BatteryDevices = std::array, max_emulated_controllers>; +using OutputDevices = std::array, max_emulated_controllers>; using ButtonParams = std::array; using StickParams = std::array; using ControllerMotionParams = std::array; using TriggerParams = std::array; -using BatteryParams = std::array; -using OutputParams = std::array; +using BatteryParams = std::array; +using OutputParams = std::array; using ButtonValues = std::array; using SticksValues = std::array; using TriggerValues = std::array; using ControllerMotionValues = std::array; -using ColorValues = std::array; -using BatteryValues = std::array; -using VibrationValues = std::array; +using ColorValues = std::array; +using BatteryValues = std::array; +using VibrationValues = std::array; struct AnalogSticks { AnalogStickState left{}; @@ -75,6 +75,13 @@ struct ControllerMotion { bool is_at_rest{}; }; +enum DeviceIndex : u8 { + LeftIndex, + RightIndex, + DualIndex, + AllDevices, +}; + using MotionState = std::array; struct ControllerStatus { @@ -189,7 +196,7 @@ public: void RestoreConfig(); /// Returns a vector of mapped devices from the mapped button and stick parameters - std::vector GetMappedDevices() const; + std::vector GetMappedDevices(DeviceIndex device_index) const; // Returns the current mapped button device Common::ParamPackage GetButtonParam(std::size_t index) const; @@ -289,6 +296,9 @@ public: void DeleteCallback(int key); private: + /// creates input devices from params + void LoadDevices(); + /** * Updates the button status of the controller * @param callback: A CallbackStatus containing the button status diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 5afd83f62..eb59c310c 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -174,7 +174,7 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { if (status) { entry = entry | mask; } else { - entry = entry & ~mask; + entry = static_cast(entry & ~mask); } } diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index b3c8913ce..e2598f367 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -33,6 +33,10 @@ Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { } break; } + case Input::InputType::Button: + battery = callback.button_status.value ? Input::BatteryLevel::Charging + : Input::BatteryLevel::Critical; + break; case Input::InputType::Battery: battery = callback.battery_status; break; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 7bf31f63a..9f84e20c2 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -101,8 +101,9 @@ Controller_NPad::Controller_NPad(Core::System& system_, for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; controller.device = system.HIDCore().GetEmulatedControllerByIndex(i); - controller.vibration[0].latest_vibration_value = DEFAULT_VIBRATION_VALUE; - controller.vibration[1].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + controller.vibration[Core::HID::DeviceIndex::LeftIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + controller.vibration[Core::HID::DeviceIndex::RightIndex].latest_vibration_value = + DEFAULT_VIBRATION_VALUE; Core::HID::ControllerUpdateCallback engine_callback{ .on_change = [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, @@ -285,9 +286,12 @@ void Controller_NPad::OnInit() { auto& npad = controller.shared_memory_entry; npad.fullkey_color = { .attribute = ColorAttribute::NoController, + .fullkey = {}, }; npad.joycon_color = { .attribute = ColorAttribute::NoController, + .left = {}, + .right = {}, }; // HW seems to initialize the first 19 entries for (std::size_t i = 0; i < 19; ++i) { @@ -907,9 +911,12 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { shared_memory_entry.battery_level_right = 0; shared_memory_entry.fullkey_color = { .attribute = ColorAttribute::NoController, + .fullkey = {}, }; shared_memory_entry.joycon_color = { .attribute = ColorAttribute::NoController, + .left = {}, + .right = {}, }; shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory_entry.footer_type = AppletFooterUiType::None; diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 9101f11ce..806a0e8bb 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -200,7 +200,7 @@ public: TriggerOnChange(status); } - void ForceUpdate() override{ + void ForceUpdate() override { up->ForceUpdate(); down->ForceUpdate(); left->ForceUpdate(); diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 024bd28ef..6edb8d900 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -183,6 +183,17 @@ public: return status; } + void ForceUpdate() { + const Input::CallbackStatus status{ + .type = Input::InputType::Stick, + .stick_status = GetStatus(), + }; + + last_axis_x_value = status.stick_status.x.raw_value; + last_axis_y_value = status.stick_status.y.raw_value; + TriggerOnChange(status); + } + void OnChange() { const Input::CallbackStatus status{ .type = Input::InputType::Stick, @@ -448,6 +459,16 @@ public: return static_cast(input_engine->GetBattery(identifier)); } + void ForceUpdate() { + const Input::CallbackStatus status{ + .type = Input::InputType::Battery, + .battery_status = GetStatus(), + }; + + last_battery_value = status.battery_status; + TriggerOnChange(status); + } + void OnChange() { const Input::CallbackStatus status{ .type = Input::InputType::Battery, @@ -579,6 +600,18 @@ public: return status; } + void ForceUpdate() { + const Input::CallbackStatus status{ + .type = Input::InputType::Motion, + .motion_status = GetStatus(), + }; + + last_axis_x_value = status.motion_status.gyro.x.raw_value; + last_axis_y_value = status.motion_status.gyro.y.raw_value; + last_axis_z_value = status.motion_status.gyro.z.raw_value; + TriggerOnChange(status); + } + void OnChange() { const Input::CallbackStatus status{ .type = Input::InputType::Motion, @@ -868,6 +901,9 @@ InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { + if (params.Has("battery")) { + return CreateBatteryDevice(params); + } if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } @@ -892,9 +928,6 @@ std::unique_ptr InputFactory::Create(const Common::ParamPack if (params.Has("axis")) { return CreateAnalogDevice(params); } - if (params.Has("battery")) { - return CreateBatteryDevice(params); - } LOG_ERROR(Input, "Invalid parameters given"); return std::make_unique(); } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 416096333..acb29a6b4 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -630,7 +630,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { return; } - const auto devices = emulated_controller->GetMappedDevices(); + const auto devices = emulated_controller->GetMappedDevices(Core::HID::DeviceIndex::AllDevices); UpdateInputDevices(); if (devices.empty()) { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 3f179150d..67e56ed3a 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -356,7 +356,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) DrawCircle(p, center + QPoint(26, 71), 5); // Draw battery - DrawBattery(p, center + QPoint(-170, -140), battery_values[0]); + DrawBattery(p, center + QPoint(-170, -140), battery_values[Core::HID::DeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) { @@ -482,7 +482,7 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5); // Draw battery - DrawBattery(p, center + QPoint(110, -140), battery_values[1]); + DrawBattery(p, center + QPoint(110, -140), battery_values[Core::HID::DeviceIndex::RightIndex]); } void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { @@ -618,8 +618,8 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f); // Draw battery - DrawBattery(p, center + QPoint(-100, -160), battery_values[0]); - DrawBattery(p, center + QPoint(40, -160), battery_values[1]); + DrawBattery(p, center + QPoint(-100, -160), battery_values[Core::HID::DeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(40, -160), battery_values[Core::HID::DeviceIndex::RightIndex]); } void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { @@ -720,9 +720,8 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f); // Draw battery - DrawBattery(p, center + QPoint(-200, 110), battery_values[0]); - DrawBattery(p, center + QPoint(-30, 110), battery_values[1]); - DrawBattery(p, center + QPoint(130, 110), battery_values[2]); + DrawBattery(p, center + QPoint(-200, 110), battery_values[Core::HID::DeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(130, 110), battery_values[Core::HID::DeviceIndex::RightIndex]); } void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { @@ -812,7 +811,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); // Draw battery - DrawBattery(p, center + QPoint(-30, -160), battery_values[0]); + DrawBattery(p, center + QPoint(-30, -160), battery_values[Core::HID::DeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { @@ -868,7 +867,7 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8); // Draw battery - DrawBattery(p, center + QPoint(-30, -165), battery_values[0]); + DrawBattery(p, center + QPoint(-30, -165), battery_values[Core::HID::DeviceIndex::LeftIndex]); } constexpr std::array symbol_a = { From 7348e205d94e2fff777781498a2ef7931163703a Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 26 Oct 2021 23:37:46 -0500 Subject: [PATCH 101/291] input_common: Add multiple vibration curves --- src/core/hid/emulated_controller.cpp | 10 +++++++- src/input_common/drivers/sdl_driver.cpp | 33 ++++++++++++++----------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 83ced5635..916368c68 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -251,7 +251,8 @@ void EmulatedController::RestoreConfig() { ReloadFromSettings(); } -std::vector EmulatedController::GetMappedDevices(DeviceIndex device_index) const { +std::vector EmulatedController::GetMappedDevices( + DeviceIndex device_index) const { std::vector devices; for (const auto& param : button_params) { if (!param.Has("engine")) { @@ -658,6 +659,10 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v const auto& player = Settings::values.players.GetValue()[player_index]; const f32 strength = static_cast(player.vibration_strength) / 100.0f; + if (!player.vibration_enabled) { + return false; + } + // Exponential amplification is too strong at low amplitudes. Switch to a linear // amplification if strength is set below 0.7f const Input::VibrationAmplificationType type = @@ -860,6 +865,9 @@ AnalogSticks EmulatedController::GetSticks() const { } // Some drivers like stick from buttons need constant refreshing for (auto& device : stick_devices) { + if (!device) { + continue; + } device->SoftUpdate(); } return controller.analog_stick_state; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index d56351815..53e282ef3 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -94,7 +94,6 @@ public: bool RumblePlay(const Input::VibrationStatus vibration) { constexpr u32 rumble_max_duration_ms = 1000; - if (sdl_controller) { return SDL_GameControllerRumble( sdl_controller.get(), static_cast(vibration.low_amplitude), @@ -520,25 +519,31 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); - const auto process_amplitude = [](f32 amplitude) { - return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; + const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { + return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF; }; - const Input::VibrationStatus exponential_vibration{ - .low_amplitude = process_amplitude(vibration.low_amplitude), + + // Default exponential curve for rumble + f32 factor = 0.35f; + + // If vibration is set as a linear output use a flatter value + if (vibration.type == Input::VibrationAmplificationType::Linear) { + factor = 0.5f; + } + + // Amplitude for HD rumble needs no modification + if (joystick->HasHDRumble()) { + factor = 1.0f; + } + + const Input::VibrationStatus new_vibration{ + .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor), .low_frequency = vibration.low_frequency, - .high_amplitude = process_amplitude(vibration.high_amplitude), + .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor), .high_frequency = vibration.high_frequency, .type = Input::VibrationAmplificationType::Exponential, }; - Input::VibrationStatus new_vibration{}; - - if (vibration.type == Input::VibrationAmplificationType::Linear || joystick->HasHDRumble()) { - new_vibration = vibration; - } else { - new_vibration = exponential_vibration; - } - if (!joystick->RumblePlay(new_vibration)) { return Input::VibrationError::Unknown; } From 1d71d4b87415b2581e6757f07d29275e02671b7a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 25 Oct 2021 12:53:14 -0500 Subject: [PATCH 102/291] input_common: Fix UDP uuid --- src/input_common/drivers/udp_client.cpp | 10 +++++++++- src/input_common/drivers/udp_client.h | 2 ++ src/yuzu/configuration/configure_input_player.cpp | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 192ab336b..7cab707da 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "common/logging/log.h" #include "common/param_package.h" @@ -279,6 +280,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, [this](Response::PortInfo info) { OnPortInfo(info); }, [this, client](Response::PadData data) { OnPadData(data, client); }}; LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); + clients[client].uuid = GetHostUUID(host); clients[client].host = host; clients[client].port = port; clients[client].active = 0; @@ -293,12 +295,18 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { const std::size_t client = pad_index / PADS_PER_CLIENT; return { - .guid = Common::UUID{clients[client].host}, + .guid = clients[client].uuid, .port = static_cast(clients[client].port), .pad = pad_index, }; } +const Common::UUID UDPClient::GetHostUUID(const std::string host) const { + const auto ip = boost::asio::ip::address_v4::from_string(host); + const auto hex_host = fmt::format("{:06x}", ip.to_ulong()); + return Common::UUID{hex_host}; +} + void UDPClient::Reset() { for (auto& client : clients) { if (client.thread.joinable()) { diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 639325b17..1f02adba5 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -69,6 +69,7 @@ private: struct ClientConnection { ClientConnection(); ~ClientConnection(); + Common::UUID uuid{"7F000001"}; std::string host{"127.0.0.1"}; u16 port{26760}; s8 active{-1}; @@ -87,6 +88,7 @@ private: void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port); const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; + const Common::UUID GetHostUUID(const std::string host) const; // Allocate clients for 8 udp servers static constexpr std::size_t MAX_UDP_CLIENTS = 8; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index acb29a6b4..9a1b3575e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1178,7 +1178,7 @@ void ConfigureInputPlayer::HandleClick( } timeout_timer->start(2500); // Cancel after 2.5 seconds - poll_timer->start(50); // Check for new inputs every 50ms + poll_timer->start(25); // Check for new inputs every 25ms } void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { @@ -1205,6 +1205,10 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) return true; } + if (params.Has("motion")) { + return true; + } + // Keyboard/Mouse if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; From c085e54316c5520ed7d58a92a7faa9e896bb6c71 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 27 Oct 2021 00:20:28 -0500 Subject: [PATCH 103/291] core/hid: Add TAS input --- src/common/settings.h | 1 - src/core/hid/emulated_controller.cpp | 72 ++++++++++++++++++++++++ src/core/hid/emulated_controller.h | 9 +++ src/yuzu/configuration/config.cpp | 2 - src/yuzu/configuration/configure_tas.cpp | 2 - src/yuzu/configuration/configure_tas.ui | 9 +-- 6 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index 4cf28617c..dac44d000 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -567,7 +567,6 @@ struct Values { BasicSetting pause_tas_on_load{true, "pause_tas_on_load"}; BasicSetting tas_enable{false, "tas_enable"}; BasicSetting tas_loop{false, "tas_loop"}; - BasicSetting tas_swap_controllers{true, "tas_swap_controllers"}; BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 916368c68..2b051ccaf 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -105,6 +105,8 @@ void EmulatedController::LoadDevices() { output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); + LoadTASParams(); + std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, button_params.begin() + Settings::NativeButton::BUTTON_NS_END, button_devices.begin(), Input::CreateDevice); @@ -120,6 +122,51 @@ void EmulatedController::LoadDevices() { Input::CreateDevice); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), Input::CreateDevice); + + // Initialize TAS devices + std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), + Input::CreateDevice); + std::transform(tas_stick_params.begin(), tas_stick_params.begin(), tas_stick_devices.begin(), + Input::CreateDevice); +} + +void EmulatedController::LoadTASParams() { + const auto player_index = NpadIdTypeToIndex(npad_id_type); + Common::ParamPackage common_params{}; + common_params.Set("engine", "tas"); + common_params.Set("pad", static_cast(player_index)); + for (auto& param : tas_button_params) { + param = common_params; + } + for (auto& param : tas_stick_params) { + param = common_params; + } + + tas_button_params[Settings::NativeButton::A].Set("button", 1 << 0); + tas_button_params[Settings::NativeButton::B].Set("button", 1 << 1); + tas_button_params[Settings::NativeButton::X].Set("button", 1 << 2); + tas_button_params[Settings::NativeButton::Y].Set("button", 1 << 3); + tas_button_params[Settings::NativeButton::LStick].Set("button", 1 << 4); + tas_button_params[Settings::NativeButton::RStick].Set("button", 1 << 5); + tas_button_params[Settings::NativeButton::L].Set("button", 1 << 6); + tas_button_params[Settings::NativeButton::R].Set("button", 1 << 7); + tas_button_params[Settings::NativeButton::ZL].Set("button", 1 << 8); + tas_button_params[Settings::NativeButton::ZR].Set("button", 1 << 9); + tas_button_params[Settings::NativeButton::Plus].Set("button", 1 << 10); + tas_button_params[Settings::NativeButton::Minus].Set("button", 1 << 11); + tas_button_params[Settings::NativeButton::DLeft].Set("button", 1 << 12); + tas_button_params[Settings::NativeButton::DUp].Set("button", 1 << 13); + tas_button_params[Settings::NativeButton::DRight].Set("button", 1 << 14); + tas_button_params[Settings::NativeButton::DDown].Set("button", 1 << 15); + tas_button_params[Settings::NativeButton::SL].Set("button", 1 << 16); + tas_button_params[Settings::NativeButton::SR].Set("button", 1 << 17); + tas_button_params[Settings::NativeButton::Home].Set("button", 1 << 18); + tas_button_params[Settings::NativeButton::Screenshot].Set("button", 1 << 19); + + tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); + tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); + tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); + tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); } void EmulatedController::ReloadInput() { @@ -174,6 +221,25 @@ void EmulatedController::ReloadInput() { motion_devices[index]->SetCallback(motion_callback); motion_devices[index]->ForceUpdate(); } + + // Register TAS devices. No need to force update + for (std::size_t index = 0; index < tas_button_devices.size(); ++index) { + if (!tas_button_devices[index]) { + continue; + } + Input::InputCallback button_callback{ + [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + tas_button_devices[index]->SetCallback(button_callback); + } + + for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) { + if (!tas_stick_devices[index]) { + continue; + } + Input::InputCallback stick_callback{ + [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + tas_stick_devices[index]->SetCallback(stick_callback); + } } void EmulatedController::UnloadInput() { @@ -195,6 +261,12 @@ void EmulatedController::UnloadInput() { for (auto& output : output_devices) { output.reset(); } + for (auto& button : tas_button_devices) { + button.reset(); + } + for (auto& stick : tas_stick_devices) { + stick.reset(); + } } void EmulatedController::EnableConfiguration() { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index eb705a241..eec51e34a 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -299,6 +299,9 @@ private: /// creates input devices from params void LoadDevices(); + /// Set the params for TAS devices + void LoadTASParams(); + /** * Updates the button status of the controller * @param callback: A CallbackStatus containing the button status @@ -363,6 +366,12 @@ private: BatteryDevices battery_devices; OutputDevices output_devices; + // TAS related variables + ButtonParams tas_button_params; + StickParams tas_stick_params; + ButtonDevices tas_button_devices; + StickDevices tas_stick_devices; + mutable std::mutex mutex; std::unordered_map callback_list; int last_callback_key = 0; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 56af07507..7a748d9c8 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -573,7 +573,6 @@ void Config::ReadControlValues() { ReadBasicSetting(Settings::values.tas_enable); ReadBasicSetting(Settings::values.tas_loop); - ReadBasicSetting(Settings::values.tas_swap_controllers); ReadBasicSetting(Settings::values.pause_tas_on_load); ReadGlobalSetting(Settings::values.use_docked_mode); @@ -1209,7 +1208,6 @@ void Config::SaveControlValues() { WriteBasicSetting(Settings::values.tas_enable); WriteBasicSetting(Settings::values.tas_loop); - WriteBasicSetting(Settings::values.tas_swap_controllers); WriteBasicSetting(Settings::values.pause_tas_on_load); qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 8e5a4c72d..979a8db61 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -32,7 +32,6 @@ void ConfigureTasDialog::LoadConfiguration() { ui->tas_path_edit->setText( QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir))); ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue()); - ui->tas_control_swap->setChecked(Settings::values.tas_swap_controllers.GetValue()); ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue()); ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue()); } @@ -40,7 +39,6 @@ void ConfigureTasDialog::LoadConfiguration() { void ConfigureTasDialog::ApplyConfiguration() { Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString()); Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked()); - Settings::values.tas_swap_controllers.SetValue(ui->tas_control_swap->isChecked()); Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked()); Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked()); } diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui index 7d44895c4..cf88a5bf0 100644 --- a/src/yuzu/configuration/configure_tas.ui +++ b/src/yuzu/configuration/configure_tas.ui @@ -59,20 +59,13 @@ - - - Automatic controller profile swapping - - - - Loop script - + false From 2d3a63b28969089746e43ed232dc74630fbfc3b2 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 27 Oct 2021 18:06:13 -0500 Subject: [PATCH 104/291] core/hid: Update structs to 13.1.0 --- src/core/hid/hid_types.h | 10 ++++ src/core/hid/input_interpreter.cpp | 14 ++--- src/core/hid/input_interpreter.h | 2 +- .../hle/service/hid/controllers/debug_pad.cpp | 4 +- .../hle/service/hid/controllers/gesture.cpp | 8 +-- .../hle/service/hid/controllers/keyboard.cpp | 4 +- .../hle/service/hid/controllers/mouse.cpp | 6 +- src/core/hle/service/hid/controllers/npad.cpp | 15 ++--- src/core/hle/service/hid/controllers/npad.h | 60 +++++++++++++++++-- .../service/hid/controllers/touchscreen.cpp | 4 +- src/core/hle/service/hid/controllers/xpad.cpp | 4 +- src/core/hle/service/hid/ring_lifo.h | 26 ++++---- 12 files changed, 107 insertions(+), 50 deletions(-) diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 59ec593b8..f8a0d5edd 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -231,7 +231,12 @@ enum class NpadButton : u64 { RightSR = 1U << 27, Palma = 1U << 28, + Verification = 1U << 29, HandheldLeftB = 1U << 30, + LagonCLeft = 1U << 31, + LagonCUp = 1ULL << 32, + LagonCRight = 1ULL << 33, + LagonCDown = 1ULL << 34, }; DECLARE_ENUM_FLAG_OPERATORS(NpadButton); @@ -278,7 +283,12 @@ struct NpadButtonState { BitField<27, 1, u64> right_sr; BitField<28, 1, u64> palma; + BitField<29, 1, u64> verification; BitField<30, 1, u64> handheld_left_b; + BitField<31, 1, u64> lagon_c_left; + BitField<32, 1, u64> lagon_c_up; + BitField<33, 1, u64> lagon_c_right; + BitField<34, 1, u64> lagon_c_down; }; }; static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect size."); diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp index 7e7c1816f..870422d82 100644 --- a/src/core/hid/input_interpreter.cpp +++ b/src/core/hid/input_interpreter.cpp @@ -20,7 +20,7 @@ InputInterpreter::InputInterpreter(Core::System& system) InputInterpreter::~InputInterpreter() = default; void InputInterpreter::PollInput() { - const u32 button_state = npad.GetAndResetPressState(); + const u64 button_state = npad.GetAndResetPressState(); previous_index = current_index; current_index = (current_index + 1) % button_states.size(); @@ -32,7 +32,7 @@ void InputInterpreter::ResetButtonStates() { previous_index = 0; current_index = 0; - button_states[0] = 0xFFFFFFFF; + button_states[0] = 0xFFFFFFFFFFFFFFFF; for (std::size_t i = 1; i < button_states.size(); ++i) { button_states[i] = 0; @@ -40,22 +40,22 @@ void InputInterpreter::ResetButtonStates() { } bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const { - return (button_states[current_index] & static_cast(button)) != 0; + return (button_states[current_index] & static_cast(button)) != 0; } bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const { - const bool current_press = (button_states[current_index] & static_cast(button)) != 0; - const bool previous_press = (button_states[previous_index] & static_cast(button)) != 0; + const bool current_press = (button_states[current_index] & static_cast(button)) != 0; + const bool previous_press = (button_states[previous_index] & static_cast(button)) != 0; return current_press && !previous_press; } bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const { - u32 held_buttons{button_states[0]}; + u64 held_buttons{button_states[0]}; for (std::size_t i = 1; i < button_states.size(); ++i) { held_buttons &= button_states[i]; } - return (held_buttons & static_cast(button)) != 0; + return (held_buttons & static_cast(button)) != 0; } diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h index 1791cf9b7..1c2e02142 100644 --- a/src/core/hid/input_interpreter.h +++ b/src/core/hid/input_interpreter.h @@ -105,7 +105,7 @@ private: Service::HID::Controller_NPad& npad; /// Stores 9 consecutive button states polled from HID. - std::array button_states{}; + std::array button_states{}; std::size_t previous_index{}; std::size_t current_index{}; diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 5b1946f13..345134357 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -30,8 +30,8 @@ void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { if (!IsControllerActivated()) { - debug_pad_lifo.entry_count = 0; - debug_pad_lifo.last_entry_index = 0; + debug_pad_lifo.buffer_count = 0; + debug_pad_lifo.buffer_tail = 0; std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 47760b4f8..00df50f32 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -31,8 +31,8 @@ Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(s Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; + gesture_lifo.buffer_count = 0; + gesture_lifo.buffer_tail = 0; force_update = true; } @@ -41,8 +41,8 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { if (!IsControllerActivated()) { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; + gesture_lifo.buffer_count = 0; + gesture_lifo.buffer_tail = 0; std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 632679a17..f4d49965f 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -27,8 +27,8 @@ void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { if (!IsControllerActivated()) { - keyboard_lifo.entry_count = 0; - keyboard_lifo.last_entry_index = 0; + keyboard_lifo.buffer_count = 0; + keyboard_lifo.buffer_tail = 0; std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 6d3bd0a2b..7ec75e8c8 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -24,11 +24,9 @@ void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - mouse_lifo.timestamp = core_timing.GetCPUTicks(); - if (!IsControllerActivated()) { - mouse_lifo.entry_count = 0; - mouse_lifo.last_entry_index = 0; + mouse_lifo.buffer_count = 0; + mouse_lifo.buffer_tail = 0; std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 9f84e20c2..9f82f872a 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -101,7 +101,8 @@ Controller_NPad::Controller_NPad(Core::System& system_, for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; controller.device = system.HIDCore().GetEmulatedControllerByIndex(i); - controller.vibration[Core::HID::DeviceIndex::LeftIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + controller.vibration[Core::HID::DeviceIndex::LeftIndex].latest_vibration_value = + DEFAULT_VIBRATION_VALUE; controller.vibration[Core::HID::DeviceIndex::RightIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; Core::HID::ControllerUpdateCallback engine_callback{ @@ -178,7 +179,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.footer_type = AppletFooterUiType::SwitchProController; + shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; break; case Core::HID::NpadType::Handheld: shared_memory.style_set.handheld.Assign(1); @@ -188,7 +189,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; + shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; case Core::HID::NpadType::JoyconDual: shared_memory.style_set.joycon_dual.Assign(1); @@ -198,7 +199,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.footer_type = AppletFooterUiType::JoyDual; + shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; break; case Core::HID::NpadType::JoyconLeft: shared_memory.style_set.joycon_left.Assign(1); @@ -206,7 +207,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_minus.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.footer_type = AppletFooterUiType::JoyLeftHorizontal; + shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; break; case Core::HID::NpadType::JoyconRight: shared_memory.style_set.joycon_right.Assign(1); @@ -214,7 +215,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.footer_type = AppletFooterUiType::JoyRightHorizontal; + shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; break; case Core::HID::NpadType::GameCube: shared_memory.style_set.gamecube.Assign(1); @@ -919,7 +920,7 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { .right = {}, }; shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory_entry.footer_type = AppletFooterUiType::None; + shared_memory_entry.applet_footer.type = AppletFooterUiType::None; controller.is_connected = false; controller.device->Disconnect(); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 0a2dc6992..af4934c55 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -330,10 +330,43 @@ private: BitField<13, 1, s32> handheld_lark_nes_left; BitField<14, 1, s32> handheld_lark_nes_right; BitField<15, 1, s32> lucia; + BitField<16, 1, s32> lagon; + BitField<17, 1, s32> lager; BitField<31, 1, s32> system; }; }; + // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl + struct NfcXcdDeviceHandleStateImpl { + u64 handle; + bool is_available; + bool is_activated; + INSERT_PADDING_BYTES(0x6); // Reserved + u64 sampling_number; + }; + static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, + "NfcXcdDeviceHandleStateImpl is an invalid size"); + + // nn::hid::detail::NfcXcdDeviceHandleStateImplAtomicStorage + struct NfcXcdDeviceHandleStateImplAtomicStorage { + u64 sampling_number; + NfcXcdDeviceHandleStateImpl nfc_xcd_device_handle_state; + }; + static_assert(sizeof(NfcXcdDeviceHandleStateImplAtomicStorage) == 0x20, + "NfcXcdDeviceHandleStateImplAtomicStorage is an invalid size"); + + // This is nn::hid::detail::NfcXcdDeviceHandleState + struct NfcXcdDeviceHandleState { + // TODO(german77): Make this struct a ring lifo object + INSERT_PADDING_BYTES(0x8); // Unused + s64 total_buffer_count = max_buffer_size; + s64 buffer_tail{}; + s64 buffer_count{}; + std::array nfc_xcd_device_handle_storage; + }; + static_assert(sizeof(NfcXcdDeviceHandleState) == 0x60, + "NfcXcdDeviceHandleState is an invalid size"); + // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); @@ -365,6 +398,14 @@ private: Lagon = 21, }; + struct AppletFooterUi { + AppletFooterUiAttributes attributes; + AppletFooterUiType type; + INSERT_PADDING_BYTES(0x5B); // Reserved + }; + static_assert(sizeof(AppletFooterUi) == 0x60, + "AppletFooterUi is an invalid size"); + // This is nn::hid::NpadLarkType enum class NpadLarkType : u32 { Invalid, @@ -382,6 +423,11 @@ private: U, }; + // This is nn::hid::NpadLagonType + enum class NpadLagonType : u32 { + Invalid, + }; + // This is nn::hid::NpadLagerType enum class NpadLagerType : u32 { Invalid, @@ -416,17 +462,19 @@ private: Core::HID::BatteryLevel battery_level_dual; Core::HID::BatteryLevel battery_level_left; Core::HID::BatteryLevel battery_level_right; - AppletFooterUiAttributes footer_attributes; - AppletFooterUiType footer_type; - // GetXcdHandleForNpadWithNfc needs to be checked switchbrew doesn't match with HW - INSERT_PADDING_BYTES(0x78); // Unknown + union { + NfcXcdDeviceHandleState nfc_xcd_device_handle; + AppletFooterUi applet_footer; + }; + INSERT_PADDING_BYTES(0x20); // Unknown Lifo gc_trigger_lifo; - NpadLarkType lark_type_l; + NpadLarkType lark_type_l_and_main; NpadLarkType lark_type_r; NpadLuciaType lucia_type; + NpadLagonType lagon_type; NpadLagerType lager_type; INSERT_PADDING_BYTES( - 0x8); // FW 13.x Investigate there is some sort of bitflag related to joycons + 0x4); // FW 13.x Investigate there is some sort of bitflag related to joycons INSERT_PADDING_BYTES(0xc08); // Unknown }; static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 5ba8d96a8..9ae2bf2b1 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -30,8 +30,8 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); if (!IsControllerActivated()) { - touch_screen_lifo.entry_count = 0; - touch_screen_lifo.last_entry_index = 0; + touch_screen_lifo.buffer_count = 0; + touch_screen_lifo.buffer_tail = 0; std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); return; } diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index aa9f044f1..a2ed1e7c2 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -20,8 +20,8 @@ void Controller_XPad::OnRelease() {} void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { if (!IsControllerActivated()) { - basic_xpad_lifo.entry_count = 0; - basic_xpad_lifo.last_entry_index = 0; + basic_xpad_lifo.buffer_count = 0; + basic_xpad_lifo.buffer_tail = 0; std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); return; } diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index f68d82762..382350a2d 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -8,7 +8,7 @@ #include "common/swap.h" namespace Service::HID { -constexpr std::size_t max_entry_size = 17; +constexpr std::size_t max_buffer_size = 17; template struct AtomicStorage { @@ -19,13 +19,13 @@ struct AtomicStorage { template struct Lifo { s64 timestamp{}; - s64 total_entry_count = max_entry_size; - s64 last_entry_index{}; - s64 entry_count{}; - std::array, max_entry_size> entries{}; + s64 total_buffer_count = max_buffer_size; + s64 buffer_tail{}; + s64 buffer_count{}; + std::array, max_buffer_size> entries{}; const AtomicStorage& ReadCurrentEntry() const { - return entries[last_entry_index]; + return entries[buffer_tail]; } const AtomicStorage& ReadPreviousEntry() const { @@ -33,21 +33,21 @@ struct Lifo { } std::size_t GetPreviuousEntryIndex() const { - return (last_entry_index + total_entry_count - 1) % total_entry_count; + return (buffer_tail + total_buffer_count - 1) % total_buffer_count; } std::size_t GetNextEntryIndex() const { - return (last_entry_index + 1) % total_entry_count; + return (buffer_tail + 1) % total_buffer_count; } void WriteNextEntry(const State& new_state) { - if (entry_count < total_entry_count - 1) { - entry_count++; + if (buffer_count < total_buffer_count - 1) { + buffer_count++; } - last_entry_index = GetNextEntryIndex(); + buffer_tail = GetNextEntryIndex(); const auto& previous_entry = ReadPreviousEntry(); - entries[last_entry_index].sampling_number = previous_entry.sampling_number + 1; - entries[last_entry_index].state = new_state; + entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1; + entries[buffer_tail].state = new_state; } }; From d8e3f2b10bad7e4a0ae09c90c76e8a1927c3d1ab Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 11:20:47 -0500 Subject: [PATCH 105/291] input_common: Fix GC adapter initialization Fix GC controller --- src/input_common/drivers/gc_adapter.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 25b66f528..62dc28711 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -73,7 +73,7 @@ GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine if (usb_adapter_handle) { return; } - LOG_INFO(Input, "GC Adapter Initialization started"); + LOG_DEBUG(Input, "Initialization started"); libusb_ctx = std::make_unique(); const int init_res = libusb_ctx->InitResult(); @@ -90,7 +90,7 @@ GCAdapter::~GCAdapter() { } void GCAdapter::AdapterInputThread(std::stop_token stop_token) { - LOG_DEBUG(Input, "GC Adapter input thread started"); + LOG_DEBUG(Input, "Input thread started"); Common::SetCurrentThreadName("yuzu:input:GCAdapter"); s32 payload_size{}; AdapterPayload adapter_payload{}; @@ -120,7 +120,7 @@ bool GCAdapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payl LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size, adapter_payload[0]); if (input_error_counter++ > 20) { - LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); + LOG_ERROR(Input, "Timeout, Is the adapter connected?"); adapter_input_thread.request_stop(); restart_scan_thread = true; } @@ -263,13 +263,6 @@ bool GCAdapter::Setup() { } bool GCAdapter::CheckDeviceAccess() { - // This fixes payload problems from offbrand GCAdapters - const s32 control_transfer_error = - libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); - if (control_transfer_error < 0) { - LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); - } - s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle->get(), 0); if (kernel_driver_error == 1) { kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle->get(), 0); @@ -291,6 +284,13 @@ bool GCAdapter::CheckDeviceAccess() { return false; } + // This fixes payload problems from offbrand GCAdapters + const s32 control_transfer_error = + libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); + if (control_transfer_error < 0) { + LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); + } + return true; } @@ -370,9 +370,9 @@ void GCAdapter::SendVibrations() { libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, payload.data(), static_cast(payload.size()), &size, 16); if (err) { - LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); + LOG_DEBUG(Input, "Libusb write failed: {}", libusb_error_name(err)); if (output_error_counter++ > 5) { - LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); + LOG_ERROR(Input, "Output timeout, Rumble disabled"); rumble_enabled = false; } return; From 5f69fdbfccdf68ddb5bb22de32321fa352b22c0a Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 12:12:52 -0500 Subject: [PATCH 106/291] core/hid: Explain better what a temporary value does --- src/core/hid/emulated_controller.cpp | 38 +++++++++++++++------------- src/core/hid/emulated_controller.h | 14 +++++----- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 2b051ccaf..3c3fa16d6 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -88,8 +88,9 @@ void EmulatedController::ReloadFromSettings() { ReloadInput(); } void EmulatedController::LoadDevices() { - const auto left_joycon = button_params[Settings::NativeButton::ZL]; - const auto right_joycon = button_params[Settings::NativeButton::ZR]; + // TODO(german77): Use more buttons to detect the correct device + const auto left_joycon = button_params[Settings::NativeButton::A]; + const auto right_joycon = button_params[Settings::NativeButton::DRight]; // Triggers for GC controllers trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; @@ -142,6 +143,7 @@ void EmulatedController::LoadTASParams() { param = common_params; } + // TODO(german77): Replace this with an input profile or something better tas_button_params[Settings::NativeButton::A].Set("button", 1 << 0); tas_button_params[Settings::NativeButton::B].Set("button", 1 << 1); tas_button_params[Settings::NativeButton::X].Set("button", 1 << 2); @@ -271,24 +273,24 @@ void EmulatedController::UnloadInput() { void EmulatedController::EnableConfiguration() { is_configuring = true; - temporary_is_connected = is_connected; - temporary_npad_type = npad_type; + tmp_is_connected = is_connected; + tmp_npad_type = npad_type; } void EmulatedController::DisableConfiguration() { is_configuring = false; // Apply temporary npad type to the real controller - if (temporary_npad_type != npad_type) { + if (tmp_npad_type != npad_type) { if (is_connected) { Disconnect(); } - SetNpadType(temporary_npad_type); + SetNpadType(tmp_npad_type); } // Apply temporary connected status to the real controller - if (temporary_is_connected != is_connected) { - if (temporary_is_connected) { + if (tmp_is_connected != is_connected) { + if (tmp_is_connected) { Connect(); return; } @@ -791,7 +793,7 @@ void EmulatedController::Connect() { { std::lock_guard lock{mutex}; if (is_configuring) { - temporary_is_connected = true; + tmp_is_connected = true; TriggerOnChange(ControllerTriggerType::Connected, false); return; } @@ -808,7 +810,7 @@ void EmulatedController::Disconnect() { { std::lock_guard lock{mutex}; if (is_configuring) { - temporary_is_connected = false; + tmp_is_connected = false; TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } @@ -821,9 +823,9 @@ void EmulatedController::Disconnect() { TriggerOnChange(ControllerTriggerType::Disconnected, true); } -bool EmulatedController::IsConnected(bool temporary) const { - if (temporary) { - return temporary_is_connected; +bool EmulatedController::IsConnected(bool get_temporary_value) const { + if (get_temporary_value) { + return tmp_is_connected; } return is_connected; } @@ -838,9 +840,9 @@ NpadIdType EmulatedController::GetNpadIdType() const { return npad_id_type; } -NpadType EmulatedController::GetNpadType(bool temporary) const { - if (temporary) { - return temporary_npad_type; +NpadType EmulatedController::GetNpadType(bool get_temporary_value) const { + if (get_temporary_value) { + return tmp_npad_type; } return npad_type; } @@ -850,10 +852,10 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { std::lock_guard lock{mutex}; if (is_configuring) { - if (temporary_npad_type == npad_type_) { + if (tmp_npad_type == npad_type_) { return; } - temporary_npad_type = npad_type_; + tmp_npad_type = npad_type_; TriggerOnChange(ControllerTriggerType::Type, false); return; } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index eec51e34a..fea401365 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -149,10 +149,10 @@ public: /** * Gets the NpadType for this controller - * @param Returns the temporary value if true + * @param If true tmp_npad_type will be returned * @return NpadType set on the controller */ - NpadType GetNpadType(bool temporary = false) const; + NpadType GetNpadType(bool get_temporary_value = false) const; /// Sets the connected status to true void Connect(); @@ -162,10 +162,10 @@ public: /** * Is the emulated connected - * @param Returns the temporary value if true + * @param If true tmp_is_connected will be returned * @return true if the controller has the connected status */ - bool IsConnected(bool temporary = false) const; + bool IsConnected(bool get_temporary_value = false) const; /// Returns true if vibration is enabled bool IsVibrationEnabled() const; @@ -346,12 +346,14 @@ private: NpadIdType npad_id_type; NpadType npad_type{NpadType::None}; - NpadType temporary_npad_type{NpadType::None}; bool is_connected{false}; - bool temporary_is_connected{false}; bool is_configuring{false}; f32 motion_sensitivity{0.01f}; + // Temporary values to avoid doing changes while the controller is on configuration mode + NpadType tmp_npad_type{NpadType::None}; + bool tmp_is_connected{false}; + ButtonParams button_params; StickParams stick_params; ControllerMotionParams motion_params; From 61d9eb9f690d6afe141f24ba75c99b54e122dfa3 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 20:16:10 -0500 Subject: [PATCH 107/291] input_common: Revert deleted TAS functions --- src/core/hid/emulated_controller.cpp | 44 +++++++++---------- src/input_common/drivers/tas_input.cpp | 23 +++++----- src/input_common/drivers/tas_input.h | 14 +++--- src/yuzu/bootmanager.cpp | 1 + src/yuzu/debugger/controller.cpp | 60 ++++++++++++++++++++++++-- src/yuzu/debugger/controller.h | 26 +++++++++-- src/yuzu/main.cpp | 2 +- 7 files changed, 122 insertions(+), 48 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 3c3fa16d6..69568f4e9 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -127,7 +127,7 @@ void EmulatedController::LoadDevices() { // Initialize TAS devices std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), Input::CreateDevice); - std::transform(tas_stick_params.begin(), tas_stick_params.begin(), tas_stick_devices.begin(), + std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), Input::CreateDevice); } @@ -135,7 +135,7 @@ void EmulatedController::LoadTASParams() { const auto player_index = NpadIdTypeToIndex(npad_id_type); Common::ParamPackage common_params{}; common_params.Set("engine", "tas"); - common_params.Set("pad", static_cast(player_index)); + common_params.Set("port", static_cast(player_index)); for (auto& param : tas_button_params) { param = common_params; } @@ -144,26 +144,26 @@ void EmulatedController::LoadTASParams() { } // TODO(german77): Replace this with an input profile or something better - tas_button_params[Settings::NativeButton::A].Set("button", 1 << 0); - tas_button_params[Settings::NativeButton::B].Set("button", 1 << 1); - tas_button_params[Settings::NativeButton::X].Set("button", 1 << 2); - tas_button_params[Settings::NativeButton::Y].Set("button", 1 << 3); - tas_button_params[Settings::NativeButton::LStick].Set("button", 1 << 4); - tas_button_params[Settings::NativeButton::RStick].Set("button", 1 << 5); - tas_button_params[Settings::NativeButton::L].Set("button", 1 << 6); - tas_button_params[Settings::NativeButton::R].Set("button", 1 << 7); - tas_button_params[Settings::NativeButton::ZL].Set("button", 1 << 8); - tas_button_params[Settings::NativeButton::ZR].Set("button", 1 << 9); - tas_button_params[Settings::NativeButton::Plus].Set("button", 1 << 10); - tas_button_params[Settings::NativeButton::Minus].Set("button", 1 << 11); - tas_button_params[Settings::NativeButton::DLeft].Set("button", 1 << 12); - tas_button_params[Settings::NativeButton::DUp].Set("button", 1 << 13); - tas_button_params[Settings::NativeButton::DRight].Set("button", 1 << 14); - tas_button_params[Settings::NativeButton::DDown].Set("button", 1 << 15); - tas_button_params[Settings::NativeButton::SL].Set("button", 1 << 16); - tas_button_params[Settings::NativeButton::SR].Set("button", 1 << 17); - tas_button_params[Settings::NativeButton::Home].Set("button", 1 << 18); - tas_button_params[Settings::NativeButton::Screenshot].Set("button", 1 << 19); + tas_button_params[Settings::NativeButton::A].Set("button", 0); + tas_button_params[Settings::NativeButton::B].Set("button", 1); + tas_button_params[Settings::NativeButton::X].Set("button", 2); + tas_button_params[Settings::NativeButton::Y].Set("button", 3); + tas_button_params[Settings::NativeButton::LStick].Set("button", 4); + tas_button_params[Settings::NativeButton::RStick].Set("button", 5); + tas_button_params[Settings::NativeButton::L].Set("button", 6); + tas_button_params[Settings::NativeButton::R].Set("button", 7); + tas_button_params[Settings::NativeButton::ZL].Set("button", 8); + tas_button_params[Settings::NativeButton::ZR].Set("button", 9); + tas_button_params[Settings::NativeButton::Plus].Set("button", 10); + tas_button_params[Settings::NativeButton::Minus].Set("button", 11); + tas_button_params[Settings::NativeButton::DLeft].Set("button", 12); + 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::Home].Set("button", 18); + tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19); tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 7e7a1d58f..d2748b240 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -141,7 +141,7 @@ void Tas::WriteTasFile(std::u8string file_name) { } } -void Tas::RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis) { +void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) { last_input = { .buttons = buttons, .l_axis = FlipAxisY(left_axis), @@ -195,7 +195,7 @@ void Tas::UpdateThread() { } if (current_command < script_length) { LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); - size_t frame = current_command++; + const size_t frame = current_command++; for (size_t player_index = 0; player_index < commands.size(); player_index++) { TASCommand command{}; if (frame < commands[player_index].size()) { @@ -207,8 +207,8 @@ void Tas::UpdateThread() { .port = player_index, .pad = 0, }; - for (std::size_t i = 0; i < sizeof(command.buttons); ++i) { - const bool button_status = (command.buttons & (1U << i)) != 0; + for (std::size_t i = 0; i < sizeof(command.buttons) * 8; ++i) { + const bool button_status = (command.buttons & (1LLU << i)) != 0; const int button = static_cast(i); SetButton(identifier, button, button_status); } @@ -244,14 +244,14 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { return {x, y}; } -u32 Tas::ReadCommandButtons(const std::string& data) const { +u64 Tas::ReadCommandButtons(const std::string& data) const { std::stringstream button_text(data); std::string line; - u32 buttons = 0; + u64 buttons = 0; while (std::getline(button_text, line, ';')) { for (auto [text, tas_button] : text_to_tas_button) { if (text == line) { - buttons |= static_cast(tas_button); + buttons |= static_cast(tas_button); break; } } @@ -259,13 +259,14 @@ u32 Tas::ReadCommandButtons(const std::string& data) const { return buttons; } -std::string Tas::WriteCommandButtons(u32 buttons) const { +std::string Tas::WriteCommandButtons(u64 buttons) const { std::string returns = ""; for (auto [text_button, tas_button] : text_to_tas_button) { - if ((buttons & static_cast(tas_button)) != 0) - returns += fmt::format("{};", text_button.substr(4)); + if ((buttons & static_cast(tas_button)) != 0) { + returns += fmt::format("{};", text_button); + } } - return returns.empty() ? "NONE" : returns.substr(2); + return returns.empty() ? "NONE" : returns; } std::string Tas::WriteCommandAxis(TasAnalog analog) const { diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 9fadc118b..5f5c3267c 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -47,7 +47,7 @@ namespace InputCommon::TasInput { constexpr size_t PLAYER_NUMBER = 10; -enum class TasButton : u32 { +enum class TasButton : u64 { BUTTON_A = 1U << 0, BUTTON_B = 1U << 1, BUTTON_X = 1U << 2, @@ -92,7 +92,7 @@ public: * @param left_axis: value of the left axis * @param right_axis: value of the right axis */ - void RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis); + void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); // Main loop that records or executes input void UpdateThread(); @@ -129,7 +129,7 @@ public: private: struct TASCommand { - u32 buttons{}; + u64 buttons{}; TasAnalog l_axis{}; TasAnalog r_axis{}; }; @@ -164,9 +164,9 @@ private: * Parses a string containing the button values. Each button is represented by it's text format * specified in text_to_tas_button array * @param line: string containing button name with the following format "a;b;c;d..." - * @return Returns a u32 with each bit representing the status of a button + * @return Returns a u64 with each bit representing the status of a button */ - u32 ReadCommandButtons(const std::string& line) const; + u64 ReadCommandButtons(const std::string& line) const; /** * Reset state of all players @@ -174,11 +174,11 @@ private: void ClearInput(); /** - * Converts an u32 containing the button status into the text equivalent + * Converts an u64 containing the button status into the text equivalent * @param buttons: bitfield with the status of the buttons * @return Returns a string with the name of the buttons to be written to the file */ - std::string WriteCommandButtons(u32 buttons) const; + std::string WriteCommandButtons(u64 buttons) const; /** * Converts an TAS analog object containing the axis status into the text equivalent diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 726f789b7..4b3cd9f3e 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -35,6 +35,7 @@ #include "core/frontend/framebuffer_layout.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" +#include "input_common/drivers/tas_input.h" #include "input_common/drivers/touch_screen.h" #include "input_common/main.h" #include "video_core/renderer_base.h" diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index f93a46421..aaca494b8 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -7,11 +7,16 @@ #include #include "common/settings.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "input_common/drivers/tas_input.h" +#include "input_common/main.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) - : QWidget(parent, Qt::Dialog) { +ControllerDialog::ControllerDialog(Core::System& system_, + std::shared_ptr input_subsystem_, + QWidget* parent) + : QWidget(parent, Qt::Dialog), system{system_}, input_subsystem{input_subsystem_} { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -21,7 +26,7 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1)); + refreshConfiguration(); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(widget); @@ -34,6 +39,22 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) widget->setFocus(); } +void ControllerDialog::refreshConfiguration() { + UnloadController(); + auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + // Display the correct controller + controller = handheld->IsConnected() ? handheld : player_1; + + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, + .is_npad_service = true, + }; + callback_key = controller->SetCallback(engine_callback); + widget->SetController(controller); + is_controller_set = true; +} + QAction* ControllerDialog::toggleViewAction() { if (toggle_view_action == nullptr) { toggle_view_action = new QAction(tr("&Controller P1"), this); @@ -47,6 +68,10 @@ QAction* ControllerDialog::toggleViewAction() { void ControllerDialog::UnloadController() { widget->UnloadController(); + if (is_controller_set) { + controller->DeleteCallback(callback_key); + is_controller_set = false; + } } void ControllerDialog::showEvent(QShowEvent* ev) { @@ -62,3 +87,32 @@ void ControllerDialog::hideEvent(QHideEvent* ev) { } QWidget::hideEvent(ev); } + +void ControllerDialog::ControllerUpdate(Core::HID::ControllerTriggerType type) { + // TODO(german77): Remove TAS from here + switch (type) { + case Core::HID::ControllerTriggerType::Button: + case Core::HID::ControllerTriggerType::Stick: { + const auto buttons_values = controller->GetButtonsValues(); + const auto stick_values = controller->GetSticksValues(); + u64 buttons = 0; + std::size_t index = 0; + for (const auto& button : buttons_values) { + buttons |= button.value ? 1LLU << index : 0; + index++; + } + const InputCommon::TasInput::TasAnalog left_axis = { + .x = stick_values[Settings::NativeAnalog::LStick].x.value, + .y = stick_values[Settings::NativeAnalog::LStick].y.value, + }; + const InputCommon::TasInput::TasAnalog right_axis = { + .x = stick_values[Settings::NativeAnalog::RStick].x.value, + .y = stick_values[Settings::NativeAnalog::RStick].y.value, + }; + input_subsystem->GetTas()->RecordInput(buttons, left_axis, right_axis); + break; + } + default: + break; + } +} diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 33f617b9b..ba4185a4b 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -11,24 +11,33 @@ class QHideEvent; class QShowEvent; class PlayerControlPreview; +namespace InputCommon { +class InputSubsystem; +} + namespace Core { class System; } -namespace InputCommon { -class InputSubsystem; +namespace Core::HID { +class EmulatedController; } class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(Core::System& system, QWidget* parent = nullptr); + explicit ControllerDialog(Core::System& system_, + std::shared_ptr input_subsystem_, + QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); - // Disables events from the emulated controller + /// Reloads the widget to apply any changes in the configuration + void refreshConfiguration(); + + /// Disables events from the emulated controller void UnloadController(); protected: @@ -36,6 +45,15 @@ protected: void hideEvent(QHideEvent* ev) override; private: + /// Redirects input from the widget to the TAS driver + void ControllerUpdate(Core::HID::ControllerTriggerType type); + + int callback_key; + bool is_controller_set{}; + Core::HID::EmulatedController* controller; + QAction* toggle_view_action = nullptr; PlayerControlPreview* widget; + Core::System& system; + std::shared_ptr input_subsystem; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 022d11cc4..56db337a4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -925,7 +925,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(*system, this); + controller_dialog = new ControllerDialog(*system, input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); From 2b1b0c2a30e242b08ec120e09803ec54d5445703 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 22:23:10 -0500 Subject: [PATCH 108/291] kraken: Address comments from review start lion review --- src/common/input.h | 4 +- src/common/settings.h | 1 - src/core/hid/emulated_console.cpp | 17 +- src/core/hid/emulated_console.h | 15 +- src/core/hid/emulated_controller.cpp | 88 ++++---- src/core/hid/emulated_controller.h | 42 ++-- src/core/hid/emulated_devices.cpp | 37 ++-- src/core/hid/emulated_devices.h | 28 +-- src/core/hid/input_converter.cpp | 75 +++---- src/core/hid/input_converter.h | 17 +- .../hle/service/hid/controllers/debug_pad.cpp | 3 - .../hle/service/hid/controllers/keyboard.cpp | 1 - src/core/hle/service/hid/controllers/npad.h | 3 +- src/core/hle/service/hid/ring_lifo.h | 6 +- src/input_common/drivers/gc_adapter.cpp | 10 +- src/input_common/drivers/gc_adapter.h | 7 +- src/input_common/drivers/keyboard.h | 2 +- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 16 +- src/input_common/drivers/sdl_driver.h | 7 +- src/input_common/drivers/touch_screen.h | 2 +- .../helpers/stick_from_buttons.cpp | 70 +++--- src/input_common/helpers/stick_from_buttons.h | 4 +- .../helpers/touch_from_buttons.cpp | 29 +-- src/input_common/helpers/touch_from_buttons.h | 4 +- src/input_common/input_engine.h | 14 +- src/input_common/input_poller.cpp | 202 +++++++++--------- src/input_common/input_poller.h | 32 +-- src/input_common/main.cpp | 76 ++++--- .../configure_input_player_widget.cpp | 105 ++++----- .../configure_input_player_widget.h | 81 +++---- 31 files changed, 534 insertions(+), 466 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index cb84f1005..6d3227f5e 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -12,7 +12,7 @@ #include "common/logging/log.h" #include "common/param_package.h" -namespace Input { +namespace Common::Input { enum class InputType { None, @@ -296,4 +296,4 @@ std::unique_ptr CreateDevice(const Common::ParamPackage package return pair->second->Create(package); } -} // namespace Input +} // namespace Common::Input diff --git a/src/common/settings.h b/src/common/settings.h index dac44d000..95225fba7 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index d1d4a5355..c259de0f1 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -55,21 +55,21 @@ void EmulatedConsole::SetTouchParams() { void EmulatedConsole::ReloadInput() { SetTouchParams(); - motion_devices = Input::CreateDevice(motion_params); + motion_devices = Common::Input::CreateDevice(motion_params); if (motion_devices) { - Input::InputCallback motion_callback{ - [this](Input::CallbackStatus callback) { SetMotion(callback); }}; + Common::Input::InputCallback motion_callback{ + [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; motion_devices->SetCallback(motion_callback); } std::size_t index = 0; for (auto& touch_device : touch_devices) { - touch_device = Input::CreateDevice(touch_params[index]); + touch_device = Common::Input::CreateDevice(touch_params[index]); if (!touch_device) { continue; } - Input::InputCallback touch_callback{ - [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; + Common::Input::InputCallback touch_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; touch_device->SetCallback(touch_callback); index++; } @@ -117,7 +117,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { ReloadInput(); } -void EmulatedConsole::SetMotion(Input::CallbackStatus callback) { +void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { std::lock_guard lock{mutex}; auto& raw_status = console.motion_values.raw_status; auto& emulated = console.motion_values.emulated; @@ -152,7 +152,8 @@ void EmulatedConsole::SetMotion(Input::CallbackStatus callback) { TriggerOnChange(ConsoleTriggerType::Motion); } -void EmulatedConsole::SetTouch(Input::CallbackStatus callback, [[maybe_unused]] std::size_t index) { +void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, + [[maybe_unused]] std::size_t index) { if (index >= console.touch_values.size()) { return; } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index f26f24f2e..9aec482a6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/point.h" @@ -20,18 +23,18 @@ namespace Core::HID { struct ConsoleMotionInfo { - Input::MotionStatus raw_status{}; + Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; }; -using ConsoleMotionDevices = std::unique_ptr; -using TouchDevices = std::array, 16>; +using ConsoleMotionDevices = std::unique_ptr; +using TouchDevices = std::array, 16>; using ConsoleMotionParams = Common::ParamPackage; using TouchParams = std::array; using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array; +using TouchValues = std::array; struct TouchFinger { u64 last_touch{}; @@ -151,14 +154,14 @@ private: * Updates the motion status of the console * @param A CallbackStatus containing gyro and accelerometer data */ - void SetMotion(Input::CallbackStatus callback); + void SetMotion(Common::Input::CallbackStatus callback); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the touch position * @param index: Finger ID to be updated */ - void SetTouch(Input::CallbackStatus callback, std::size_t index); + void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the console status diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 69568f4e9..49893cdbd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -110,25 +110,25 @@ void EmulatedController::LoadDevices() { std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, button_params.begin() + Settings::NativeButton::BUTTON_NS_END, - button_devices.begin(), Input::CreateDevice); + button_devices.begin(), Common::Input::CreateDevice); std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, stick_params.begin() + Settings::NativeAnalog::STICK_HID_END, - stick_devices.begin(), Input::CreateDevice); + stick_devices.begin(), Common::Input::CreateDevice); std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, - motion_devices.begin(), Input::CreateDevice); + motion_devices.begin(), Common::Input::CreateDevice); std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); // Initialize TAS devices std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); } void EmulatedController::LoadTASParams() { @@ -178,8 +178,8 @@ void EmulatedController::ReloadInput() { if (!button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; button_devices[index]->SetCallback(button_callback); button_devices[index]->ForceUpdate(); } @@ -188,8 +188,8 @@ void EmulatedController::ReloadInput() { if (!stick_devices[index]) { continue; } - Input::InputCallback stick_callback{ - [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + Common::Input::InputCallback stick_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; stick_devices[index]->SetCallback(stick_callback); stick_devices[index]->ForceUpdate(); } @@ -198,8 +198,8 @@ void EmulatedController::ReloadInput() { if (!trigger_devices[index]) { continue; } - Input::InputCallback trigger_callback{ - [this, index](Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + Common::Input::InputCallback trigger_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetTrigger(callback, index); }}; trigger_devices[index]->SetCallback(trigger_callback); trigger_devices[index]->ForceUpdate(); } @@ -208,8 +208,8 @@ void EmulatedController::ReloadInput() { if (!battery_devices[index]) { continue; } - Input::InputCallback battery_callback{ - [this, index](Input::CallbackStatus callback) { SetBattery(callback, index); }}; + Common::Input::InputCallback battery_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }}; battery_devices[index]->SetCallback(battery_callback); battery_devices[index]->ForceUpdate(); } @@ -218,8 +218,8 @@ void EmulatedController::ReloadInput() { if (!motion_devices[index]) { continue; } - Input::InputCallback motion_callback{ - [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; + Common::Input::InputCallback motion_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }}; motion_devices[index]->SetCallback(motion_callback); motion_devices[index]->ForceUpdate(); } @@ -229,8 +229,8 @@ void EmulatedController::ReloadInput() { if (!tas_button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; tas_button_devices[index]->SetCallback(button_callback); } @@ -238,8 +238,8 @@ void EmulatedController::ReloadInput() { if (!tas_stick_devices[index]) { continue; } - Input::InputCallback stick_callback{ - [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + Common::Input::InputCallback stick_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; tas_stick_devices[index]->SetCallback(stick_callback); } } @@ -418,7 +418,7 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage ReloadInput(); } -void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.button_values.size()) { return; } @@ -548,7 +548,7 @@ void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t i TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.stick_values.size()) { return; } @@ -587,7 +587,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.trigger_values.size()) { return; } @@ -618,7 +618,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t TriggerOnChange(ControllerTriggerType::Trigger, true); } -void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.motion_values.size()) { return; } @@ -655,7 +655,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i TriggerOnChange(ControllerTriggerType::Motion, true); } -void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.battery_values.size()) { return; } @@ -671,25 +671,25 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t bool is_powered = false; BatteryLevel battery_level = 0; switch (controller.battery_values[index]) { - case Input::BatteryLevel::Charging: + case Common::Input::BatteryLevel::Charging: is_charging = true; is_powered = true; battery_level = 6; break; - case Input::BatteryLevel::Medium: + case Common::Input::BatteryLevel::Medium: battery_level = 6; break; - case Input::BatteryLevel::Low: + case Common::Input::BatteryLevel::Low: battery_level = 4; break; - case Input::BatteryLevel::Critical: + case Common::Input::BatteryLevel::Critical: battery_level = 2; break; - case Input::BatteryLevel::Empty: + case Common::Input::BatteryLevel::Empty: battery_level = 0; break; - case Input::BatteryLevel::None: - case Input::BatteryLevel::Full: + case Common::Input::BatteryLevel::None: + case Common::Input::BatteryLevel::Full: default: is_powered = true; battery_level = 8; @@ -739,18 +739,19 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v // Exponential amplification is too strong at low amplitudes. Switch to a linear // amplification if strength is set below 0.7f - const Input::VibrationAmplificationType type = - strength > 0.7f ? Input::VibrationAmplificationType::Exponential - : Input::VibrationAmplificationType::Linear; + const Common::Input::VibrationAmplificationType type = + strength > 0.7f ? Common::Input::VibrationAmplificationType::Exponential + : Common::Input::VibrationAmplificationType::Linear; - const Input::VibrationStatus status = { + const Common::Input::VibrationStatus status = { .low_amplitude = std::min(vibration.low_amplitude * strength, 1.0f), .low_frequency = vibration.low_frequency, .high_amplitude = std::min(vibration.high_amplitude * strength, 1.0f), .high_frequency = vibration.high_frequency, .type = type, }; - return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; + return output_devices[device_index]->SetVibration(status) == + Common::Input::VibrationError::None; } bool EmulatedController::TestVibration(std::size_t device_index) { @@ -762,14 +763,15 @@ bool EmulatedController::TestVibration(std::size_t device_index) { } // Send a slight vibration to test for rumble support - constexpr Input::VibrationStatus status = { + constexpr Common::Input::VibrationStatus status = { .low_amplitude = 0.001f, .low_frequency = 160.0f, .high_amplitude = 0.001f, .high_frequency = 320.0f, - .type = Input::VibrationAmplificationType::Linear, + .type = Common::Input::VibrationAmplificationType::Linear, }; - return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; + return output_devices[device_index]->SetVibration(status) == + Common::Input::VibrationError::None; } void EmulatedController::SetLedPattern() { @@ -779,7 +781,7 @@ void EmulatedController::SetLedPattern() { } const LedPattern pattern = GetLedPattern(); - const Input::LedStatus status = { + const Common::Input::LedStatus status = { .led_1 = pattern.position1 != 0, .led_2 = pattern.position2 != 0, .led_3 = pattern.position3 != 0, diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fea401365..dd9a93364 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/point.h" @@ -20,20 +23,22 @@ namespace Core::HID { const std::size_t max_emulated_controllers = 2; struct ControllerMotionInfo { - Input::MotionStatus raw_status{}; + Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; }; using ButtonDevices = - std::array, Settings::NativeButton::NumButtons>; + std::array, Settings::NativeButton::NumButtons>; using StickDevices = - std::array, Settings::NativeAnalog::NumAnalogs>; + std::array, Settings::NativeAnalog::NumAnalogs>; using ControllerMotionDevices = - std::array, Settings::NativeMotion::NumMotions>; + std::array, Settings::NativeMotion::NumMotions>; using TriggerDevices = - std::array, Settings::NativeTrigger::NumTriggers>; -using BatteryDevices = std::array, max_emulated_controllers>; -using OutputDevices = std::array, max_emulated_controllers>; + std::array, Settings::NativeTrigger::NumTriggers>; +using BatteryDevices = + std::array, max_emulated_controllers>; +using OutputDevices = + std::array, max_emulated_controllers>; using ButtonParams = std::array; using StickParams = std::array; @@ -42,13 +47,14 @@ using TriggerParams = std::array; using OutputParams = std::array; -using ButtonValues = std::array; -using SticksValues = std::array; -using TriggerValues = std::array; +using ButtonValues = std::array; +using SticksValues = std::array; +using TriggerValues = + std::array; using ControllerMotionValues = std::array; -using ColorValues = std::array; -using BatteryValues = std::array; -using VibrationValues = std::array; +using ColorValues = std::array; +using BatteryValues = std::array; +using VibrationValues = std::array; struct AnalogSticks { AnalogStickState left{}; @@ -307,35 +313,35 @@ private: * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetButton(Input::CallbackStatus callback, std::size_t index); + void SetButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the analog stick status of the controller * @param callback: A CallbackStatus containing the analog stick status * @param index: stick ID of the to be updated */ - void SetStick(Input::CallbackStatus callback, std::size_t index); + void SetStick(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the trigger status of the controller * @param callback: A CallbackStatus containing the trigger status * @param index: trigger ID of the to be updated */ - void SetTrigger(Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the motion status of the controller * @param callback: A CallbackStatus containing gyro and accelerometer data * @param index: motion ID of the to be updated */ - void SetMotion(Input::CallbackStatus callback, std::size_t index); + void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the battery status of the controller * @param callback: A CallbackStatus containing the battery status * @param index: Button ID of the to be updated */ - void SetBattery(Input::CallbackStatus callback, std::size_t index); + void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the controller status diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index eb59c310c..c76a86b6c 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included +#include #include #include "core/hid/emulated_devices.h" @@ -25,21 +26,25 @@ void EmulatedDevices::ReloadFromSettings() { void EmulatedDevices::ReloadInput() { std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, - mouse_button_devices.begin(), Input::CreateDevice); + mouse_button_devices.begin(), + Common::Input::CreateDevice); std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_devices.begin(), Input::CreateDeviceFromString); + keyboard_devices.begin(), + Common::Input::CreateDeviceFromString); std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), keyboard_modifier_devices.begin(), - Input::CreateDeviceFromString); + Common::Input::CreateDeviceFromString); for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetMouseButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetMouseButton(callback, index); + }}; mouse_button_devices[index]->SetCallback(button_callback); } @@ -47,8 +52,10 @@ void EmulatedDevices::ReloadInput() { if (!keyboard_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetKeyboardButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetKeyboardButton(callback, index); + }}; keyboard_devices[index]->SetCallback(button_callback); } @@ -56,9 +63,10 @@ void EmulatedDevices::ReloadInput() { if (!keyboard_modifier_devices[index]) { continue; } - Input::InputCallback button_callback{[this, index](Input::CallbackStatus callback) { - SetKeyboardModifier(callback, index); - }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetKeyboardModifier(callback, index); + }}; keyboard_modifier_devices[index]->SetCallback(button_callback); } } @@ -122,7 +130,7 @@ void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackag ReloadInput(); } -void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { return; } @@ -170,7 +178,7 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { constexpr u8 KEYS_PER_BYTE = 8; auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; - const u8 mask = 1 << (key_index % KEYS_PER_BYTE); + const u8 mask = static_cast(1 << (key_index % KEYS_PER_BYTE)); if (status) { entry = entry | mask; } else { @@ -178,7 +186,8 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { } } -void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, + std::size_t index) { if (index >= device_status.keyboard_moddifier_values.size()) { return; } @@ -247,7 +256,7 @@ void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::s TriggerOnChange(DeviceTriggerType::KeyboardModdifier); } -void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.mouse_button_values.size()) { return; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 7ed95eac6..418b2f9b5 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/settings.h" @@ -16,21 +19,22 @@ namespace Core::HID { -using KeyboardDevices = - std::array, Settings::NativeKeyboard::NumKeyboardKeys>; -using KeyboardModifierDevices = - std::array, Settings::NativeKeyboard::NumKeyboardMods>; -using MouseButtonDevices = - std::array, Settings::NativeMouseButton::NumMouseButtons>; +using KeyboardDevices = std::array, + Settings::NativeKeyboard::NumKeyboardKeys>; +using KeyboardModifierDevices = std::array, + Settings::NativeKeyboard::NumKeyboardMods>; +using MouseButtonDevices = std::array, + Settings::NativeMouseButton::NumMouseButtons>; using MouseButtonParams = std::array; -using KeyboardValues = std::array; +using KeyboardValues = + std::array; using KeyboardModifierValues = - std::array; + std::array; using MouseButtonValues = - std::array; + std::array; struct MousePosition { s32 x; @@ -151,21 +155,21 @@ private: * @param callback: A CallbackStatus containing the key status * @param index: key ID to be updated */ - void SetKeyboardButton(Input::CallbackStatus callback, std::size_t index); + void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the modifier key status * @param index: modifier key ID to be updated */ - void SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index); + void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetMouseButton(Input::CallbackStatus callback, std::size_t index); + void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the device status diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index e2598f367..14204917e 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -9,35 +9,35 @@ namespace Core::HID { -Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { - Input::BatteryStatus battery{Input::BatteryStatus::None}; +Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) { + Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None}; switch (callback.type) { - case Input::InputType::Analog: - case Input::InputType::Trigger: { + case Common::Input::InputType::Analog: + case Common::Input::InputType::Trigger: { const auto value = TransformToTrigger(callback).analog.value; - battery = Input::BatteryLevel::Empty; + battery = Common::Input::BatteryLevel::Empty; if (value > 0.2f) { - battery = Input::BatteryLevel::Critical; + battery = Common::Input::BatteryLevel::Critical; } if (value > 0.4f) { - battery = Input::BatteryLevel::Low; + battery = Common::Input::BatteryLevel::Low; } if (value > 0.6f) { - battery = Input::BatteryLevel::Medium; + battery = Common::Input::BatteryLevel::Medium; } if (value > 0.8f) { - battery = Input::BatteryLevel::Full; + battery = Common::Input::BatteryLevel::Full; } if (value >= 1.0f) { - battery = Input::BatteryLevel::Charging; + battery = Common::Input::BatteryLevel::Charging; } break; } - case Input::InputType::Button: - battery = callback.button_status.value ? Input::BatteryLevel::Charging - : Input::BatteryLevel::Critical; + case Common::Input::InputType::Button: + battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging + : Common::Input::BatteryLevel::Critical; break; - case Input::InputType::Battery: + case Common::Input::InputType::Battery: battery = callback.battery_status; break; default: @@ -48,14 +48,14 @@ Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { return battery; } -Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) { - Input::ButtonStatus status{}; +Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) { + Common::Input::ButtonStatus status{}; switch (callback.type) { - case Input::InputType::Analog: - case Input::InputType::Trigger: + case Common::Input::InputType::Analog: + case Common::Input::InputType::Trigger: status.value = TransformToTrigger(callback).pressed; break; - case Input::InputType::Button: + case Common::Input::InputType::Button: status = callback.button_status; break; default: @@ -70,15 +70,15 @@ Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) { return status; } -Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { - Input::MotionStatus status{}; +Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) { + Common::Input::MotionStatus status{}; switch (callback.type) { - case Input::InputType::Button: { + case Common::Input::InputType::Button: { if (TransformToButton(callback).value) { std::random_device device; std::mt19937 gen(device()); std::uniform_int_distribution distribution(-1000, 1000); - Input::AnalogProperties properties{ + Common::Input::AnalogProperties properties{ .deadzone = 0.0, .range = 1.0f, .offset = 0.0, @@ -116,7 +116,7 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { } break; } - case Input::InputType::Motion: + case Common::Input::InputType::Motion: status = callback.motion_status; break; default: @@ -133,11 +133,11 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { return status; } -Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { - Input::StickStatus status{}; +Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) { + Common::Input::StickStatus status{}; switch (callback.type) { - case Input::InputType::Stick: + case Common::Input::InputType::Stick: status = callback.stick_status; break; default: @@ -160,11 +160,11 @@ Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { return status; } -Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) { - Input::TouchStatus status{}; +Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) { + Common::Input::TouchStatus status{}; switch (callback.type) { - case Input::InputType::Touch: + case Common::Input::InputType::Touch: status = callback.touch_status; break; default: @@ -192,22 +192,22 @@ Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) { return status; } -Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { - Input::TriggerStatus status{}; +Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) { + Common::Input::TriggerStatus status{}; float& raw_value = status.analog.raw_value; bool calculate_button_value = true; switch (callback.type) { - case Input::InputType::Analog: + case Common::Input::InputType::Analog: status.analog.properties = callback.analog_status.properties; raw_value = callback.analog_status.raw_value; break; - case Input::InputType::Button: + case Common::Input::InputType::Button: status.analog.properties.range = 1.0f; status.analog.properties.inverted = callback.button_status.inverted; raw_value = callback.button_status.value ? 1.0f : 0.0f; break; - case Input::InputType::Trigger: + case Common::Input::InputType::Trigger: status = callback.trigger_status; calculate_button_value = false; break; @@ -234,7 +234,7 @@ Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { return status; } -void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { +void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; float& value = analog.value; @@ -274,7 +274,8 @@ void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { } } -void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value) { +void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, + bool clamp_value) { const auto& properties_x = analog_x.properties; const auto& properties_y = analog_y.properties; float& raw_x = analog_x.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 3cc32e26a..b38e657b0 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -16,7 +16,7 @@ namespace Core::HID { * @param Supported callbacks: Analog, Battery, Trigger. * @return A valid BatteryStatus object. */ -Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback); +Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid button status. Applies invert properties to the output. @@ -24,7 +24,7 @@ Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback); * @param Supported callbacks: Analog, Button, Trigger. * @return A valid TouchStatus object. */ -Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback); +Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid motion status. @@ -32,7 +32,7 @@ Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback); * @param Supported callbacks: Motion. * @return A valid TouchStatus object. */ -Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback); +Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert @@ -41,7 +41,7 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback); * @param Supported callbacks: Stick. * @return A valid StickStatus object. */ -Input::StickStatus TransformToStick(const Input::CallbackStatus& callback); +Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid touch status. @@ -49,7 +49,7 @@ Input::StickStatus TransformToStick(const Input::CallbackStatus& callback); * @param Supported callbacks: Touch. * @return A valid TouchStatus object. */ -Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback); +Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and @@ -58,20 +58,21 @@ Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback); * @param Supported callbacks: Analog, Button, Trigger. * @return A valid TriggerStatus object. */ -Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback); +Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); /** * Converts raw analog data into a valid analog value * @param An analog object containing raw data and properties, bool that determines if the value * needs to be clamped between -1.0f and 1.0f. */ -void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value); +void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value); /** * Converts raw stick data into a valid stick value * @param Two analog objects containing raw data and properties, bool that determines if the value * needs to be clamped into the unit circle. */ -void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value); +void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, + bool clamp_value); } // namespace Core::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 345134357..b009ed086 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -13,9 +13,6 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -constexpr s32 HID_JOYSTICK_MAX = 0x7fff; -[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; -enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} { controller = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Other); diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index f4d49965f..60dc62f2c 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,7 +12,6 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -constexpr u8 KEYS_PER_BYTE = 8; Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} { emulated_devices = system.HIDCore().GetEmulatedDevices(); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index af4934c55..4a9c9cc1a 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -403,8 +403,7 @@ private: AppletFooterUiType type; INSERT_PADDING_BYTES(0x5B); // Reserved }; - static_assert(sizeof(AppletFooterUi) == 0x60, - "AppletFooterUi is an invalid size"); + static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); // This is nn::hid::NpadLarkType enum class NpadLarkType : u32 { diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 382350a2d..6209ed0d1 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "common/common_types.h" #include "common/swap.h" @@ -29,10 +31,10 @@ struct Lifo { } const AtomicStorage& ReadPreviousEntry() const { - return entries[GetPreviuousEntryIndex()]; + return entries[GetPreviousEntryIndex()]; } - std::size_t GetPreviuousEntryIndex() const { + std::size_t GetPreviousEntryIndex() const { return (buffer_tail + total_buffer_count - 1) % total_buffer_count; } diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 62dc28711..2550f8cba 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -248,7 +248,7 @@ bool GCAdapter::Setup() { std::size_t port = 0; for (GCController& pad : pads) { pad.identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = port++, .pad = 0, }; @@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) { +Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, + const Common::Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); @@ -334,9 +334,9 @@ Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, pads[identifier.port].rumble_amplitude = processed_amplitude; if (!rumble_enabled) { - return Input::VibrationError::Disabled; + return Common::Input::VibrationError::Disabled; } - return Input::VibrationError::None; + return Common::Input::VibrationError::None; } void GCAdapter::UpdateVibrations() { diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index b82e4803d..fba90352e 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -4,8 +4,11 @@ #pragma once +#include +#include #include #include +#include #include #include "input_common/input_engine.h" @@ -24,8 +27,8 @@ public: explicit GCAdapter(const std::string input_engine_); ~GCAdapter(); - Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + Common::Input::VibrationError SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index a3e0d8a61..58df15050 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -35,7 +35,7 @@ public: private: const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index d3178b1a9..cf0918409 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -63,7 +63,7 @@ private: void StopPanning(); const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 53e282ef3..1e3741e0f 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -92,7 +92,7 @@ public: return motion; } - bool RumblePlay(const Input::VibrationStatus vibration) { + bool RumblePlay(const Common::Input::VibrationStatus vibration) { constexpr u32 rumble_max_duration_ms = 1000; if (sdl_controller) { return SDL_GameControllerRumble( @@ -515,8 +515,8 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) { +Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, + const Common::Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { @@ -527,7 +527,7 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, f32 factor = 0.35f; // If vibration is set as a linear output use a flatter value - if (vibration.type == Input::VibrationAmplificationType::Linear) { + if (vibration.type == Common::Input::VibrationAmplificationType::Linear) { factor = 0.5f; } @@ -536,19 +536,19 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, factor = 1.0f; } - const Input::VibrationStatus new_vibration{ + const Common::Input::VibrationStatus new_vibration{ .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor), .low_frequency = vibration.low_frequency, .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor), .high_frequency = vibration.high_frequency, - .type = Input::VibrationAmplificationType::Exponential, + .type = Common::Input::VibrationAmplificationType::Exponential, }; if (!joystick->RumblePlay(new_vibration)) { - return Input::VibrationError::Unknown; + return Common::Input::VibrationError::Unknown; } - return Input::VibrationError::None; + return Common::Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index 1ff85f48d..b879df8ab 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -58,8 +58,8 @@ public: std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string direction_name) const override; - Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + Common::Input::VibrationError SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; private: void InitJoystick(int joystick_index); @@ -105,9 +105,6 @@ private: /// Returns true if the button is on the left joycon bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; - // Set to true if SDL supports game controller subsystem - bool has_gamecontroller = false; - /// Map of GUID of a list of corresponding virtual Joysticks std::unordered_map>> joystick_map; std::mutex joystick_map_mutex; diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 5fbb2f47f..d297d253c 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -41,7 +41,7 @@ public: private: const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 806a0e8bb..1d5948f79 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -10,25 +10,27 @@ namespace InputCommon { -class Stick final : public Input::InputDevice { +class Stick final : public Common::Input::InputDevice { public: - using Button = std::unique_ptr; + using Button = std::unique_ptr; Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, float modifier_scale_, float modifier_angle_) : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { - Input::InputCallback button_up_callback{ - [this](Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; - Input::InputCallback button_down_callback{ - [this](Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; - Input::InputCallback button_left_callback{ - [this](Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; - Input::InputCallback button_right_callback{ - [this](Input::CallbackStatus callback_) { UpdateRightButtonStatus(callback_); }}; - Input::InputCallback button_modifier_callback{ - [this](Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; + Common::Input::InputCallback button_up_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; + Common::Input::InputCallback button_down_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; + Common::Input::InputCallback button_left_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; + Common::Input::InputCallback button_right_callback{ + [this](Common::Input::CallbackStatus callback_) { + UpdateRightButtonStatus(callback_); + }}; + Common::Input::InputCallback button_modifier_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; up->SetCallback(button_up_callback); down->SetCallback(button_down_callback); left->SetCallback(button_left_callback); @@ -129,27 +131,27 @@ public: } } - void UpdateUpButtonStatus(Input::CallbackStatus button_callback) { + void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) { up_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateDownButtonStatus(Input::CallbackStatus button_callback) { + void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) { down_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateLeftButtonStatus(Input::CallbackStatus button_callback) { + void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) { left_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateRightButtonStatus(Input::CallbackStatus button_callback) { + void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) { right_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateModButtonStatus(Input::CallbackStatus button_callback) { + void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) { modifier_status = button_callback.button_status.value; UpdateStatus(); } @@ -193,8 +195,8 @@ public: } last_update = now; - Input::CallbackStatus status{ - .type = Input::InputType::Stick, + Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; TriggerOnChange(status); @@ -209,15 +211,15 @@ public: } void SoftUpdate() override { - Input::CallbackStatus status{ - .type = Input::InputType::Stick, + Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; TriggerOnChange(status); } - Input::StickStatus GetStatus() const { - Input::StickStatus status{}; + Common::Input::StickStatus GetStatus() const { + Common::Input::StickStatus status{}; status.x.properties = properties; status.y.properties = properties; if (Settings::values.emulate_analog_keyboard) { @@ -263,19 +265,23 @@ private: bool left_status; bool right_status; bool modifier_status; - const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; + const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); - auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); - auto left = Input::CreateDeviceFromString(params.Get("left", null_engine)); - auto right = - Input::CreateDeviceFromString(params.Get("right", null_engine)); - auto modifier = - Input::CreateDeviceFromString(params.Get("modifier", null_engine)); + auto up = Common::Input::CreateDeviceFromString( + params.Get("up", null_engine)); + auto down = Common::Input::CreateDeviceFromString( + params.Get("down", null_engine)); + auto left = Common::Input::CreateDeviceFromString( + params.Get("left", null_engine)); + auto right = Common::Input::CreateDeviceFromString( + params.Get("right", null_engine)); + auto modifier = Common::Input::CreateDeviceFromString( + params.Get("modifier", null_engine)); auto modifier_scale = params.Get("modifier_scale", 0.5f); auto modifier_angle = params.Get("modifier_angle", 5.5f); return std::make_unique(std::move(up), std::move(down), std::move(left), diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 82dff5ca8..437ace4f7 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -12,7 +12,7 @@ namespace InputCommon { * An analog device factory that takes direction button devices and combines them into a analog * device. */ -class StickFromButton final : public Input::Factory { +class StickFromButton final : public Common::Input::Factory { public: /** * Creates an analog device from direction button devices @@ -24,7 +24,7 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index bb2bad5b1..fee41cae3 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -9,22 +9,22 @@ namespace InputCommon { -class TouchFromButtonDevice final : public Input::InputDevice { +class TouchFromButtonDevice final : public Common::Input::InputDevice { public: - using Button = std::unique_ptr; + using Button = std::unique_ptr; TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_) : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { - Input::InputCallback button_up_callback{ - [this](Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; + Common::Input::InputCallback button_up_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; button->SetCallback(button_up_callback); button->ForceUpdate(); } - Input::TouchStatus GetStatus(bool pressed) const { - const Input::ButtonStatus button_status{ + Common::Input::TouchStatus GetStatus(bool pressed) const { + const Common::Input::ButtonStatus button_status{ .value = pressed, }; - Input::TouchStatus status{ + Common::Input::TouchStatus status{ .pressed = button_status, .x = {}, .y = {}, @@ -42,9 +42,9 @@ public: return status; } - void UpdateButtonStatus(Input::CallbackStatus button_callback) { - const Input::CallbackStatus status{ - .type = Input::InputType::Touch, + void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) { + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Touch, .touch_status = GetStatus(button_callback.button_status.value), }; TriggerOnChange(status); @@ -55,13 +55,14 @@ private: const u32 touch_id; const float x; const float y; - const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; + const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; -std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr TouchFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto button = - Input::CreateDeviceFromString(params.Get("button", null_engine)); + auto button = Common::Input::CreateDeviceFromString( + params.Get("button", null_engine)); const auto touch_id = params.Get("touch_id", 0); const float x = params.Get("x", 0.0f) / 1280.0f; const float y = params.Get("y", 0.0f) / 720.0f; diff --git a/src/input_common/helpers/touch_from_buttons.h b/src/input_common/helpers/touch_from_buttons.h index 21b353728..628f18215 100644 --- a/src/input_common/helpers/touch_from_buttons.h +++ b/src/input_common/helpers/touch_from_buttons.h @@ -11,12 +11,12 @@ namespace InputCommon { /** * A touch device factory that takes a list of button devices and combines them into a touch device. */ -class TouchFromButton final : public Input::Factory { +class TouchFromButton final : public Common::Input::Factory { public: /** * Creates a touch device from a list of button devices */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 31ce900d7..ed79d3d93 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -116,22 +116,22 @@ public: // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::LedStatus led_status) { + [[maybe_unused]] const Common::Input::LedStatus led_status) { return; } // Sets rumble to a controller - virtual Input::VibrationError SetRumble( + virtual Common::Input::VibrationError SetRumble( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { - return Input::VibrationError::NotSupported; + [[maybe_unused]] const Common::Input::VibrationStatus vibration) { + return Common::Input::VibrationError::NotSupported; } // Sets polling mode to a controller - virtual Input::PollingError SetPollingMode( + virtual Common::Input::PollingError SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::PollingMode vibration) { - return Input::PollingError::NotSupported; + [[maybe_unused]] const Common::Input::PollingMode vibration) { + return Common::Input::PollingError::NotSupported; } // Returns the engine name diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 6edb8d900..2b3b77938 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -10,13 +10,13 @@ namespace InputCommon { -class DummyInput final : public Input::InputDevice { +class DummyInput final : public Common::Input::InputDevice { public: explicit DummyInput() {} ~DummyInput() {} }; -class InputFromButton final : public Input::InputDevice { +class InputFromButton final : public Common::Input::InputDevice { public: explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, InputEngine* input_engine_) @@ -37,7 +37,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::ButtonStatus GetStatus() const { + Common::Input::ButtonStatus GetStatus() const { return { .value = input_engine->GetButton(identifier, button), .inverted = inverted, @@ -46,8 +46,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -56,8 +56,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -77,7 +77,7 @@ private: InputEngine* input_engine; }; -class InputFromHatButton final : public Input::InputDevice { +class InputFromHatButton final : public Common::Input::InputDevice { public: explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_, bool inverted_, InputEngine* input_engine_) @@ -98,7 +98,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::ButtonStatus GetStatus() const { + Common::Input::ButtonStatus GetStatus() const { return { .value = input_engine->GetHatButton(identifier, button, direction), .inverted = inverted, @@ -107,8 +107,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -117,8 +117,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -139,11 +139,12 @@ private: InputEngine* input_engine; }; -class InputFromStick final : public Input::InputDevice { +class InputFromStick final : public Common::Input::InputDevice { public: explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), properties_y(properties_y_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -170,8 +171,8 @@ public: input_engine->DeleteCallback(callback_key_y); } - Input::StickStatus GetStatus() const { - Input::StickStatus status; + Common::Input::StickStatus GetStatus() const { + Common::Input::StickStatus status; status.x = { .raw_value = input_engine->GetAxis(identifier, axis_x), .properties = properties_x, @@ -184,8 +185,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Stick, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; @@ -195,8 +196,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Stick, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; @@ -212,8 +213,8 @@ private: const PadIdentifier identifier; const u32 axis_x; const u32 axis_y; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; int callback_key_x; int callback_key_y; float last_axis_x_value; @@ -221,12 +222,13 @@ private: InputEngine* input_engine; }; -class InputFromTouch final : public Input::InputDevice { +class InputFromTouch final : public Common::Input::InputDevice { public: explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_, bool inverted_, u32 axis_x_, u32 axis_y_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + InputEngine* input_engine_) : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), properties_y(properties_y_), input_engine(input_engine_) { @@ -263,8 +265,8 @@ public: input_engine->DeleteCallback(callback_key_y); } - Input::TouchStatus GetStatus() const { - Input::TouchStatus status; + Common::Input::TouchStatus GetStatus() const { + Common::Input::TouchStatus status; status.id = touch_id; status.pressed = { .value = input_engine->GetButton(identifier, button), @@ -283,8 +285,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Touch, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Touch, .touch_status = GetStatus(), }; @@ -306,8 +308,8 @@ private: const bool inverted; const u32 axis_x; const u32 axis_y; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; int callback_key_button; int callback_key_x; int callback_key_y; @@ -317,10 +319,10 @@ private: InputEngine* input_engine; }; -class InputFromTrigger final : public Input::InputDevice { +class InputFromTrigger final : public Common::Input::InputDevice { public: explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, - u32 axis_, Input::AnalogProperties properties_, + u32 axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), axis(axis_), properties(properties_), input_engine(input_engine_) { @@ -348,8 +350,8 @@ public: input_engine->DeleteCallback(axis_callback_key); } - Input::TriggerStatus GetStatus() const { - const Input::AnalogStatus analog_status{ + Common::Input::TriggerStatus GetStatus() const { + const Common::Input::AnalogStatus analog_status{ .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, }; @@ -360,8 +362,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Trigger, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Trigger, .trigger_status = GetStatus(), }; @@ -379,7 +381,7 @@ private: const bool toggle; const bool inverted; const u32 axis; - const Input::AnalogProperties properties; + const Common::Input::AnalogProperties properties; int callback_key_button; int axis_callback_key; bool last_button_value; @@ -387,10 +389,11 @@ private: InputEngine* input_engine; }; -class InputFromAnalog final : public Input::InputDevice { +class InputFromAnalog final : public Common::Input::InputDevice { public: explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_, - Input::AnalogProperties properties_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_, + InputEngine* input_engine_) : identifier(identifier_), axis(axis_), properties(properties_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -408,7 +411,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::AnalogStatus GetStatus() const { + Common::Input::AnalogStatus GetStatus() const { return { .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, @@ -416,8 +419,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Analog, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Analog, .analog_status = GetStatus(), }; @@ -430,13 +433,13 @@ public: private: const PadIdentifier identifier; const u32 axis; - const Input::AnalogProperties properties; + const Common::Input::AnalogProperties properties; int callback_key; float last_axis_value; InputEngine* input_engine; }; -class InputFromBattery final : public Input::InputDevice { +class InputFromBattery final : public Common::Input::InputDevice { public: explicit InputFromBattery(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) { @@ -447,7 +450,7 @@ public: .index = 0, .callback = engine_callback, }; - last_battery_value = Input::BatteryStatus::Charging; + last_battery_value = Common::Input::BatteryStatus::Charging; callback_key = input_engine->SetCallback(input_identifier); } @@ -455,13 +458,13 @@ public: input_engine->DeleteCallback(callback_key); } - Input::BatteryStatus GetStatus() const { - return static_cast(input_engine->GetBattery(identifier)); + Common::Input::BatteryStatus GetStatus() const { + return static_cast(input_engine->GetBattery(identifier)); } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Battery, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Battery, .battery_status = GetStatus(), }; @@ -470,8 +473,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Battery, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Battery, .battery_status = GetStatus(), }; @@ -484,11 +487,11 @@ public: private: const PadIdentifier identifier; int callback_key; - Input::BatteryStatus last_battery_value; + Common::Input::BatteryStatus last_battery_value; InputEngine* input_engine; }; -class InputFromMotion final : public Input::InputDevice { +class InputFromMotion final : public Common::Input::InputDevice { public: explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_, InputEngine* input_engine_) @@ -507,10 +510,10 @@ public: input_engine->DeleteCallback(callback_key); } - Input::MotionStatus GetStatus() const { + Common::Input::MotionStatus GetStatus() const { const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor); - Input::MotionStatus status{}; - const Input::AnalogProperties properties = { + Common::Input::MotionStatus status{}; + const Common::Input::AnalogProperties properties = { .deadzone = 0.001f, .range = 1.0f, .offset = 0.0f, @@ -526,8 +529,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -541,12 +544,13 @@ private: InputEngine* input_engine; }; -class InputFromAxisMotion final : public Input::InputDevice { +class InputFromAxisMotion final : public Common::Input::InputDevice { public: explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, - Input::AnalogProperties properties_z_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + Common::Input::AnalogProperties properties_z_, + InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), axis_z(axis_z_), properties_x(properties_x_), properties_y(properties_y_), properties_z(properties_z_), input_engine(input_engine_) { @@ -583,8 +587,8 @@ public: input_engine->DeleteCallback(callback_key_z); } - Input::MotionStatus GetStatus() const { - Input::MotionStatus status{}; + Common::Input::MotionStatus GetStatus() const { + Common::Input::MotionStatus status{}; status.gyro.x = { .raw_value = input_engine->GetAxis(identifier, axis_x), .properties = properties_x, @@ -601,8 +605,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -613,8 +617,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -633,9 +637,9 @@ private: const u32 axis_x; const u32 axis_y; const u32 axis_z; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; - const Input::AnalogProperties properties_z; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_z; int callback_key_x; int callback_key_y; int callback_key_z; @@ -645,20 +649,21 @@ private: InputEngine* input_engine; }; -class OutputFromIdentifier final : public Input::OutputDevice { +class OutputFromIdentifier final : public Common::Input::OutputDevice { public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED(Input::LedStatus led_status) { + virtual void SetLED(Common::Input::LedStatus led_status) { input_engine->SetLeds(identifier, led_status); } - virtual Input::VibrationError SetVibration(Input::VibrationStatus vibration_status) { + virtual Common::Input::VibrationError SetVibration( + Common::Input::VibrationStatus vibration_status) { return input_engine->SetRumble(identifier, vibration_status); } - virtual Input::PollingError SetPollingMode(Input::PollingMode polling_mode) { + virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) { return input_engine->SetPollingMode(identifier, polling_mode); } @@ -667,7 +672,7 @@ private: InputEngine* input_engine; }; -std::unique_ptr InputFactory::CreateButtonDevice( +std::unique_ptr InputFactory::CreateButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -690,7 +695,7 @@ std::unique_ptr InputFactory::CreateButtonDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateHatButtonDevice( +std::unique_ptr InputFactory::CreateHatButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -709,7 +714,7 @@ std::unique_ptr InputFactory::CreateHatButtonDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateStickDevice( +std::unique_ptr InputFactory::CreateStickDevice( const Common::ParamPackage& params) { const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); @@ -721,7 +726,7 @@ std::unique_ptr InputFactory::CreateStickDevice( }; const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -730,7 +735,7 @@ std::unique_ptr InputFactory::CreateStickDevice( }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -744,7 +749,7 @@ std::unique_ptr InputFactory::CreateStickDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateAnalogDevice( +std::unique_ptr InputFactory::CreateAnalogDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -753,7 +758,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( }; const auto axis = static_cast(params.Get("axis", 0)); - const Input::AnalogProperties properties = { + const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f), .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), @@ -765,7 +770,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( return std::make_unique(identifier, axis, properties, input_engine.get()); } -std::unique_ptr InputFactory::CreateTriggerDevice( +std::unique_ptr InputFactory::CreateTriggerDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -778,7 +783,7 @@ std::unique_ptr InputFactory::CreateTriggerDevice( const auto inverted = params.Get("inverted", false); const auto axis = static_cast(params.Get("axis", 0)); - const Input::AnalogProperties properties = { + const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f), .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), @@ -792,7 +797,7 @@ std::unique_ptr InputFactory::CreateTriggerDevice( properties, input_engine.get()); } -std::unique_ptr InputFactory::CreateTouchDevice( +std::unique_ptr InputFactory::CreateTouchDevice( const Common::ParamPackage& params) { const auto touch_id = params.Get("touch_id", 0); const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); @@ -809,7 +814,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( const auto inverted = params.Get("inverted", false); const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -818,7 +823,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -833,7 +838,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( axis_y, properties_x, properties_y, input_engine.get()); } -std::unique_ptr InputFactory::CreateBatteryDevice( +std::unique_ptr InputFactory::CreateBatteryDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -845,7 +850,8 @@ std::unique_ptr InputFactory::CreateBatteryDevice( return std::make_unique(identifier, input_engine.get()); } -std::unique_ptr InputFactory::CreateMotionDevice(Common::ParamPackage params) { +std::unique_ptr InputFactory::CreateMotionDevice( + Common::ParamPackage params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), @@ -864,7 +870,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -873,7 +879,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -882,7 +888,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par }; const auto axis_z = static_cast(params.Get("axis_z", 1)); - const Input::AnalogProperties properties_z = { + const Common::Input::AnalogProperties properties_z = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -900,7 +906,8 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create( + const Common::ParamPackage& params) { if (params.Has("battery")) { return CreateBatteryDevice(params); } @@ -935,7 +942,8 @@ std::unique_ptr InputFactory::Create(const Common::ParamPack OutputFactory::OutputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr OutputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr OutputFactory::Create( + const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 1357e104b..573f09fde 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -17,7 +17,7 @@ class InputEngine; * An Input factory. It receives input events and forward them to all input devices it created. */ -class OutputFactory final : public Input::Factory { +class OutputFactory final : public Common::Input::Factory { public: explicit OutputFactory(std::shared_ptr input_engine_); @@ -29,13 +29,14 @@ public: * @param - "pad": slot of the connected controller * @return an unique ouput device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; private: std::shared_ptr input_engine; }; -class InputFactory final : public Input::Factory { +class InputFactory final : public Common::Input::Factory { public: explicit InputFactory(std::shared_ptr input_engine_); @@ -64,7 +65,7 @@ public: * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: /** @@ -79,7 +80,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateButtonDevice(const Common::ParamPackage& params); + std::unique_ptr CreateButtonDevice( + const Common::ParamPackage& params); /** * Creates a hat button device from the parameters given. @@ -93,7 +95,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateHatButtonDevice(const Common::ParamPackage& params); + std::unique_ptr CreateHatButtonDevice( + const Common::ParamPackage& params); /** * Creates a stick device from the parameters given. @@ -112,7 +115,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateStickDevice(const Common::ParamPackage& params); + std::unique_ptr CreateStickDevice( + const Common::ParamPackage& params); /** * Creates an analog device from the parameters given. @@ -128,7 +132,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateAnalogDevice(const Common::ParamPackage& params); + std::unique_ptr CreateAnalogDevice( + const Common::ParamPackage& params); /** * Creates a trigger device from the parameters given. @@ -148,7 +153,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateTriggerDevice(const Common::ParamPackage& params); + std::unique_ptr CreateTriggerDevice( + const Common::ParamPackage& params); /** * Creates a touch device from the parameters given. @@ -171,7 +177,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateTouchDevice(const Common::ParamPackage& params); + std::unique_ptr CreateTouchDevice( + const Common::ParamPackage& params); /** * Creates a battery device from the parameters given. @@ -181,7 +188,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateBatteryDevice(const Common::ParamPackage& params); + std::unique_ptr CreateBatteryDevice( + const Common::ParamPackage& params); /** * Creates a motion device from the parameters given. @@ -202,7 +210,7 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateMotionDevice(Common::ParamPackage params); + std::unique_ptr CreateMotionDevice(Common::ParamPackage params); std::shared_ptr input_engine; }; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 07d514ad7..df36a337c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -33,89 +33,97 @@ struct InputSubsystem::Impl { keyboard->SetMappingCallback(mapping_callback); keyboard_factory = std::make_shared(keyboard); keyboard_output_factory = std::make_shared(keyboard); - Input::RegisterFactory(keyboard->GetEngineName(), keyboard_factory); - Input::RegisterFactory(keyboard->GetEngineName(), - keyboard_output_factory); + Common::Input::RegisterFactory(keyboard->GetEngineName(), + keyboard_factory); + Common::Input::RegisterFactory(keyboard->GetEngineName(), + keyboard_output_factory); mouse = std::make_shared("mouse"); mouse->SetMappingCallback(mapping_callback); mouse_factory = std::make_shared(mouse); mouse_output_factory = std::make_shared(mouse); - Input::RegisterFactory(mouse->GetEngineName(), mouse_factory); - Input::RegisterFactory(mouse->GetEngineName(), mouse_output_factory); + Common::Input::RegisterFactory(mouse->GetEngineName(), + mouse_factory); + Common::Input::RegisterFactory(mouse->GetEngineName(), + mouse_output_factory); touch_screen = std::make_shared("touch"); touch_screen_factory = std::make_shared(touch_screen); - Input::RegisterFactory(touch_screen->GetEngineName(), - touch_screen_factory); + Common::Input::RegisterFactory(touch_screen->GetEngineName(), + touch_screen_factory); gcadapter = std::make_shared("gcpad"); gcadapter->SetMappingCallback(mapping_callback); gcadapter_input_factory = std::make_shared(gcadapter); gcadapter_output_factory = std::make_shared(gcadapter); - Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_input_factory); - Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_output_factory); + Common::Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_input_factory); + Common::Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_output_factory); udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); udp_client_factory = std::make_shared(udp_client); - Input::RegisterFactory(udp_client->GetEngineName(), udp_client_factory); + Common::Input::RegisterFactory(udp_client->GetEngineName(), + udp_client_factory); tas_input = std::make_shared("tas"); tas_input->SetMappingCallback(mapping_callback); tas_input_factory = std::make_shared(tas_input); tas_output_factory = std::make_shared(tas_input); - Input::RegisterFactory(tas_input->GetEngineName(), tas_input_factory); - Input::RegisterFactory(tas_input->GetEngineName(), tas_output_factory); + Common::Input::RegisterFactory(tas_input->GetEngineName(), + tas_input_factory); + Common::Input::RegisterFactory(tas_input->GetEngineName(), + tas_output_factory); #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); sdl_input_factory = std::make_shared(sdl); sdl_output_factory = std::make_shared(sdl); - Input::RegisterFactory(sdl->GetEngineName(), sdl_input_factory); - Input::RegisterFactory(sdl->GetEngineName(), sdl_output_factory); + Common::Input::RegisterFactory(sdl->GetEngineName(), + sdl_input_factory); + Common::Input::RegisterFactory(sdl->GetEngineName(), + sdl_output_factory); #endif - Input::RegisterFactory("touch_from_button", - std::make_shared()); - Input::RegisterFactory("analog_from_button", - std::make_shared()); + Common::Input::RegisterFactory( + "touch_from_button", std::make_shared()); + Common::Input::RegisterFactory( + "analog_from_button", std::make_shared()); } void Shutdown() { - Input::UnregisterFactory(keyboard->GetEngineName()); - Input::UnregisterFactory(keyboard->GetEngineName()); + Common::Input::UnregisterFactory(keyboard->GetEngineName()); + Common::Input::UnregisterFactory(keyboard->GetEngineName()); keyboard.reset(); - Input::UnregisterFactory(mouse->GetEngineName()); - Input::UnregisterFactory(mouse->GetEngineName()); + Common::Input::UnregisterFactory(mouse->GetEngineName()); + Common::Input::UnregisterFactory(mouse->GetEngineName()); mouse.reset(); - Input::UnregisterFactory(touch_screen->GetEngineName()); + Common::Input::UnregisterFactory(touch_screen->GetEngineName()); touch_screen.reset(); - Input::UnregisterFactory(gcadapter->GetEngineName()); - Input::UnregisterFactory(gcadapter->GetEngineName()); + Common::Input::UnregisterFactory(gcadapter->GetEngineName()); + Common::Input::UnregisterFactory(gcadapter->GetEngineName()); gcadapter.reset(); - Input::UnregisterFactory(udp_client->GetEngineName()); + Common::Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); - Input::UnregisterFactory(tas_input->GetEngineName()); - Input::UnregisterFactory(tas_input->GetEngineName()); + Common::Input::UnregisterFactory(tas_input->GetEngineName()); + Common::Input::UnregisterFactory(tas_input->GetEngineName()); tas_input.reset(); #ifdef HAVE_SDL2 - Input::UnregisterFactory(sdl->GetEngineName()); - Input::UnregisterFactory(sdl->GetEngineName()); + Common::Input::UnregisterFactory(sdl->GetEngineName()); + Common::Input::UnregisterFactory(sdl->GetEngineName()); sdl.reset(); #endif - Input::UnregisterFactory("touch_from_button"); - Input::UnregisterFactory("analog_from_button"); + Common::Input::UnregisterFactory("touch_from_button"); + Common::Input::UnregisterFactory("analog_from_button"); } [[nodiscard]] std::vector GetInputDevices() const { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 67e56ed3a..bb20e9339 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -1945,8 +1945,8 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { } void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; std::array qbody_top; @@ -1984,8 +1984,8 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, - Input::TriggerStatus left_trigger, - Input::TriggerStatus right_trigger) { + Common::Input::TriggerStatus left_trigger, + Common::Input::TriggerStatus right_trigger) { std::array qleft_trigger; std::array qright_trigger; @@ -2022,8 +2022,8 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; @@ -2048,8 +2048,8 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente } void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 1.62f; @@ -2076,9 +2076,9 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2113,9 +2113,9 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce DrawSymbol(p, center + QPointF(177, -84), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2149,7 +2149,7 @@ void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { + const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2166,7 +2166,7 @@ void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { + const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2184,8 +2184,8 @@ void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, 225 * 16, 44 * 16); } -void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2203,8 +2203,8 @@ void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF ce DrawSymbol(p, center + QPointF(-143, -36), Symbol::L, 1.0f); } -void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2223,7 +2223,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2240,7 +2240,7 @@ void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2259,8 +2259,8 @@ void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, 271 * 16, 44 * 16); } -void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2278,8 +2278,8 @@ void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF c DrawSymbol(p, center + QPointF(137, -36), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2298,7 +2298,7 @@ void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF } void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { const float radius1 = 13.0f * size; const float radius2 = 9.0f * size; @@ -2317,7 +2317,8 @@ void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float } void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle, - float size, const Input::ButtonStatus& pressed) { + float size, + const Common::Input::ButtonStatus& pressed) { QVector joystick; joystick.reserve(static_cast(left_joystick_sideview.size() / 2)); @@ -2342,7 +2343,7 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset, float offset_scalar, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { const float radius1 = 24.0f; const float radius2 = 17.0f; @@ -2377,7 +2378,7 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co } void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { // Outer circle p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); @@ -2414,8 +2415,8 @@ void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPo } } -void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF center, - const Input::AnalogProperties& properties) { +void PlayerControlPreview::DrawJoystickProperties( + QPainter& p, const QPointF center, const Common::Input::AnalogProperties& properties) { constexpr float size = 45.0f; const float range = size * properties.range; const float deadzone = size * properties.deadzone; @@ -2435,7 +2436,7 @@ void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF cen } void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, - const Input::StickStatus& stick, bool raw) { + const Common::Input::StickStatus& stick, bool raw) { constexpr float size = 45.0f; const float range = size * stick.x.properties.range; @@ -2450,7 +2451,7 @@ void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, - const Input::ButtonStatus& pressed, float width, + const Common::Input::ButtonStatus& pressed, float width, float height, Direction direction, float radius) { p.setBrush(button_color); if (pressed.value) { @@ -2476,13 +2477,15 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, p.drawRoundedRect(rect, radius, radius); } void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, int button_size) { + const Common::Input::ButtonStatus& pressed, + int button_size) { p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); } void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, int button_size) { + const Common::Input::ButtonStatus& pressed, + int button_size) { // Draw outer line p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); @@ -2499,7 +2502,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) { @@ -2512,7 +2515,7 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) { @@ -2525,7 +2528,7 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) { @@ -2539,7 +2542,8 @@ void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, float button_size) { + const Common::Input::ButtonStatus& pressed, + float button_size) { p.setBrush(button_color); if (pressed.value) { p.setBrush(colors.highlight); @@ -2571,7 +2575,7 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, const Direction direction, - const Input::ButtonStatus& pressed, float size) { + const Common::Input::ButtonStatus& pressed, float size) { std::array arrow_button; QPoint offset; @@ -2628,7 +2632,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, const Direction direction, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array qtrigger_button; for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { @@ -2655,8 +2659,9 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, DrawPolygon(p, qtrigger_button); } -void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery) { - if (battery == Input::BatteryLevel::None) { +void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, + Common::Input::BatteryLevel battery) { + if (battery == Common::Input::BatteryLevel::None) { return; } p.setPen(colors.outline); @@ -2665,29 +2670,29 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte p.drawRect(center.x() + 56, center.y() + 6, 3, 8); p.setBrush(colors.deadzone); switch (battery) { - case Input::BatteryLevel::Charging: + case Common::Input::BatteryLevel::Charging: p.setBrush(colors.indicator2); p.drawText(center + QPoint(2, 14), tr("Charging")); break; - case Input::BatteryLevel::Full: + case Common::Input::BatteryLevel::Full: p.drawRect(center.x() + 42, center.y(), 14, 20); p.drawRect(center.x() + 28, center.y(), 14, 20); p.drawRect(center.x() + 14, center.y(), 14, 20); p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Medium: + case Common::Input::BatteryLevel::Medium: p.drawRect(center.x() + 28, center.y(), 14, 20); p.drawRect(center.x() + 14, center.y(), 14, 20); p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Low: + case Common::Input::BatteryLevel::Low: p.drawRect(center.x() + 14, center.y(), 14, 20); p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Critical: + case Common::Input::BatteryLevel::Critical: p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Empty: + case Common::Input::BatteryLevel::Empty: p.drawRect(center.x(), center.y(), 5, 20); break; default: diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 333c3fc56..430e4f4f4 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -115,66 +115,75 @@ private: void DrawGCBody(QPainter& p, QPointF center); // Draw triggers functions - void DrawProTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawGCTriggers(QPainter& p, QPointF center, Input::TriggerStatus left_trigger, - Input::TriggerStatus right_trigger); - void DrawHandheldTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawDualTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); + void DrawProTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); + void DrawGCTriggers(QPainter& p, QPointF center, Common::Input::TriggerStatus left_trigger, + Common::Input::TriggerStatus right_trigger); + void DrawHandheldTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); + void DrawDualTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); void DrawDualTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); void DrawDualZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawLeftTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); - void DrawLeftZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); + void DrawLeftTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& left_pressed); + void DrawLeftZTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& left_pressed); void DrawLeftTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed); + const Common::Input::ButtonStatus& left_pressed); void DrawLeftZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed); - void DrawRightTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); - void DrawRightZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& left_pressed); + void DrawRightTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& right_pressed); + void DrawRightZTriggers(QPainter& p, QPointF center, + const Common::Input::ButtonStatus& right_pressed); void DrawRightTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& right_pressed); void DrawRightZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& right_pressed); // Draw joystick functions - void DrawJoystick(QPainter& p, QPointF center, float size, const Input::ButtonStatus& pressed); + void DrawJoystick(QPainter& p, QPointF center, float size, + const Common::Input::ButtonStatus& pressed); void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, - const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right); void DrawJoystickProperties(QPainter& p, QPointF center, - const Input::AnalogProperties& properties); - void DrawJoystickDot(QPainter& p, QPointF center, const Input::StickStatus& stick, bool raw); + const Common::Input::AnalogProperties& properties); + void DrawJoystickDot(QPainter& p, QPointF center, const Common::Input::StickStatus& stick, + bool raw); void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, - const Input::ButtonStatus& pressed); - void DrawGCJoystick(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); + void DrawGCJoystick(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); // Draw button functions - void DrawCircleButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawCircleButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, float button_size); - void DrawRoundButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawRoundButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, float width, float height, Direction direction = Direction::None, float radius = 2); - void DrawMinusButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawMinusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, int button_size); - void DrawPlusButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawPlusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, int button_size); - void DrawGCButtonX(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); - void DrawGCButtonY(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); - void DrawGCButtonZ(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + void DrawGCButtonX(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); + void DrawGCButtonY(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); + void DrawGCButtonZ(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); void DrawArrowButton(QPainter& p, QPointF center, Direction direction, - const Input::ButtonStatus& pressed, float size = 1.0f); + const Common::Input::ButtonStatus& pressed, float size = 1.0f); void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, - const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); // Draw battery functions - void DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery); + void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery); // Draw icon functions void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); From 730f07830247cfcdc551c253d30c6717fc16316c Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 31 Oct 2021 10:41:44 -0500 Subject: [PATCH 109/291] settings: Fix Debug controller type options --- src/common/input.h | 4 +- src/core/hid/emulated_console.cpp | 3 +- src/core/hid/emulated_controller.cpp | 11 ++- src/core/hid/input_converter.cpp | 4 +- src/input_common/drivers/tas_input.h | 1 - .../helpers/touch_from_buttons.cpp | 4 +- src/input_common/input_engine.cpp | 2 +- src/input_common/input_engine.h | 5 +- src/input_common/input_poller.cpp | 89 ++++++++++--------- src/yuzu/applets/qt_controller.cpp | 2 - .../configuration/configure_input_player.cpp | 2 - .../configuration/configure_input_player.ui | 25 ------ .../configure_input_player_widget.cpp | 20 +++-- 13 files changed, 77 insertions(+), 95 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 6d3227f5e..16b1e6f1b 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -100,7 +100,7 @@ struct StickStatus { struct TriggerStatus { AnalogStatus analog{}; - bool pressed{}; + ButtonStatus pressed{}; }; struct MotionSensor { @@ -119,7 +119,7 @@ struct TouchStatus { ButtonStatus pressed{}; AnalogStatus x{}; AnalogStatus y{}; - u32 id{}; + int id{}; }; struct BodyColorStatus { diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index c259de0f1..012909954 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -166,9 +166,10 @@ void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, return; } + // TODO(german77): Remap touch id in sequential order console.touch_state[index] = { .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, - .id = console.touch_values[index].id, + .id = static_cast(console.touch_values[index].id), .pressed = console.touch_values[index].pressed.value, }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 49893cdbd..9a1864279 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -77,7 +77,12 @@ void EmulatedController::ReloadFromSettings() { controller.colors_state.fullkey = controller.colors_state.left; - SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + // Other or debug controller should always be a pro controller + if (npad_id_type != NpadIdType::Other) { + SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + } else { + SetNpadType(NpadType::ProController); + } if (player.connected) { Connect(); @@ -606,12 +611,12 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std: switch (index) { case Settings::NativeTrigger::LTrigger: controller.gc_trigger_state.left = static_cast(trigger.analog.value * HID_TRIGGER_MAX); - controller.npad_button_state.zl.Assign(trigger.pressed); + controller.npad_button_state.zl.Assign(trigger.pressed.value); break; case Settings::NativeTrigger::RTrigger: controller.gc_trigger_state.right = static_cast(trigger.analog.value * HID_TRIGGER_MAX); - controller.npad_button_state.zr.Assign(trigger.pressed); + controller.npad_button_state.zr.Assign(trigger.pressed.value); break; } diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 14204917e..5b123bd3a 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -53,7 +53,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu switch (callback.type) { case Common::Input::InputType::Analog: case Common::Input::InputType::Trigger: - status.value = TransformToTrigger(callback).pressed; + status.value = TransformToTrigger(callback).pressed.value; break; case Common::Input::InputType::Button: status = callback.button_status; @@ -222,7 +222,7 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta // Set button status if (calculate_button_value) { - status.pressed = value > properties.threshold; + status.pressed.value = value > properties.threshold; } // Adjust if value is inverted diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 5f5c3267c..82dc9d616 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -188,7 +188,6 @@ private: std::string WriteCommandAxis(TasAnalog data) const; size_t script_length{0}; - bool is_old_input_saved{false}; bool is_recording{false}; bool is_running{false}; bool needs_reset{false}; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index fee41cae3..024343715 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -12,7 +12,7 @@ namespace InputCommon { class TouchFromButtonDevice final : public Common::Input::InputDevice { public: using Button = std::unique_ptr; - TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_) + TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { Common::Input::InputCallback button_up_callback{ [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; @@ -52,7 +52,7 @@ public: private: Button button; - const u32 touch_id; + const int touch_id; const float x; const float y; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 9cfe0f232..965a2bdf1 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -315,7 +315,7 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, - std::size_t index) const { + int index) const { if (input_identifier.type != type) { return false; } diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index ed79d3d93..5430c0cf8 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -96,7 +96,7 @@ struct MappingCallback { struct InputIdentifier { PadIdentifier identifier; EngineInputType type; - std::size_t index; + int index; UpdateCallback callback; }; @@ -216,12 +216,11 @@ private: bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, - std::size_t index) const; + int index) const; mutable std::mutex mutex; mutable std::mutex mutex_callback; bool configuring{false}; - bool is_callback_enabled{true}; const std::string input_engine; int last_callback_key = 0; std::unordered_map controller_list; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 2b3b77938..01c435802 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -18,7 +18,7 @@ public: class InputFromButton final : public Common::Input::InputDevice { public: - explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, + explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), input_engine(input_engine_) { @@ -69,7 +69,7 @@ public: private: const PadIdentifier identifier; - const u32 button; + const int button; const bool toggle; const bool inverted; int callback_key; @@ -79,7 +79,7 @@ private: class InputFromHatButton final : public Common::Input::InputDevice { public: - explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_, + explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_, bool inverted_, InputEngine* input_engine_) : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), inverted(inverted_), input_engine(input_engine_) { @@ -130,7 +130,7 @@ public: private: const PadIdentifier identifier; - const u32 button; + const int button; const u8 direction; const bool toggle; const bool inverted; @@ -141,7 +141,7 @@ private: class InputFromStick final : public Common::Input::InputDevice { public: - explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, + explicit InputFromStick(PadIdentifier identifier_, int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) @@ -211,8 +211,8 @@ public: private: const PadIdentifier identifier; - const u32 axis_x; - const u32 axis_y; + const int axis_x; + const int axis_y; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; int callback_key_x; @@ -224,8 +224,8 @@ private: class InputFromTouch final : public Common::Input::InputDevice { public: - explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_, - bool inverted_, u32 axis_x_, u32 axis_y_, + explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, + bool inverted_, int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) @@ -302,12 +302,12 @@ public: private: const PadIdentifier identifier; - const u32 touch_id; - const u32 button; + const int touch_id; + const int button; const bool toggle; const bool inverted; - const u32 axis_x; - const u32 axis_y; + const int axis_x; + const int axis_y; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; int callback_key_button; @@ -321,8 +321,8 @@ private: class InputFromTrigger final : public Common::Input::InputDevice { public: - explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, - u32 axis_, Common::Input::AnalogProperties properties_, + explicit InputFromTrigger(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, + int axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), axis(axis_), properties(properties_), input_engine(input_engine_) { @@ -355,9 +355,14 @@ public: .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, }; + const Common::Input::ButtonStatus button_status{ + .value = input_engine->GetButton(identifier, button), + .inverted = inverted, + .toggle = toggle, + }; return { .analog = analog_status, - .pressed = input_engine->GetButton(identifier, button), + .pressed = button_status, }; } @@ -368,19 +373,19 @@ public: }; if (status.trigger_status.analog.raw_value != last_axis_value || - status.trigger_status.pressed != last_button_value) { + status.trigger_status.pressed.value != last_button_value) { last_axis_value = status.trigger_status.analog.raw_value; - last_button_value = status.trigger_status.pressed; + last_button_value = status.trigger_status.pressed.value; TriggerOnChange(status); } } private: const PadIdentifier identifier; - const u32 button; + const int button; const bool toggle; const bool inverted; - const u32 axis; + const int axis; const Common::Input::AnalogProperties properties; int callback_key_button; int axis_callback_key; @@ -391,7 +396,7 @@ private: class InputFromAnalog final : public Common::Input::InputDevice { public: - explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_, + explicit InputFromAnalog(PadIdentifier identifier_, int axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), axis(axis_), properties(properties_), @@ -432,7 +437,7 @@ public: private: const PadIdentifier identifier; - const u32 axis; + const int axis; const Common::Input::AnalogProperties properties; int callback_key; float last_axis_value; @@ -493,7 +498,7 @@ private: class InputFromMotion final : public Common::Input::InputDevice { public: - explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_, + explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, InputEngine* input_engine_) : identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -539,14 +544,14 @@ public: private: const PadIdentifier identifier; - const u32 motion_sensor; + const int motion_sensor; int callback_key; InputEngine* input_engine; }; class InputFromAxisMotion final : public Common::Input::InputDevice { public: - explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_, + explicit InputFromAxisMotion(PadIdentifier identifier_, int axis_x_, int axis_y_, int axis_z_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, Common::Input::AnalogProperties properties_z_, @@ -634,9 +639,9 @@ public: private: const PadIdentifier identifier; - const u32 axis_x; - const u32 axis_y; - const u32 axis_z; + const int axis_x; + const int axis_y; + const int axis_z; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; const Common::Input::AnalogProperties properties_z; @@ -680,8 +685,8 @@ std::unique_ptr InputFactory::CreateButtonDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button_id = static_cast(params.Get("button", 0)); - const auto keyboard_key = static_cast(params.Get("code", 0)); + const auto button_id = params.Get("button", 0); + const auto keyboard_key = params.Get("code", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); input_engine->PreSetController(identifier); @@ -703,7 +708,7 @@ std::unique_ptr InputFactory::CreateHatButtonDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button_id = static_cast(params.Get("hat", 0)); + const auto button_id = params.Get("hat", 0); const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); @@ -725,7 +730,7 @@ std::unique_ptr InputFactory::CreateStickDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -734,7 +739,7 @@ std::unique_ptr InputFactory::CreateStickDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -757,7 +762,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto axis = static_cast(params.Get("axis", 0)); + const auto axis = params.Get("axis", 0); const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f), @@ -778,11 +783,11 @@ std::unique_ptr InputFactory::CreateTriggerDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button = static_cast(params.Get("button", 0)); + const auto button = params.Get("button", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); - const auto axis = static_cast(params.Get("axis", 0)); + const auto axis = params.Get("axis", 0); const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f), @@ -809,11 +814,11 @@ std::unique_ptr InputFactory::CreateTouchDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button = static_cast(params.Get("button", 0)); + const auto button = params.Get("button", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -822,7 +827,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -869,7 +874,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -878,7 +883,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -887,7 +892,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( .inverted = params.Get("invert_y", "+") != "+", }; - const auto axis_z = static_cast(params.Get("axis_z", 1)); + const auto axis_z = params.Get("axis_z", 1); const Common::Input::AnalogProperties properties_z = { .deadzone = deadzone, .range = range, diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 59289c6a5..e9cb578b4 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -26,8 +26,6 @@ namespace { -constexpr std::size_t HANDHELD_INDEX = 8; - void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadType controller_type, bool connected) { if (controller->IsConnected()) { diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9a1b3575e..8d6289d8e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -38,8 +38,6 @@ const std::array namespace { -constexpr std::size_t HANDHELD_INDEX = 8; - QString GetKeyName(int key_code) { switch (key_code) { case Qt::Key_Shift: diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 14ca02fd8..958a89229 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -89,31 +89,6 @@ 21 - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - Handheld - - diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index bb20e9339..99c4f13c3 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -118,7 +118,7 @@ void PlayerControlPreview::ResetInputs() { }); trigger_values.fill({ .analog = {.value = 0, .properties = {0, 1, 0}}, - .pressed = false, + .pressed = {.value = false}, }); update(); } @@ -2001,11 +2001,11 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, // Left trigger p.setPen(colors.outline); - p.setBrush(left_trigger.pressed ? colors.highlight : colors.button); + p.setBrush(left_trigger.pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_trigger.pressed ? colors.highlight : colors.button); + p.setBrush(right_trigger.pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text @@ -2587,15 +2587,17 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, case Direction::Up: arrow_button[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size); break; - case Direction::Left: - arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size); - break; case Direction::Right: arrow_button[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size); break; case Direction::Down: arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size); break; + case Direction::Left: + // Compiler doesn't optimize this correctly + arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, + up_arrow_button[point * 2 + 0] * size); + break; case Direction::None: break; } @@ -2610,15 +2612,15 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, case Direction::Up: offset = QPoint(0, -20 * size); break; - case Direction::Left: - offset = QPoint(-20 * size, 0); - break; case Direction::Right: offset = QPoint(20 * size, 0); break; case Direction::Down: offset = QPoint(0, 20 * size); break; + case Direction::Left: + offset = QPoint(-20 * size, 0); + break; case Direction::None: offset = QPoint(0, 0); break; From 77fa4d4bf60526826ef8b53ee3870f7d2a761976 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 1 Nov 2021 14:17:53 -0600 Subject: [PATCH 110/291] second commit lion review --- src/common/input.h | 2 +- src/core/hid/emulated_console.cpp | 5 +++-- src/core/hid/emulated_controller.cpp | 5 +++-- src/core/hid/emulated_devices.cpp | 5 +++-- src/core/hid/hid_core.cpp | 3 +++ src/core/hid/hid_core.h | 10 +++++++--- src/core/hid/input_converter.h | 12 ++++++++++-- .../hle/service/am/applets/applet_controller.cpp | 2 ++ .../hle/service/hid/controllers/console_sixaxis.cpp | 1 + src/core/hle/service/hid/controllers/debug_pad.cpp | 1 + src/core/hle/service/hid/controllers/gesture.h | 5 +---- src/core/hle/service/hid/controllers/keyboard.cpp | 1 + src/core/hle/service/hid/controllers/mouse.cpp | 1 + src/core/hle/service/hid/controllers/npad.cpp | 2 ++ src/core/hle/service/hid/controllers/npad.h | 6 +++++- src/core/hle/service/hid/controllers/touchscreen.h | 1 + src/input_common/drivers/keyboard.cpp | 6 ++++++ src/input_common/drivers/keyboard.h | 7 ------- src/input_common/drivers/mouse.cpp | 5 +++++ src/input_common/drivers/mouse.h | 5 ----- src/input_common/drivers/touch_screen.cpp | 6 ++++++ src/input_common/drivers/touch_screen.h | 8 +------- src/input_common/input_engine.cpp | 5 +++-- src/yuzu/applets/qt_controller.cpp | 1 + .../configuration/configure_input_player_widget.cpp | 5 ++--- .../configuration/configure_input_player_widget.h | 1 + src/yuzu/debugger/controller.h | 3 ++- src/yuzu/main.cpp | 1 + 28 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 16b1e6f1b..12acd8785 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -29,7 +29,7 @@ enum class InputType { Ir, }; -enum class BatteryLevel { +enum class BatteryLevel : u32 { None, Empty, Critical, diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 012909954..dfbaa3f8c 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -209,10 +209,11 @@ int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { void EmulatedConsole::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 9a1864279..7bab00bb1 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -993,10 +993,11 @@ int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { void EmulatedController::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index c76a86b6c..e97470240 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -362,10 +362,11 @@ int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { void EmulatedDevices::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 3cb26e1e7..741a69c3c 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include "common/assert.h" +#include "core/hid/emulated_console.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" namespace Core::HID { diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index a4a66a3a4..1fe2fd89b 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -6,9 +6,13 @@ #include -#include "core/hid/emulated_console.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/emulated_devices.h" +#include "core/hid/hid_types.h" + +namespace Core::HID { +class EmulatedConsole; +class EmulatedController; +class EmulatedDevices; +} // namespace Core::HID namespace Core::HID { diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index b38e657b0..2a722b39f 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -4,9 +4,17 @@ #pragma once -namespace Input { +namespace Common::Input { struct CallbackStatus; -}; +enum class BatteryLevel : u32; +using BatteryStatus = BatteryLevel; +struct AnalogStatus; +struct ButtonStatus; +struct MotionStatus; +struct StickStatus; +struct TouchStatus; +struct TriggerStatus; +}; // namespace Common::Input namespace Core::HID { diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 658265a00..374e0c7f4 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -10,6 +10,8 @@ #include "common/string_util.h" #include "core/core.h" #include "core/frontend/applets/controller.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index 1d351fde0..2bebcf0d0 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -5,6 +5,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" namespace Service::HID { diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index b009ed086..86b95f2c8 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 58139a5cf..9bffde438 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -8,13 +8,10 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/point.h" +#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 60dc62f2c..acea68e24 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/keyboard.h" diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 7ec75e8c8..21f7e48bb 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -7,6 +7,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/mouse.h" diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 9f82f872a..0b5a23696 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -12,6 +12,8 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4a9c9cc1a..871d245fd 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -12,11 +12,15 @@ #include "common/common_types.h" #include "common/quaternion.h" #include "common/settings.h" -#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" +namespace Core::HID { +class EmulatedController; +enum class ControllerTriggerType; +} // namespace Core::HID + namespace Kernel { class KEvent; class KReadableEvent; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index fa4dfa1a2..50dadd25f 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" +#include "core/hid/emulated_console.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 85a781a30..549704e89 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -7,6 +7,12 @@ namespace InputCommon { +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; + Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 58df15050..46fe78576 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -32,13 +32,6 @@ public: /// Used for automapping features std::vector GetInputDevices() const override; - -private: - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; }; } // namespace InputCommon diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 1c32b54be..afa92b458 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -14,6 +14,11 @@ namespace InputCommon { constexpr int touch_axis_x = 10; constexpr int touch_axis_y = 11; +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index cf0918409..1be362b94 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -62,11 +62,6 @@ private: void UpdateThread(std::stop_token stop_token); void StopPanning(); - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; Common::Vec2 mouse_origin; Common::Vec2 last_mouse_position; Common::Vec2 last_mouse_change; diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index e13835e9f..377c9ee2b 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -7,6 +7,12 @@ namespace InputCommon { +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; + TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index d297d253c..0f4cd0e7a 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -37,14 +37,8 @@ public: */ void TouchReleased(std::size_t finger); + /// Resets all inputs to their initial value void ReleaseAllTouch(); - -private: - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; }; } // namespace InputCommon diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 965a2bdf1..139d8d2e6 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -353,11 +353,12 @@ void InputEngine::SetMappingCallback(MappingCallback callback) { void InputEngine::DeleteCallback(int key) { std::lock_guard lock{mutex_callback}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace InputCommon diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index e9cb578b4..9c6377cf0 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -10,6 +10,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/lock.h" #include "core/hle/service/hid/controllers/npad.h" diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 99c4f13c3..7e71a0f58 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -2594,9 +2594,8 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size); break; case Direction::Left: - // Compiler doesn't optimize this correctly - arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, - up_arrow_button[point * 2 + 0] * size); + // Compiler doesn't optimize this correctly check why + arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size); break; case Direction::None: break; diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 430e4f4f4..acc53a9e3 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -9,6 +9,7 @@ #include #include "common/input.h" #include "common/settings.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index ba4185a4b..d08643baa 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -21,7 +21,8 @@ class System; namespace Core::HID { class EmulatedController; -} +enum class ControllerTriggerType; +} // namespace Core::HID class ControllerDialog : public QWidget { Q_OBJECT diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 56db337a4..7c95851b3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -26,6 +26,7 @@ #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/software_keyboard.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" From 136eb9c4c2b2425c2dd45a79cf444dee7170714d Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 1 Nov 2021 19:49:14 -0600 Subject: [PATCH 111/291] core/hid: Fully emulate motion from button --- src/common/input.h | 5 ++ src/core/hid/emulated_controller.cpp | 11 ++- src/core/hid/emulated_controller.h | 1 + src/core/hid/input_converter.cpp | 78 ++++++++++--------- src/core/hid/motion_input.h | 16 ++++ .../helpers/stick_from_buttons.cpp | 12 +++ .../helpers/touch_from_buttons.cpp | 11 ++- 7 files changed, 97 insertions(+), 37 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 12acd8785..8f29026a1 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -110,9 +110,14 @@ struct MotionSensor { }; struct MotionStatus { + // Gyroscope vector measurement in radians/s. MotionSensor gyro{}; + // Acceleration vector measurement in G force MotionSensor accel{}; + // Time since last measurement in microseconds u64 delta_timestamp{}; + // Request to update after reading the value + bool force_update{}; }; struct TouchStatus { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7bab00bb1..2db2b4da0 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -644,6 +644,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std:: }); emulated.UpdateRotation(raw_status.delta_timestamp); emulated.UpdateOrientation(raw_status.delta_timestamp); + force_update_motion = raw_status.force_update; if (is_configuring) { TriggerOnChange(ControllerTriggerType::Motion, false); @@ -653,7 +654,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std:: auto& motion = controller.motion_state[index]; motion.accel = emulated.GetAcceleration(); motion.gyro = emulated.GetGyroscope(); - motion.rotation = emulated.GetGyroscope(); + motion.rotation = emulated.GetRotations(); motion.orientation = emulated.GetOrientation(); motion.is_at_rest = emulated.IsMoving(motion_sensitivity); @@ -962,6 +963,14 @@ NpadGcTriggerState EmulatedController::GetTriggers() const { } MotionState EmulatedController::GetMotions() const { + if (force_update_motion) { + for (auto& device : motion_devices) { + if (!device) { + continue; + } + device->ForceUpdate(); + } + } return controller.motion_state; } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index dd9a93364..2f7afff56 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -355,6 +355,7 @@ private: bool is_connected{false}; bool is_configuring{false}; f32 motion_sensitivity{0.01f}; + bool force_update_motion{false}; // Temporary values to avoid doing changes while the controller is on configuration mode NpadType tmp_npad_type{NpadType::None}; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5b123bd3a..480b862fd 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -74,45 +74,53 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu Common::Input::MotionStatus status{}; switch (callback.type) { case Common::Input::InputType::Button: { + Common::Input::AnalogProperties properties{ + .deadzone = 0.0f, + .range = 1.0f, + .offset = 0.0f, + }; + status.delta_timestamp = 5000; + status.force_update = true; + status.accel.x = { + .value = 0.0f, + .raw_value = 0.0f, + .properties = properties, + }; + status.accel.y = { + .value = 0.0f, + .raw_value = 0.0f, + .properties = properties, + }; + status.accel.z = { + .value = 0.0f, + .raw_value = -1.0f, + .properties = properties, + }; + status.gyro.x = { + .value = 0.0f, + .raw_value = 0.0f, + .properties = properties, + }; + status.gyro.y = { + .value = 0.0f, + .raw_value = 0.0f, + .properties = properties, + }; + status.gyro.z = { + .value = 0.0f, + .raw_value = 0.0f, + .properties = properties, + }; if (TransformToButton(callback).value) { std::random_device device; std::mt19937 gen(device()); std::uniform_int_distribution distribution(-1000, 1000); - Common::Input::AnalogProperties properties{ - .deadzone = 0.0, - .range = 1.0f, - .offset = 0.0, - }; - status.accel.x = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; - status.accel.y = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; - status.accel.z = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; - status.gyro.x = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; - status.gyro.y = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; - status.gyro.z = { - .value = 0, - .raw_value = static_cast(distribution(gen)) * 0.001f, - .properties = properties, - }; + status.accel.x.raw_value = static_cast(distribution(gen)) * 0.001f; + status.accel.y.raw_value = static_cast(distribution(gen)) * 0.001f; + status.accel.z.raw_value = static_cast(distribution(gen)) * 0.001f; + status.gyro.x.raw_value = static_cast(distribution(gen)) * 0.001f; + status.gyro.y.raw_value = static_cast(distribution(gen)) * 0.001f; + status.gyro.z.raw_value = static_cast(distribution(gen)) * 0.001f; } break; } diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h index 3deef5ac3..5b5b420bb 100644 --- a/src/core/hid/motion_input.h +++ b/src/core/hid/motion_input.h @@ -56,15 +56,31 @@ private: Common::Vec3f integral_error; Common::Vec3f derivative_error; + // Quaternion containing the device orientation Common::Quaternion quat{{0.0f, 0.0f, -1.0f}, 0.0f}; + + // Number of full rotations in each axis Common::Vec3f rotations; + + // Acceleration vector measurement in G force Common::Vec3f accel; + + // Gyroscope vector measurement in radians/s. Common::Vec3f gyro; + + // Vector to be substracted from gyro measurements Common::Vec3f gyro_drift; + // Minimum gyro amplitude to detect if the device is moving f32 gyro_threshold = 0.0f; + + // Number of invalid sequential data u32 reset_counter = 0; + + // If the provided data is invalid the device will be autocalibrated bool reset_enabled = true; + + // Use accelerometer values to calculate position bool only_accelerometer = true; }; diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 1d5948f79..77fcd655e 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -36,6 +36,8 @@ public: left->SetCallback(button_left_callback); right->SetCallback(button_right_callback); modifier->SetCallback(button_modifier_callback); + last_x_axis_value = 0.0f; + last_y_axis_value = 0.0f; } bool IsAngleGreater(float old_angle, float new_angle) const { @@ -199,6 +201,8 @@ public: .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; + last_x_axis_value = status.stick_status.x.raw_value; + last_y_axis_value = status.stick_status.y.raw_value; TriggerOnChange(status); } @@ -215,6 +219,12 @@ public: .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; + if (last_x_axis_value == status.stick_status.x.raw_value && + last_y_axis_value == status.stick_status.y.raw_value) { + return; + } + last_x_axis_value = status.stick_status.x.raw_value; + last_y_axis_value = status.stick_status.y.raw_value; TriggerOnChange(status); } @@ -265,6 +275,8 @@ private: bool left_status; bool right_status; bool modifier_status; + float last_x_axis_value; + float last_y_axis_value; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point last_update; }; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 024343715..35d60bc90 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -16,10 +16,15 @@ public: : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { Common::Input::InputCallback button_up_callback{ [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; + last_button_value = false; button->SetCallback(button_up_callback); button->ForceUpdate(); } + void ForceUpdate() override { + button->ForceUpdate(); + } + Common::Input::TouchStatus GetStatus(bool pressed) const { const Common::Input::ButtonStatus button_status{ .value = pressed, @@ -47,11 +52,15 @@ public: .type = Common::Input::InputType::Touch, .touch_status = GetStatus(button_callback.button_status.value), }; - TriggerOnChange(status); + if (last_button_value != button_callback.button_status.value) { + last_button_value = button_callback.button_status.value; + TriggerOnChange(status); + } } private: Button button; + bool last_button_value; const int touch_id; const float x; const float y; From 157e0b85fdd805e02d234dccf1ce578e3159adee Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 2 Nov 2021 22:50:30 -0600 Subject: [PATCH 112/291] core/hid: Prevent Emulated controller from flapping with multiple inputs devices --- src/common/input.h | 4 ++ src/core/hid/emulated_controller.cpp | 68 ++++++++++++++++++++++---- src/core/hid/emulated_controller.h | 6 +-- src/input_common/drivers/tas_input.cpp | 24 ++++----- src/input_common/drivers/tas_input.h | 11 ++--- 5 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 8f29026a1..f21872b0a 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -11,6 +11,7 @@ #include #include "common/logging/log.h" #include "common/param_package.h" +#include "common/uuid.h" namespace Common::Input { @@ -81,6 +82,7 @@ struct AnalogStatus { }; struct ButtonStatus { + Common::UUID uuid{}; bool value{}; bool inverted{}; bool toggle{}; @@ -90,6 +92,7 @@ struct ButtonStatus { using BatteryStatus = BatteryLevel; struct StickStatus { + Common::UUID uuid{}; AnalogStatus x{}; AnalogStatus y{}; bool left{}; @@ -99,6 +102,7 @@ struct StickStatus { }; struct TriggerStatus { + Common::UUID uuid{}; AnalogStatus analog{}; ButtonStatus pressed{}; }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 2db2b4da0..6fe3744fd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -183,8 +183,11 @@ void EmulatedController::ReloadInput() { if (!button_devices[index]) { continue; } + const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, uuid); + }}; button_devices[index]->SetCallback(button_callback); button_devices[index]->ForceUpdate(); } @@ -193,8 +196,11 @@ void EmulatedController::ReloadInput() { if (!stick_devices[index]) { continue; } + const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, uuid); + }}; stick_devices[index]->SetCallback(stick_callback); stick_devices[index]->ForceUpdate(); } @@ -203,8 +209,11 @@ void EmulatedController::ReloadInput() { if (!trigger_devices[index]) { continue; } + const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; Common::Input::InputCallback trigger_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetTrigger(callback, index, uuid); + }}; trigger_devices[index]->SetCallback(trigger_callback); trigger_devices[index]->ForceUpdate(); } @@ -229,13 +238,18 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } + // Use a common UUID for TAS + const auto tas_uuid = Common::UUID{0x0, 0x7A5}; + // Register TAS devices. No need to force update for (std::size_t index = 0; index < tas_button_devices.size(); ++index) { if (!tas_button_devices[index]) { continue; } Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, tas_uuid); + }}; tas_button_devices[index]->SetCallback(button_callback); } @@ -244,7 +258,9 @@ void EmulatedController::ReloadInput() { continue; } Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, tas_uuid); + }}; tas_stick_devices[index]->SetCallback(stick_callback); } } @@ -423,7 +439,8 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage ReloadInput(); } -void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.button_values.size()) { return; } @@ -432,7 +449,16 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: bool value_changed = false; const auto new_status = TransformToButton(callback); auto& current_status = controller.button_values[index]; + + // Only read button values that have the same uuid or are pressed once + if (current_status.uuid != uuid) { + if (!new_status.value) { + return; + } + } + current_status.toggle = new_status.toggle; + current_status.uuid = uuid; // Update button status with current if (!current_status.toggle) { @@ -553,12 +579,23 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.stick_values.size()) { return; } std::lock_guard lock{mutex}; - controller.stick_values[index] = TransformToStick(callback); + const auto stick_value = TransformToStick(callback); + + // Only read stick values that have the same uuid or are over the threshold to avoid flapping + if (controller.stick_values[index].uuid != uuid) { + if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) { + return; + } + } + + controller.stick_values[index] = stick_value; + controller.stick_values[index].uuid = uuid; if (is_configuring) { controller.analog_stick_state.left = {}; @@ -592,12 +629,23 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.trigger_values.size()) { return; } std::lock_guard lock{mutex}; - controller.trigger_values[index] = TransformToTrigger(callback); + const auto trigger_value = TransformToTrigger(callback); + + // Only read trigger values that have the same uuid or are pressed once + if (controller.stick_values[index].uuid != uuid) { + if (!trigger_value.pressed.value) { + return; + } + } + + controller.trigger_values[index] = trigger_value; + controller.trigger_values[index].uuid = uuid; if (is_configuring) { controller.gc_trigger_state.left = 0; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 2f7afff56..9a8bdf14d 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -313,21 +313,21 @@ private: * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetButton(Common::Input::CallbackStatus callback, std::size_t index); + void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the analog stick status of the controller * @param callback: A CallbackStatus containing the analog stick status * @param index: stick ID of the to be updated */ - void SetStick(Common::Input::CallbackStatus callback, std::size_t index); + void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the trigger status of the controller * @param callback: A CallbackStatus containing the trigger status * @param index: trigger ID of the to be updated */ - void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the motion status of the controller diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d2748b240..bb9c236ea 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -71,21 +71,21 @@ Tas::~Tas() { void Tas::LoadTasFiles() { script_length = 0; for (size_t i = 0; i < commands.size(); i++) { - LoadTasFile(i); + LoadTasFile(i, 0); if (commands[i].size() > script_length) { script_length = commands[i].size(); } } } -void Tas::LoadTasFile(size_t player_index) { +void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (!commands[player_index].empty()) { commands[player_index].clear(); } - std::string file = - Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / - fmt::format("script0-{}.txt", player_index + 1), - Common::FS::FileType::BinaryFile); + std::string file = Common::FS::ReadStringFromFile( + Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / + fmt::format("script{}-{}.txt", file_index, player_index + 1), + Common::FS::FileType::BinaryFile); std::stringstream command_line(file); std::string line; int frame_no = 0; @@ -144,15 +144,8 @@ void Tas::WriteTasFile(std::u8string file_name) { void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) { last_input = { .buttons = buttons, - .l_axis = FlipAxisY(left_axis), - .r_axis = FlipAxisY(right_axis), - }; -} - -TasAnalog Tas::FlipAxisY(TasAnalog old) { - return { - .x = old.x, - .y = -old.y, + .l_axis = left_axis, + .r_axis = right_axis, }; } @@ -219,6 +212,7 @@ void Tas::UpdateThread() { } } else { is_running = Settings::values.tas_loop.GetValue(); + LoadTasFiles(); current_command = 0; ClearInput(); } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 82dc9d616..bfb37a638 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -138,21 +138,16 @@ private: void LoadTasFiles(); /** Loads TAS file from the specified player - * @param player_index: player number where data is going to be stored + * @param player_index: player number to save the script + * @param file_index: script number of the file */ - void LoadTasFile(size_t player_index); + void LoadTasFile(size_t player_index, size_t file_index); /** Writes a TAS file from the recorded commands * @param file_name: name of the file to be written */ void WriteTasFile(std::u8string file_name); - /** Inverts the Y axis polarity - * @param old: value of the axis - * @return new value of the axis - */ - TasAnalog FlipAxisY(TasAnalog old); - /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 * @param line: string containing axis values with the following format "x;y" From c35af8d1c05d94028b215df7721e5235083bcb97 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 3 Nov 2021 17:06:21 -0600 Subject: [PATCH 113/291] input_common: Fix motion from 3 axis --- src/input_common/input_poller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 01c435802..92cf690cd 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -606,6 +606,8 @@ public: .raw_value = input_engine->GetAxis(identifier, axis_z), .properties = properties_z, }; + status.delta_timestamp = 5000; + status.force_update = true; return status; } From 84c58666a4dbb6d46e132514e4d91437fb689fa0 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 3 Nov 2021 22:35:45 -0600 Subject: [PATCH 114/291] config: Cleanup and documentation --- src/common/input.h | 34 ++++++++- src/common/settings.h | 3 - src/core/hid/emulated_console.cpp | 6 +- src/yuzu/configuration/config.cpp | 4 -- .../configuration/configure_motion_touch.cpp | 8 +-- .../configuration/configure_motion_touch.ui | 70 ++----------------- src/yuzu_cmd/config.cpp | 3 - src/yuzu_cmd/default_ini.h | 17 +---- 8 files changed, 46 insertions(+), 99 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index f21872b0a..d997853c6 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -15,6 +15,7 @@ namespace Common::Input { +// Type of data that is expected to recieve or send enum class InputType { None, Battery, @@ -30,6 +31,7 @@ enum class InputType { Ir, }; +// Internal battery charge level enum class BatteryLevel : u32 { None, Empty, @@ -41,13 +43,17 @@ enum class BatteryLevel : u32 { }; enum class PollingMode { + // Constant polling of buttons, analogs and motion data Active, + // Only update on button change, digital analogs Pasive, - Camera, - NCF, + // Enable near field communication polling + NFC, + // Enable infrared camera polling IR, }; +// Vibration reply from the controller enum class VibrationError { None, NotSupported, @@ -55,6 +61,7 @@ enum class VibrationError { Unknown, }; +// Polling mode reply from the controller enum class PollingError { None, NotSupported, @@ -67,20 +74,28 @@ enum class VibrationAmplificationType { Exponential, }; +// Analog properties for calibration struct AnalogProperties { + // Anything below this value will be detected as zero float deadzone{}; + // Anyting above this values will be detected as one float range{1.0f}; + // Minimum value to be detected as active float threshold{0.5f}; + // Drift correction applied to the raw data float offset{}; + // Invert direction of the sensor data bool inverted{}; }; +// Single analog sensor data struct AnalogStatus { float value{}; float raw_value{}; AnalogProperties properties{}; }; +// Button data struct ButtonStatus { Common::UUID uuid{}; bool value{}; @@ -89,8 +104,10 @@ struct ButtonStatus { bool locked{}; }; +// Internal battery data using BatteryStatus = BatteryLevel; +// Analog and digital joystick data struct StickStatus { Common::UUID uuid{}; AnalogStatus x{}; @@ -101,18 +118,21 @@ struct StickStatus { bool down{}; }; +// Analog and digital trigger data struct TriggerStatus { Common::UUID uuid{}; AnalogStatus analog{}; ButtonStatus pressed{}; }; +// 3D vector representing motion input struct MotionSensor { AnalogStatus x{}; AnalogStatus y{}; AnalogStatus z{}; }; +// Motion data used to calculate controller orientation struct MotionStatus { // Gyroscope vector measurement in radians/s. MotionSensor gyro{}; @@ -124,6 +144,7 @@ struct MotionStatus { bool force_update{}; }; +// Data of a single point on a touch screen struct TouchStatus { ButtonStatus pressed{}; AnalogStatus x{}; @@ -131,11 +152,13 @@ struct TouchStatus { int id{}; }; +// Physical controller color in RGB format struct BodyColorStatus { u32 body{}; u32 buttons{}; }; +// HD rumble data struct VibrationStatus { f32 low_amplitude{}; f32 low_frequency{}; @@ -144,6 +167,7 @@ struct VibrationStatus { VibrationAmplificationType type; }; +// Physical controller LED pattern struct LedStatus { bool led_1{}; bool led_2{}; @@ -151,6 +175,7 @@ struct LedStatus { bool led_4{}; }; +// Callback data consisting of an input type and the equivalent data status struct CallbackStatus { InputType type{InputType::None}; ButtonStatus button_status{}; @@ -164,6 +189,7 @@ struct CallbackStatus { VibrationStatus vibration_status{}; }; +// Triggered once every input change struct InputCallback { std::function on_change; }; @@ -178,15 +204,17 @@ public: return; } - // Force input device to update data regarless of the current state + // Force input device to update data regardless of the current state virtual void ForceUpdate() { return; } + // Sets the function to be triggered when input changes void SetCallback(InputCallback callback_) { callback = std::move(callback_); } + // Triggers the function set in the callback void TriggerOnChange(CallbackStatus status) { if (callback.on_change) { callback.on_change(status); diff --git a/src/common/settings.h b/src/common/settings.h index 95225fba7..b52d0d1d0 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -559,8 +559,6 @@ struct Values { Setting enable_accurate_vibrations{false, "enable_accurate_vibrations"}; Setting motion_enabled{true, "motion_enabled"}; - BasicSetting motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01", - "motion_device"}; BasicSetting udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; BasicSetting pause_tas_on_load{true, "pause_tas_on_load"}; @@ -583,7 +581,6 @@ struct Values { TouchscreenInput touchscreen; - BasicSetting use_touch_from_button{false, "use_touch_from_button"}; BasicSetting touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"}; BasicSetting touch_from_button_map_index{0, "touch_from_button_map"}; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index dfbaa3f8c..b51c72eae 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -11,7 +11,7 @@ EmulatedConsole::EmulatedConsole() = default; EmulatedConsole::~EmulatedConsole() = default; void EmulatedConsole::ReloadFromSettings() { - // Using first motion device from player 1. No need to assign a special config at the moment + // Using first motion device from player 1. No need to assign any unique config at the moment const auto& player = Settings::values.players.GetValue()[0]; motion_params = Common::ParamPackage(player.motions[0]); @@ -33,6 +33,7 @@ void EmulatedConsole::SetTouchParams() { static_cast(Settings::values.touch_from_button_map_index.GetValue()); const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons; + // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { Common::ParamPackage params{config_entry}; Common::ParamPackage touch_button_params; @@ -54,7 +55,9 @@ void EmulatedConsole::SetTouchParams() { } void EmulatedConsole::ReloadInput() { + // If you load any device here add the equivalent to the UnloadInput() function SetTouchParams(); + motion_devices = Common::Input::CreateDevice(motion_params); if (motion_devices) { Common::Input::InputCallback motion_callback{ @@ -62,6 +65,7 @@ void EmulatedConsole::ReloadInput() { motion_devices->SetCallback(motion_callback); } + // Unique index for identifying touch device source std::size_t index = 0; for (auto& touch_device : touch_devices) { touch_device = Common::Input::CreateDevice(touch_params[index]); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7a748d9c8..7669fe474 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -623,9 +623,7 @@ void Config::ReadMotionTouchValues() { } qt_config->endArray(); - ReadBasicSetting(Settings::values.motion_device); ReadBasicSetting(Settings::values.touch_device); - ReadBasicSetting(Settings::values.use_touch_from_button); ReadBasicSetting(Settings::values.touch_from_button_map_index); Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); @@ -1131,9 +1129,7 @@ void Config::SaveTouchscreenValues() { } void Config::SaveMotionTouchValues() { - WriteBasicSetting(Settings::values.motion_device); WriteBasicSetting(Settings::values.touch_device); - WriteBasicSetting(Settings::values.use_touch_from_button); WriteBasicSetting(Settings::values.touch_from_button_map_index); WriteBasicSetting(Settings::values.udp_input_servers); diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 9fd1a919f..8539a5c8b 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -93,6 +93,7 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, "using-a-controller-or-android-phone-for-motion-or-touch-input'>Learn More")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); SetConfiguration(); UpdateUiDisplay(); ConnectEvents(); @@ -101,17 +102,14 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::SetConfiguration() { - const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue()); const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); - ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue()); touch_from_button_maps = Settings::values.touch_from_button_maps; for (const auto& touch_map : touch_from_button_maps) { ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); } ui->touch_from_button_map->setCurrentIndex( Settings::values.touch_from_button_map_index.GetValue()); - ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f)); min_x = touch_param.Get("min_x", 100); min_y = touch_param.Get("min_y", 50); @@ -139,9 +137,6 @@ void ConfigureMotionTouch::SetConfiguration() { void ConfigureMotionTouch::UpdateUiDisplay() { const QString cemuhook_udp = QStringLiteral("cemuhookudp"); - ui->motion_sensitivity_label->setVisible(true); - ui->motion_sensitivity->setVisible(true); - ui->touch_calibration->setVisible(true); ui->touch_calibration_config->setVisible(true); ui->touch_calibration_label->setVisible(true); @@ -312,7 +307,6 @@ void ConfigureMotionTouch::ApplyConfiguration() { touch_param.Set("max_y", max_y); Settings::values.touch_device = touch_param.Serialize(); - Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); Settings::values.touch_from_button_maps = touch_from_button_maps; Settings::values.udp_input_servers = GetUDPServerString(); diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index 1e35ea946..c75a84ae4 100644 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui @@ -2,14 +2,6 @@ ConfigureMotionTouch - - - 0 - 0 - 500 - 482 - - Configure Motion / Touch @@ -17,48 +9,6 @@ - - - - Mouse Motion - - - - - - - - Sensitivity: - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 4 - - - 0.010000000000000 - - - 10.000000000000000 - - - 0.001000000000000 - - - 0.010000000000000 - - - - - - - - @@ -101,19 +51,13 @@ - - - - - 0 - 0 - - - - Use button mapping: - - - + + + + Touch from button profile: + + + diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 103a12b12..7ca09a635 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -292,8 +292,6 @@ void Config::ReadValues() { Settings::values.mouse_buttons[i] = default_param; } - ReadSetting("ControlsGeneral", Settings::values.motion_device); - ReadSetting("ControlsGeneral", Settings::values.touch_device); ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled); @@ -362,7 +360,6 @@ void Config::ReadValues() { Settings::TouchFromButtonMap{"default", {}}); num_touch_from_button_maps = 1; } - ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button); Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index ecdc271a8..6d613bf7a 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -84,23 +84,10 @@ enable_accurate_vibrations= # 0: Disabled, 1 (default): Enabled motion_enabled = -# for motion input, the following devices are available: -# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: -# - "update_period": update period in milliseconds (default to 100) -# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01) -# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol -motion_device= - -# for touch input, the following devices are available: -# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required -# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol -# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system +# Defines the udp device's touch screen coordinate system for cemuhookudp devices +# - "min_x", "min_y", "max_x", "max_y" touch_device= -# Whether to enable or disable touch input from button -# 0 (default): Disabled, 1: Enabled -use_touch_from_button= - # for mapping buttons to touch inputs. #touch_from_button_map=1 #touch_from_button_maps_0_name=default From 5d0f3540c4b085103afa27d6120ea29e0324a5a2 Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 4 Nov 2021 12:08:54 -0600 Subject: [PATCH 115/291] core/hid: Rename NpadType to NpadStyleIndex --- src/core/frontend/applets/controller.cpp | 10 +- src/core/hid/emulated_controller.cpp | 44 +++--- src/core/hid/emulated_controller.h | 18 +-- src/core/hid/hid_types.h | 13 +- src/core/hle/service/hid/controllers/npad.cpp | 129 +++++++++--------- src/core/hle/service/hid/controllers/npad.h | 11 +- src/core/hle/service/hid/hid.cpp | 14 +- src/yuzu/applets/qt_controller.cpp | 65 ++++----- src/yuzu/applets/qt_controller.h | 8 +- src/yuzu/applets/qt_software_keyboard.cpp | 14 +- .../configuration/configure_input_player.cpp | 87 ++++++------ .../configuration/configure_input_player.h | 8 +- .../configure_input_player_widget.cpp | 18 +-- .../configure_input_player_widget.h | 2 +- src/yuzu/main.cpp | 2 +- 15 files changed, 228 insertions(+), 215 deletions(-) diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 212ace892..6dbd38ffa 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -44,26 +44,26 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb // Connect controllers based on the following priority list from highest to lowest priority: // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld if (parameters.allow_pro_controller) { - controller->SetNpadType(Core::HID::NpadType::ProController); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); controller->Connect(); } else if (parameters.allow_dual_joycons) { - controller->SetNpadType(Core::HID::NpadType::JoyconDual); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); controller->Connect(); } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { // Assign left joycons to even player indices and right joycons to odd player indices. // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and // a right Joycon for Player 2 in 2 Player Assist mode. if (index % 2 == 0) { - controller->SetNpadType(Core::HID::NpadType::JoyconLeft); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); controller->Connect(); } else { - controller->SetNpadType(Core::HID::NpadType::JoyconRight); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); controller->Connect(); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && !Settings::values.use_docked_mode.GetValue()) { // We should *never* reach here under any normal circumstances. - controller->SetNpadType(Core::HID::NpadType::Handheld); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); controller->Connect(); } else { UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 6fe3744fd..a200992f2 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -13,38 +13,38 @@ EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type( EmulatedController::~EmulatedController() = default; -NpadType EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { +NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { switch (type) { case Settings::ControllerType::ProController: - return NpadType::ProController; + return NpadStyleIndex::ProController; case Settings::ControllerType::DualJoyconDetached: - return NpadType::JoyconDual; + return NpadStyleIndex::JoyconDual; case Settings::ControllerType::LeftJoycon: - return NpadType::JoyconLeft; + return NpadStyleIndex::JoyconLeft; case Settings::ControllerType::RightJoycon: - return NpadType::JoyconRight; + return NpadStyleIndex::JoyconRight; case Settings::ControllerType::Handheld: - return NpadType::Handheld; + return NpadStyleIndex::Handheld; case Settings::ControllerType::GameCube: - return NpadType::GameCube; + return NpadStyleIndex::GameCube; default: - return NpadType::ProController; + return NpadStyleIndex::ProController; } } -Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type) { +Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) { switch (type) { - case NpadType::ProController: + case NpadStyleIndex::ProController: return Settings::ControllerType::ProController; - case NpadType::JoyconDual: + case NpadStyleIndex::JoyconDual: return Settings::ControllerType::DualJoyconDetached; - case NpadType::JoyconLeft: + case NpadStyleIndex::JoyconLeft: return Settings::ControllerType::LeftJoycon; - case NpadType::JoyconRight: + case NpadStyleIndex::JoyconRight: return Settings::ControllerType::RightJoycon; - case NpadType::Handheld: + case NpadStyleIndex::Handheld: return Settings::ControllerType::Handheld; - case NpadType::GameCube: + case NpadStyleIndex::GameCube: return Settings::ControllerType::GameCube; default: return Settings::ControllerType::ProController; @@ -79,9 +79,9 @@ void EmulatedController::ReloadFromSettings() { // Other or debug controller should always be a pro controller if (npad_id_type != NpadIdType::Other) { - SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); } else { - SetNpadType(NpadType::ProController); + SetNpadStyleIndex(NpadStyleIndex::ProController); } if (player.connected) { @@ -306,7 +306,7 @@ void EmulatedController::DisableConfiguration() { if (is_connected) { Disconnect(); } - SetNpadType(tmp_npad_type); + SetNpadStyleIndex(tmp_npad_type); } // Apply temporary connected status to the real controller @@ -569,10 +569,10 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: } } if (!is_connected) { - if (npad_id_type == NpadIdType::Player1 && npad_type != NpadType::Handheld) { + if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) { Connect(); } - if (npad_id_type == NpadIdType::Handheld && npad_type == NpadType::Handheld) { + if (npad_id_type == NpadIdType::Handheld && npad_type == NpadStyleIndex::Handheld) { Connect(); } } @@ -896,14 +896,14 @@ NpadIdType EmulatedController::GetNpadIdType() const { return npad_id_type; } -NpadType EmulatedController::GetNpadType(bool get_temporary_value) const { +NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { if (get_temporary_value) { return tmp_npad_type; } return npad_type; } -void EmulatedController::SetNpadType(NpadType npad_type_) { +void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { { std::lock_guard lock{mutex}; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 9a8bdf14d..fa2e89c0b 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -142,23 +142,23 @@ public: YUZU_NON_MOVEABLE(EmulatedController); /// Converts the controller type from settings to npad type - static NpadType MapSettingsTypeToNPad(Settings::ControllerType type); + static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type); /// Converts npad type to the equivalent of controller type from settings - static Settings::ControllerType MapNPadToSettingsType(NpadType type); + static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type); /// Gets the NpadIdType for this controller NpadIdType GetNpadIdType() const; - /// Sets the NpadType for this controller - void SetNpadType(NpadType npad_type_); + /// Sets the NpadStyleIndex for this controller + void SetNpadStyleIndex(NpadStyleIndex npad_type_); /** - * Gets the NpadType for this controller + * Gets the NpadStyleIndex for this controller * @param If true tmp_npad_type will be returned - * @return NpadType set on the controller + * @return NpadStyleIndex set on the controller */ - NpadType GetNpadType(bool get_temporary_value = false) const; + NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const; /// Sets the connected status to true void Connect(); @@ -351,14 +351,14 @@ private: void TriggerOnChange(ControllerTriggerType type, bool is_service_update); NpadIdType npad_id_type; - NpadType npad_type{NpadType::None}; + NpadStyleIndex npad_type{NpadStyleIndex::None}; bool is_connected{false}; bool is_configuring{false}; f32 motion_sensitivity{0.01f}; bool force_update_motion{false}; // Temporary values to avoid doing changes while the controller is on configuration mode - NpadType tmp_npad_type{NpadType::None}; + NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; bool tmp_is_connected{false}; ButtonParams button_params; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index f8a0d5edd..7e4f6a804 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -84,8 +84,8 @@ constexpr NpadIdType IndexToNpadIdType(size_t index) { } } -// This is nn::hid::NpadType -enum class NpadType : u8 { +// This is nn::hid::NpadStyleIndex +enum class NpadStyleIndex : u8 { None = 0, ProController = 3, Handheld = 4, @@ -94,7 +94,14 @@ enum class NpadType : u8 { JoyconRight = 7, GameCube = 8, Pokeball = 9, - MaxNpadType = 10, + NES = 10, + HandheldNES = 11, + SNES = 12, + N64 = 13, + SegaGenesis = 14, + SystemExt = 32, + System = 33, + MaxNpadType = 34, }; // This is nn::hid::NpadStyleTag diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 0b5a23696..e4a3d9163 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -93,7 +93,7 @@ bool Controller_NPad::IsNpadIdValid(u32 npad_id) { bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { return IsNpadIdValid(device_handle.npad_id) && - device_handle.npad_type < Core::HID::NpadType::MaxNpadType && + device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && device_handle.device_index < DeviceIndex::MaxDeviceIndex; } @@ -134,7 +134,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, auto& controller = controller_data[controller_idx]; const auto is_connected = controller.device->IsConnected(); - const auto npad_type = controller.device->GetNpadType(); + const auto npad_type = controller.device->GetNpadStyleIndex(); switch (type) { case Core::HID::ControllerTriggerType::Connected: case Core::HID::ControllerTriggerType::Disconnected: @@ -161,9 +161,9 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { auto& controller = controller_data[controller_idx]; - const auto controller_type = controller.device->GetNpadType(); + const auto controller_type = controller.device->GetNpadStyleIndex(); auto& shared_memory = controller.shared_memory_entry; - if (controller_type == Core::HID::NpadType::None) { + if (controller_type == Core::HID::NpadStyleIndex::None) { controller.styleset_changed_event->GetWritableEvent().Signal(); return; } @@ -171,10 +171,10 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.device_type.raw = 0; shared_memory.system_properties.raw = 0; switch (controller_type) { - case Core::HID::NpadType::None: + case Core::HID::NpadStyleIndex::None: UNREACHABLE(); break; - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: shared_memory.style_set.fullkey.Assign(1); shared_memory.device_type.fullkey.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); @@ -183,7 +183,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; break; - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: shared_memory.style_set.handheld.Assign(1); shared_memory.device_type.handheld_left.Assign(1); shared_memory.device_type.handheld_right.Assign(1); @@ -193,7 +193,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: shared_memory.style_set.joycon_dual.Assign(1); shared_memory.device_type.joycon_left.Assign(1); shared_memory.device_type.joycon_right.Assign(1); @@ -203,7 +203,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: shared_memory.style_set.joycon_left.Assign(1); shared_memory.device_type.joycon_left.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); @@ -211,7 +211,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: shared_memory.style_set.joycon_right.Assign(1); shared_memory.device_type.joycon_right.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); @@ -219,14 +219,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: shared_memory.style_set.gamecube.Assign(1); // The GC Controller behaves like a wired Pro Controller shared_memory.device_type.fullkey.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); break; - case Core::HID::NpadType::Pokeball: + case Core::HID::NpadStyleIndex::Pokeball: shared_memory.style_set.palma.Assign(1); shared_memory.device_type.palma.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; @@ -307,7 +307,7 @@ void Controller_NPad::OnInit() { const auto& device = controller.device; if (device->IsConnected()) { const std::size_t index = Core::HID::NpadIdTypeToIndex(device->GetNpadIdType()); - AddNewControllerAt(device->GetNpadType(), index); + AddNewControllerAt(device->GetNpadStyleIndex(), index); } } } @@ -347,7 +347,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { std::lock_guard lock{mutex}; const auto controller_idx = NPadIdToIndex(npad_id); auto& controller = controller_data[controller_idx]; - const auto controller_type = controller.device->GetNpadType(); + const auto controller_type = controller.device->GetNpadStyleIndex(); if (!controller.device->IsConnected()) { return; } @@ -359,7 +359,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { using btn = Core::HID::NpadButton; pad_entry.npad_buttons.raw = btn::None; - if (controller_type != Core::HID::NpadType::JoyconLeft) { + if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | btn::StickRRight | btn::StickRDown; @@ -367,7 +367,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { pad_entry.r_stick = stick_state.right; } - if (controller_type != Core::HID::NpadType::JoyconRight) { + if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { constexpr btn left_button_mask = btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL | btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown; @@ -375,17 +375,17 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { pad_entry.l_stick = stick_state.left; } - if (controller_type == Core::HID::NpadType::JoyconLeft) { + if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) { 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::NpadType::JoyconRight) { + if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) { pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); } - if (controller_type == Core::HID::NpadType::GameCube) { + if (controller_type == Core::HID::NpadStyleIndex::GameCube) { const auto& trigger_state = controller.device->GetTriggers(); trigger_entry.l_analog = trigger_state.left; trigger_entry.r_analog = trigger_state.right; @@ -406,9 +406,10 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* auto& controller = controller_data[i]; auto& npad = controller.shared_memory_entry; - const auto& controller_type = controller.device->GetNpadType(); + const auto& controller_type = controller.device->GetNpadStyleIndex(); - if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { + if (controller_type == Core::HID::NpadStyleIndex::None || + !controller.device->IsConnected()) { // Refresh shared memory std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), &controller.shared_memory_entry, sizeof(NpadInternalState)); @@ -426,10 +427,10 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.raw = 0; libnx_state.connection_status.is_connected.Assign(1); switch (controller_type) { - case Core::HID::NpadType::None: + case Core::HID::NpadStyleIndex::None: UNREACHABLE(); break; - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_wired.Assign(1); @@ -439,7 +440,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.fullkey_lifo.WriteNextEntry(pad_state); break; - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_wired.Assign(1); @@ -457,7 +458,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.handheld_lifo.WriteNextEntry(pad_state); break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_left_connected.Assign(1); @@ -469,7 +470,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.joy_dual_lifo.WriteNextEntry(pad_state); break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_left_connected.Assign(1); @@ -479,7 +480,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.joy_left_lifo.WriteNextEntry(pad_state); break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_right_connected.Assign(1); @@ -489,7 +490,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.joy_right_lifo.WriteNextEntry(pad_state); break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_wired.Assign(1); @@ -502,7 +503,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.fullkey_lifo.WriteNextEntry(pad_state); npad.gc_trigger_lifo.WriteNextEntry(trigger_state); break; - case Core::HID::NpadType::Pokeball: + case Core::HID::NpadStyleIndex::Pokeball: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.sampling_number = @@ -534,9 +535,10 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; - const auto& controller_type = controller.device->GetNpadType(); + const auto& controller_type = controller.device->GetNpadStyleIndex(); - if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { + if (controller_type == Core::HID::NpadStyleIndex::None || + !controller.device->IsConnected()) { continue; } @@ -557,10 +559,10 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing } switch (controller_type) { - case Core::HID::NpadType::None: + case Core::HID::NpadStyleIndex::None: UNREACHABLE(); break; - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: sixaxis_fullkey_state.attribute.raw = 0; if (sixaxis_sensors_enabled) { sixaxis_fullkey_state.attribute.is_connected.Assign(1); @@ -570,7 +572,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_fullkey_state.orientation = motion_state[0].orientation; } break; - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: sixaxis_handheld_state.attribute.raw = 0; if (sixaxis_sensors_enabled) { sixaxis_handheld_state.attribute.is_connected.Assign(1); @@ -580,7 +582,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_handheld_state.orientation = motion_state[0].orientation; } break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: sixaxis_dual_left_state.attribute.raw = 0; sixaxis_dual_right_state.attribute.raw = 0; if (sixaxis_sensors_enabled) { @@ -600,7 +602,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_dual_right_state.orientation = motion_state[1].orientation; } break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: sixaxis_left_lifo_state.attribute.raw = 0; if (sixaxis_sensors_enabled) { sixaxis_left_lifo_state.attribute.is_connected.Assign(1); @@ -610,7 +612,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_left_lifo_state.orientation = motion_state[0].orientation; } break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: sixaxis_right_lifo_state.attribute.raw = 0; if (sixaxis_sensors_enabled) { sixaxis_right_lifo_state.attribute.is_connected.Assign(1); @@ -779,11 +781,11 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han } // Some games try to send mismatched parameters in the device handle, block these. - if ((controller.device->GetNpadType() == Core::HID::NpadType::JoyconLeft && - (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconRight || + if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && + (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || vibration_device_handle.device_index == DeviceIndex::Right)) || - (controller.device->GetNpadType() == Core::HID::NpadType::JoyconRight && - (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconLeft || + (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && + (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || vibration_device_handle.device_index == DeviceIndex::Left))) { return; } @@ -876,11 +878,12 @@ void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { controller.styleset_changed_event->GetWritableEvent().Signal(); } -void Controller_NPad::AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index) { +void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, + std::size_t npad_index) { UpdateControllerAt(controller, npad_index, true); } -void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index, +void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, std::size_t npad_index, bool connected) { auto& controller = controller_data[npad_index]; if (!connected) { @@ -888,7 +891,7 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t n return; } - controller.device->SetNpadType(type); + controller.device->SetNpadStyleIndex(type); InitNewlyAddedController(npad_index); } @@ -971,13 +974,13 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { // If the controllers at both npad indices form a pair of left and right joycons, merge them. // Otherwise, do nothing. - if ((controller_1->GetNpadType() == Core::HID::NpadType::JoyconLeft && - controller_2->GetNpadType() == Core::HID::NpadType::JoyconRight) || - (controller_2->GetNpadType() == Core::HID::NpadType::JoyconLeft && - controller_1->GetNpadType() == Core::HID::NpadType::JoyconRight)) { + if ((controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && + controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) || + (controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && + controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) { // Disconnect the joycon at the second id and connect the dual joycon at the first index. DisconnectNpad(npad_id_2); - AddNewControllerAt(Core::HID::NpadType::JoyconDual, npad_index_1); + AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_index_1); } } @@ -1000,8 +1003,8 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { const auto npad_index_2 = NPadIdToIndex(npad_id_2); const auto& controller_1 = controller_data[npad_index_1].device; const auto& controller_2 = controller_data[npad_index_2].device; - const auto type_index_1 = controller_1->GetNpadType(); - const auto type_index_2 = controller_2->GetNpadType(); + const auto type_index_1 = controller_1->GetNpadStyleIndex(); + const auto type_index_2 = controller_2->GetNpadStyleIndex(); if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) { return false; @@ -1039,9 +1042,9 @@ void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { void Controller_NPad::ClearAllConnectedControllers() { for (auto& controller : controller_data) { if (controller.device->IsConnected() && - controller.device->GetNpadType() != Core::HID::NpadType::None) { - controller.device->SetNpadType(Core::HID::NpadType::None); + controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { controller.device->Disconnect(); + controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); } } } @@ -1054,7 +1057,7 @@ void Controller_NPad::DisconnectAllConnectedControllers() { void Controller_NPad::ConnectAllDisconnectedControllers() { for (auto& controller : controller_data) { - if (controller.device->GetNpadType() != Core::HID::NpadType::None && + if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && !controller.device->IsConnected()) { controller.device->Connect(); } @@ -1063,8 +1066,8 @@ void Controller_NPad::ConnectAllDisconnectedControllers() { void Controller_NPad::ClearAllControllers() { for (auto& controller : controller_data) { - controller.device->SetNpadType(Core::HID::NpadType::None); controller.device->Disconnect(); + controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); } } @@ -1072,8 +1075,8 @@ u32 Controller_NPad::GetAndResetPressState() { return press_state.exchange(0); } -bool Controller_NPad::IsControllerSupported(Core::HID::NpadType controller) const { - if (controller == Core::HID::NpadType::Handheld) { +bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { + if (controller == Core::HID::NpadStyleIndex::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != supported_npad_id_types.end(); @@ -1093,17 +1096,17 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadType controller) cons [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { Core::HID::NpadStyleTag style = GetSupportedStyleSet(); switch (controller) { - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: return style.fullkey; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: return style.joycon_dual; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: return style.joycon_left; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: return style.joycon_right; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: return style.gamecube; - case Core::HID::NpadType::Pokeball: + case Core::HID::NpadStyleIndex::Pokeball: return style.palma; default: return false; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 871d245fd..512fb5afc 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -96,7 +96,7 @@ public: }; struct DeviceHandle { - Core::HID::NpadType npad_type; + Core::HID::NpadStyleIndex npad_type; u8 npad_id; DeviceIndex device_index; INSERT_PADDING_BYTES_NOINIT(1); @@ -160,9 +160,10 @@ public: void SignalStyleSetChangedEvent(u32 npad_id) const; // Adds a new controller at an index. - void AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index); + void AddNewControllerAt(Core::HID::NpadStyleIndex controller, std::size_t npad_index); // Adds a new controller at an index with connection status. - void UpdateControllerAt(Core::HID::NpadType controller, std::size_t npad_index, bool connected); + void UpdateControllerAt(Core::HID::NpadStyleIndex controller, std::size_t npad_index, + bool connected); void DisconnectNpad(u32 npad_id); void DisconnectNpadAtIndex(std::size_t index); @@ -496,7 +497,7 @@ private: std::array vibration{}; bool unintended_home_button_input_protection{}; bool is_connected{}; - Core::HID::NpadType npad_type{Core::HID::NpadType::None}; + Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; // Current pad state NPadGenericState npad_pad_state{}; @@ -513,7 +514,7 @@ private: void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); void InitNewlyAddedController(std::size_t controller_idx); - bool IsControllerSupported(Core::HID::NpadType controller) const; + bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; void RequestPadStateUpdate(u32 npad_id); void WriteEmptyEntry(NpadInternalState& npad); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ac48f96d3..648e69de9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -1131,18 +1131,18 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { Core::HID::VibrationDeviceInfo vibration_device_info; switch (vibration_device_handle.npad_type) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::Handheld: - case Core::HID::NpadType::JoyconDual: - case Core::HID::NpadType::JoyconLeft: - case Core::HID::NpadType::JoyconRight: + 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: default: vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; break; - case Core::HID::NpadType::Pokeball: + case Core::HID::NpadStyleIndex::Pokeball: vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; break; } diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 9c6377cf0..6a2cdda63 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -28,31 +28,31 @@ namespace { void UpdateController(Core::HID::EmulatedController* controller, - Core::HID::NpadType controller_type, bool connected) { + Core::HID::NpadStyleIndex controller_type, bool connected) { if (controller->IsConnected()) { controller->Disconnect(); } - controller->SetNpadType(controller_type); + controller->SetNpadStyleIndex(controller_type); if (connected) { controller->Connect(); } } // Returns true if the given controller type is compatible with the given parameters. -bool IsControllerCompatible(Core::HID::NpadType controller_type, +bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, Core::Frontend::ControllerParameters parameters) { switch (controller_type) { - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: return parameters.allow_pro_controller; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: return parameters.allow_dual_joycons; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: return parameters.allow_left_joycon; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: return parameters.allow_right_joycon; - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: return parameters.enable_single_mode && parameters.allow_handheld; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: return parameters.allow_gamecube_controller; default: return false; @@ -183,7 +183,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( connect(emulated_controllers[i], qOverload(&QComboBox::currentIndexChanged), [this, i](int index) { UpdateDockedState(GetControllerTypeFromIndex(index, i) == - Core::HID::NpadType::Handheld); + Core::HID::NpadStyleIndex::Handheld); }); } } @@ -243,7 +243,7 @@ void QtControllerSelectorDialog::LoadConfiguration() { player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); emulated_controllers[index]->setCurrentIndex( - GetIndexFromControllerType(controller->GetNpadType(), index)); + GetIndexFromControllerType(controller->GetNpadStyleIndex(), index)); } UpdateDockedState(handheld->IsConnected()); @@ -402,32 +402,33 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index emulated_controllers[player_index]->clear(); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadType::ProController); + Core::HID::NpadStyleIndex::ProController); emulated_controllers[player_index]->addItem(tr("Pro Controller")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadType::JoyconDual); + Core::HID::NpadStyleIndex::JoyconDual); emulated_controllers[player_index]->addItem(tr("Dual Joycons")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadType::JoyconLeft); + Core::HID::NpadStyleIndex::JoyconLeft); emulated_controllers[player_index]->addItem(tr("Left Joycon")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadType::JoyconRight); + Core::HID::NpadStyleIndex::JoyconRight); emulated_controllers[player_index]->addItem(tr("Right Joycon")); if (player_index == 0) { pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadType::Handheld); + Core::HID::NpadStyleIndex::Handheld); emulated_controllers[player_index]->addItem(tr("Handheld")); } - pairs.emplace_back(emulated_controllers[player_index]->count(), Core::HID::NpadType::GameCube); + pairs.emplace_back(emulated_controllers[player_index]->count(), + Core::HID::NpadStyleIndex::GameCube); emulated_controllers[player_index]->addItem(tr("GameCube Controller")); } -Core::HID::NpadType QtControllerSelectorDialog::GetControllerTypeFromIndex( +Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex( int index, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -435,13 +436,13 @@ Core::HID::NpadType QtControllerSelectorDialog::GetControllerTypeFromIndex( [index](const auto& pair) { return pair.first == index; }); if (it == pairs.end()) { - return Core::HID::NpadType::ProController; + return Core::HID::NpadStyleIndex::ProController; } return it->second; } -int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadType type, +int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -465,16 +466,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) const QString stylesheet = [this, player_index] { switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), player_index)) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::GameCube: return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: return QStringLiteral("image: url(:/controller/applet_handheld%0); "); default: return QString{}; @@ -507,9 +508,9 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) const auto controller_type = GetControllerTypeFromIndex( emulated_controllers[player_index]->currentIndex(), player_index); const auto player_connected = player_groupboxes[player_index]->isChecked() && - controller_type != Core::HID::NpadType::Handheld; + controller_type != Core::HID::NpadStyleIndex::Handheld; - if (controller->GetNpadType() == controller_type && + if (controller->GetNpadStyleIndex() == controller_type && controller->IsConnected() == player_connected) { // Set vibration devices in the event that the input device has changed. ConfigureVibration::SetVibrationDevices(player_index); @@ -523,10 +524,10 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) // Handheld if (player_index == 0) { - if (controller_type == Core::HID::NpadType::Handheld) { + if (controller_type == Core::HID::NpadStyleIndex::Handheld) { auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - UpdateController(handheld, Core::HID::NpadType::Handheld, + UpdateController(handheld, Core::HID::NpadStyleIndex::Handheld, player_groupboxes[player_index]->isChecked()); } } @@ -537,7 +538,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { if (!player_groupboxes[player_index]->isChecked() || GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), - player_index) == Core::HID::NpadType::Handheld) { + player_index) == Core::HID::NpadStyleIndex::Handheld) { led_patterns_boxes[player_index][0]->setChecked(false); led_patterns_boxes[player_index][1]->setChecked(false); led_patterns_boxes[player_index][2]->setChecked(false); @@ -632,7 +633,7 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); // Disconnect any unsupported players here and disable or hide them if applicable. - UpdateController(controller, controller->GetNpadType(), false); + UpdateController(controller, controller->GetNpadStyleIndex(), false); // Hide the player widgets when max_supported_controllers is less than or equal to 4. if (max_supported_players <= 4) { player_widgets[index]->hide(); diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index dd981f479..cc343e5ae 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -32,7 +32,7 @@ class System; } namespace Core::HID { -enum class NpadType : u8; +enum class NpadStyleIndex : u8; } class QtControllerSelectorDialog final : public QDialog { @@ -74,10 +74,10 @@ private: void SetEmulatedControllers(std::size_t player_index); // Gets the Controller Type for a given controller combobox index per player. - Core::HID::NpadType GetControllerTypeFromIndex(int index, std::size_t player_index) const; + Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const; // Gets the controller combobox index for a given Controller Type per player. - int GetIndexFromControllerType(Core::HID::NpadType type, std::size_t player_index) const; + int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const; // Updates the controller icons per player. void UpdateControllerIcon(std::size_t player_index); @@ -139,7 +139,7 @@ private: std::array emulated_controllers; /// Pairs of emulated controller index and Controller Type enum per player. - std::array>, NUM_PLAYERS> + std::array>, NUM_PLAYERS> index_controller_type_pairs; // Labels representing the number of connected controllers diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index 3d91f8034..de7f98c4f 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -801,7 +801,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto controller_type = - handheld->IsConnected() ? handheld->GetNpadType() : player_1->GetNpadType(); + handheld->IsConnected() ? handheld->GetNpadStyleIndex() : player_1->GetNpadStyleIndex(); const QString theme = [] { if (QIcon::themeName().contains(QStringLiteral("dark")) || @@ -813,8 +813,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { }(); switch (controller_type) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::GameCube: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -822,7 +822,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -830,7 +830,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); @@ -841,7 +841,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); @@ -852,7 +852,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); break; - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 8d6289d8e..95a9b8614 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -455,7 +455,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int index) { emit HandheldStateChanged(GetControllerTypeFromIndex(index) == - Core::HID::NpadType::Handheld); + Core::HID::NpadStyleIndex::Handheld); }); } @@ -482,7 +482,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - const Core::HID::NpadType type = + const Core::HID::NpadStyleIndex type = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (player_index == 0) { @@ -492,10 +492,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); bool is_connected = emulated_controller->IsConnected(true); - emulated_controller_p1->SetNpadType(type); - emulated_controller_hanheld->SetNpadType(type); + emulated_controller_p1->SetNpadStyleIndex(type); + emulated_controller_hanheld->SetNpadStyleIndex(type); if (is_connected) { - if (type == Core::HID::NpadType::Handheld) { + if (type == Core::HID::NpadStyleIndex::Handheld) { emulated_controller_p1->Disconnect(); emulated_controller_hanheld->Connect(); emulated_controller = emulated_controller_hanheld; @@ -507,7 +507,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } ui->controllerFrame->SetController(emulated_controller); } - emulated_controller->SetNpadType(type); + emulated_controller->SetNpadStyleIndex(type); }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, @@ -607,7 +607,8 @@ void ConfigureInputPlayer::LoadConfiguration() { return; } - const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType(true)); + const int comboBoxIndex = + GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true)); ui->comboControllerType->setCurrentIndex(comboBoxIndex); ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); } @@ -810,37 +811,37 @@ void ConfigureInputPlayer::SetConnectableControllers() { if (enable_all || npad_style_set.fullkey == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::ProController); + Core::HID::NpadStyleIndex::ProController); ui->comboControllerType->addItem(tr("Pro Controller")); } if (enable_all || npad_style_set.joycon_dual == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::JoyconDual); + Core::HID::NpadStyleIndex::JoyconDual); ui->comboControllerType->addItem(tr("Dual Joycons")); } if (enable_all || npad_style_set.joycon_left == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::JoyconLeft); + Core::HID::NpadStyleIndex::JoyconLeft); ui->comboControllerType->addItem(tr("Left Joycon")); } if (enable_all || npad_style_set.joycon_right == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::JoyconRight); + Core::HID::NpadStyleIndex::JoyconRight); ui->comboControllerType->addItem(tr("Right Joycon")); } if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::Handheld); + Core::HID::NpadStyleIndex::Handheld); ui->comboControllerType->addItem(tr("Handheld")); } if (enable_all || npad_style_set.gamecube == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadType::GameCube); + Core::HID::NpadStyleIndex::GameCube); ui->comboControllerType->addItem(tr("GameCube Controller")); } }; @@ -853,19 +854,19 @@ void ConfigureInputPlayer::SetConnectableControllers() { add_controllers(false, system.HIDCore().GetSupportedStyleTag()); } -Core::HID::NpadType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { +Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [index](const auto& pair) { return pair.first == index; }); if (it == index_controller_type_pairs.end()) { - return Core::HID::NpadType::ProController; + return Core::HID::NpadStyleIndex::ProController; } return it->second; } -int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadType type) const { +int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [type](const auto& pair) { return pair.second == type; }); @@ -888,7 +889,7 @@ void ConfigureInputPlayer::UpdateInputDevices() { void ConfigureInputPlayer::UpdateControllerAvailableButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadType::ProController; + layout = Core::HID::NpadStyleIndex::ProController; } // List of all the widgets that will be hidden by any of the following layouts that need @@ -913,15 +914,15 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { std::vector layout_hidden; switch (layout) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::JoyconDual: - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, }; break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget2, ui->buttonShoulderButtonsRight, @@ -929,7 +930,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomRight, }; break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget, ui->buttonShoulderButtonsLeft, @@ -937,7 +938,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomLeft, }; break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, @@ -957,7 +958,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { void ConfigureInputPlayer::UpdateControllerEnabledButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadType::ProController; + layout = Core::HID::NpadStyleIndex::ProController; } // List of all the widgets that will be disabled by any of the following layouts that need @@ -974,13 +975,13 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { std::vector layout_disable; switch (layout) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::JoyconDual: - case Core::HID::NpadType::Handheld: - case Core::HID::NpadType::JoyconLeft: - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconRight: break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: layout_disable = { ui->buttonHome, ui->buttonLStickPressedGroup, @@ -1007,24 +1008,24 @@ void ConfigureInputPlayer::UpdateMotionButtons() { // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::JoyconLeft: - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconLeft: + case Core::HID::NpadStyleIndex::Handheld: // Show "Motion 1" and hide "Motion 2". ui->buttonMotionLeftGroup->show(); ui->buttonMotionRightGroup->hide(); break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: // Show "Motion 2" and hide "Motion 1". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->show(); break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: // Hide both "Motion 1/2". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->hide(); break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: default: // Show both "Motion 1/2". ui->buttonMotionLeftGroup->show(); @@ -1036,15 +1037,15 @@ void ConfigureInputPlayer::UpdateMotionButtons() { void ConfigureInputPlayer::UpdateControllerButtonNames() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadType::ProController; + layout = Core::HID::NpadStyleIndex::ProController; } switch (layout) { - case Core::HID::NpadType::ProController: - case Core::HID::NpadType::JoyconDual: - case Core::HID::NpadType::Handheld: - case Core::HID::NpadType::JoyconLeft: - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconRight: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Plus")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("ZL")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("ZR")); @@ -1052,7 +1053,7 @@ void ConfigureInputPlayer::UpdateControllerButtonNames() { ui->LStick->setTitle(tr("Left Stick")); ui->RStick->setTitle(tr("Right Stick")); break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Start / Pause")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("L")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("R")); diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 02d6920f1..7bff4b196 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -51,7 +51,7 @@ class System; namespace Core::HID { class EmulatedController; -enum class NpadType : u8; +enum class NpadStyleIndex : u8; } // namespace Core::HID class ConfigureInputPlayer : public QWidget { @@ -134,10 +134,10 @@ private: void SetConnectableControllers(); /// Gets the Controller Type for a given controller combobox index. - Core::HID::NpadType GetControllerTypeFromIndex(int index) const; + Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index) const; /// Gets the controller combobox index for a given Controller Type. - int GetIndexFromControllerType(Core::HID::NpadType type) const; + int GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const; /// Update the available input devices. void UpdateInputDevices(); @@ -182,7 +182,7 @@ private: std::unique_ptr poll_timer; /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. - std::vector> index_controller_type_pairs; + std::vector> index_controller_type_pairs; static constexpr int PLAYER_COUNT = 8; std::array player_connected_checkbox; diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 7e71a0f58..e63c25e70 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -147,7 +147,7 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ needs_redraw = true; break; case Core::HID::ControllerTriggerType::Type: - controller_type = controller->GetNpadType(true); + controller_type = controller->GetNpadStyleIndex(true); needs_redraw = true; break; case Core::HID::ControllerTriggerType::Color: @@ -221,22 +221,22 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { const QPointF center = rect().center(); switch (controller_type) { - case Core::HID::NpadType::Handheld: + case Core::HID::NpadStyleIndex::Handheld: DrawHandheldController(p, center); break; - case Core::HID::NpadType::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconDual: DrawDualController(p, center); break; - case Core::HID::NpadType::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: DrawLeftController(p, center); break; - case Core::HID::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::JoyconRight: DrawRightController(p, center); break; - case Core::HID::NpadType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: DrawGCController(p, center); break; - case Core::HID::NpadType::ProController: + case Core::HID::NpadStyleIndex::ProController: default: DrawProController(p, center); break; @@ -2394,7 +2394,7 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right) { using namespace Settings::NativeAnalog; - if (controller_type != Core::HID::NpadType::JoyconLeft) { + if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { DrawJoystickProperties(p, center_right, stick_values[RStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); @@ -2404,7 +2404,7 @@ void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPo DrawJoystickDot(p, center_right, stick_values[RStick], false); } - if (controller_type != Core::HID::NpadType::JoyconRight) { + if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { DrawJoystickProperties(p, center_left, stick_values[LStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index acc53a9e3..ee217f3c9 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -203,7 +203,7 @@ private: bool is_controller_set{}; bool is_connected{}; bool needs_redraw{}; - Core::HID::NpadType controller_type; + Core::HID::NpadStyleIndex controller_type; bool mapping_active{}; int blink_counter{}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7c95851b3..a10522f5f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -841,7 +841,7 @@ void GMainWindow::InitializeWidgets() { tr("Handheld controller can't be used on docked mode. Pro " "controller will be selected.")); handheld->Disconnect(); - player_1->SetNpadType(Core::HID::NpadType::ProController); + player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); player_1->Connect(); } From d14e74132ceaa8b5efef8a7d543cb50429cb4fb3 Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 4 Nov 2021 13:08:30 -0600 Subject: [PATCH 116/291] settings: Fix controller preview not displaying the correct controller --- src/core/hid/emulated_controller.cpp | 4 ++-- src/yuzu/configuration/configure_input_player_widget.cpp | 4 ++-- src/yuzu/main.cpp | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a200992f2..a9038e06f 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -880,7 +880,7 @@ void EmulatedController::Disconnect() { } bool EmulatedController::IsConnected(bool get_temporary_value) const { - if (get_temporary_value) { + if (get_temporary_value && is_configuring) { return tmp_is_connected; } return is_connected; @@ -897,7 +897,7 @@ NpadIdType EmulatedController::GetNpadIdType() const { } NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { - if (get_temporary_value) { + if (get_temporary_value && is_configuring) { return tmp_npad_type; } return npad_type; diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index e63c25e70..af65cf64c 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -2394,7 +2394,7 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right) { using namespace Settings::NativeAnalog; - if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { + if (center_right != QPointF(0, 0)) { DrawJoystickProperties(p, center_right, stick_values[RStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); @@ -2404,7 +2404,7 @@ void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPo DrawJoystickDot(p, center_right, stick_values[RStick], false); } - if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { + if (center_left != QPointF(0, 0)) { DrawJoystickProperties(p, center_left, stick_values[LStick].x.properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a10522f5f..baf7b38b4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -230,6 +230,7 @@ GMainWindow::GMainWindow() ConnectWidgetEvents(); system->HIDCore().ReloadInputDevices(); + controller_dialog->refreshConfiguration(); const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); @@ -843,6 +844,7 @@ void GMainWindow::InitializeWidgets() { handheld->Disconnect(); player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); player_1->Connect(); + controller_dialog->refreshConfiguration(); } Settings::values.use_docked_mode.SetValue(!is_docked); @@ -2744,6 +2746,7 @@ void GMainWindow::OnConfigure() { } UpdateStatusButtons(); + controller_dialog->refreshConfiguration(); } void GMainWindow::OnConfigureTas() { From b21fcd952721af357d50d487ffba9580e5a6bf00 Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 4 Nov 2021 14:43:08 -0600 Subject: [PATCH 117/291] service/hid: Add support for new controllers --- src/core/hid/hid_types.h | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 7e4f6a804..22177b5ed 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -89,13 +89,13 @@ enum class NpadStyleIndex : u8 { None = 0, ProController = 3, Handheld = 4, + HandheldNES = 4, JoyconDual = 5, JoyconLeft = 6, JoyconRight = 7, GameCube = 8, Pokeball = 9, NES = 10, - HandheldNES = 11, SNES = 12, N64 = 13, SegaGenesis = 14, diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e4a3d9163..fcc36bbc1 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -221,7 +221,6 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { break; case Core::HID::NpadStyleIndex::GameCube: shared_memory.style_set.gamecube.Assign(1); - // The GC Controller behaves like a wired Pro Controller shared_memory.device_type.fullkey.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); @@ -231,6 +230,24 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.device_type.palma.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; break; + case Core::HID::NpadStyleIndex::NES: + shared_memory.style_set.lark.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + break; + case Core::HID::NpadStyleIndex::SNES: + shared_memory.style_set.lucia.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.applet_footer.type = AppletFooterUiType::Lucia; + break; + case Core::HID::NpadStyleIndex::N64: + shared_memory.style_set.lagoon.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.applet_footer.type = AppletFooterUiType::Lagon; + break; + case Core::HID::NpadStyleIndex::SegaGenesis: + shared_memory.style_set.lager.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + break; default: break; } @@ -431,6 +448,10 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* UNREACHABLE(); break; case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::NES: + case Core::HID::NpadStyleIndex::SNES: + case Core::HID::NpadStyleIndex::N64: + case Core::HID::NpadStyleIndex::SegaGenesis: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_wired.Assign(1); @@ -1108,6 +1129,14 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return style.gamecube; case Core::HID::NpadStyleIndex::Pokeball: return style.palma; + case Core::HID::NpadStyleIndex::NES: + return style.lark; + case Core::HID::NpadStyleIndex::SNES: + return style.lucia; + case Core::HID::NpadStyleIndex::N64: + return style.lagoon; + case Core::HID::NpadStyleIndex::SegaGenesis: + return style.lager; default: return false; } From 690013b342e6d9a9561017b2e94f42acfde25147 Mon Sep 17 00:00:00 2001 From: Levi Behunin Date: Thu, 4 Nov 2021 16:09:57 -0600 Subject: [PATCH 118/291] UI nits Set top margin to 6 on Right Stick, LeftStick, Face Buttons, D-Pad. Change property on Input Device QComboBox from minimumSize to minimumContentsLength. --- src/yuzu/configuration/configure_input_player.ui | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 958a89229..756a414b5 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -117,11 +117,8 @@ - - - 0 - 21 - + + 60 @@ -307,7 +304,7 @@ 3 - 0 + 6 3 @@ -883,7 +880,7 @@ 3 - 0 + 6 3 @@ -2186,7 +2183,7 @@ 3 - 0 + 6 3 @@ -2535,7 +2532,7 @@ 3 - 0 + 6 3 From e7eee36d52259321b938c350cb37a3b115953229 Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 4 Nov 2021 19:05:58 -0600 Subject: [PATCH 119/291] service/hid: Remove includes of core.h and settings.h --- src/core/hid/emulated_console.cpp | 1 + src/core/hid/emulated_console.h | 1 - src/core/hid/emulated_devices.h | 3 +-- .../service/hid/controllers/console_sixaxis.cpp | 8 ++++---- .../hle/service/hid/controllers/console_sixaxis.h | 8 ++++++-- .../service/hid/controllers/controller_base.cpp | 2 +- .../hle/service/hid/controllers/controller_base.h | 8 ++++---- .../hle/service/hid/controllers/debug_pad.cpp | 6 +++--- src/core/hle/service/hid/controllers/debug_pad.h | 3 +-- src/core/hle/service/hid/controllers/gesture.cpp | 5 ++--- src/core/hle/service/hid/controllers/gesture.h | 2 +- src/core/hle/service/hid/controllers/keyboard.cpp | 6 +++--- src/core/hle/service/hid/controllers/keyboard.h | 3 +-- src/core/hle/service/hid/controllers/mouse.cpp | 5 ++--- src/core/hle/service/hid/controllers/mouse.h | 3 +-- src/core/hle/service/hid/controllers/npad.cpp | 15 +++++++-------- src/core/hle/service/hid/controllers/npad.h | 3 +-- src/core/hle/service/hid/controllers/stubbed.cpp | 3 ++- src/core/hle/service/hid/controllers/stubbed.h | 2 +- .../hle/service/hid/controllers/touchscreen.cpp | 7 +++++-- .../hle/service/hid/controllers/touchscreen.h | 8 +++++--- src/core/hle/service/hid/controllers/xpad.cpp | 3 ++- src/core/hle/service/hid/controllers/xpad.h | 2 +- src/core/hle/service/hid/hid.cpp | 1 + src/core/hle/service/hid/hid.h | 4 ++-- src/yuzu/bootmanager.cpp | 1 - src/yuzu/debugger/controller.cpp | 10 +++++----- src/yuzu/debugger/controller.h | 9 +++------ src/yuzu/main.cpp | 2 +- 29 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index b51c72eae..864481f52 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included +#include "common/settings.h" #include "core/hid/emulated_console.h" #include "core/hid/input_converter.h" diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 9aec482a6..25c183eee 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -15,7 +15,6 @@ #include "common/param_package.h" #include "common/point.h" #include "common/quaternion.h" -#include "common/settings.h" #include "common/vector_math.h" #include "core/hid/hid_types.h" #include "core/hid/motion_input.h" diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 418b2f9b5..d49d6d78a 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -15,7 +15,6 @@ #include "common/param_package.h" #include "common/settings.h" #include "core/hid/hid_types.h" -#include "core/hid/motion_input.h" namespace Core::HID { @@ -103,7 +102,7 @@ public: /// Reverts any mapped changes made that weren't saved void RestoreConfig(); - /// Returns the current mapped motion device + /// Returns the current mapped mouse button device Common::ParamPackage GetMouseButtonParam(std::size_t index) const; /** diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index 2bebcf0d0..ea7e8f18f 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -3,17 +3,17 @@ // Refer to the license.txt file included. #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/hid/emulated_console.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; -Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) - : ControllerBase{system_} { - console = system.HIDCore().GetEmulatedConsole(); +Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + console = hid_core.GetEmulatedConsole(); } Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 95729e6b2..7c92413e8 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -5,16 +5,20 @@ #pragma once #include + #include "common/common_types.h" #include "common/quaternion.h" -#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +namespace Core::HID { +class EmulatedConsole; +} // namespace Core::HID + namespace Service::HID { class Controller_ConsoleSixAxis final : public ControllerBase { public: - explicit Controller_ConsoleSixAxis(Core::System& system_); + explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); ~Controller_ConsoleSixAxis() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 74a394784..788ae9ae7 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -6,7 +6,7 @@ namespace Service::HID { -ControllerBase::ControllerBase(Core::System& system_) : system(system_) {} +ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} ControllerBase::~ControllerBase() = default; void ControllerBase::ActivateController() { diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 4ba2eda1a..8125bbc84 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -11,14 +11,14 @@ namespace Core::Timing { class CoreTiming; } -namespace Core { -class System; +namespace Core::HID { +class HIDCore; } namespace Service::HID { class ControllerBase { public: - explicit ControllerBase(Core::System& system_); + explicit ControllerBase(Core::HID::HIDCore& hid_core_); virtual ~ControllerBase(); // Called when the controller is initialized @@ -44,6 +44,6 @@ public: protected: bool is_activated{false}; - Core::System& system; + Core::HID::HIDCore& hid_core; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 86b95f2c8..6a6fb9cab 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -5,7 +5,6 @@ #include #include "common/common_types.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -15,8 +14,9 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} { - controller = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Other); +Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); } Controller_DebugPad::~Controller_DebugPad() = default; diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index bd0f15eaa..15b3afb7a 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -8,7 +8,6 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" @@ -22,7 +21,7 @@ struct AnalogStickState; namespace Service::HID { class Controller_DebugPad final : public ControllerBase { public: - explicit Controller_DebugPad(Core::System& system_); + explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); ~Controller_DebugPad() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 00df50f32..fe895c4f6 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -5,7 +5,6 @@ #include "common/logging/log.h" #include "common/math_util.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/hid/hid_core.h" @@ -25,8 +24,8 @@ constexpr f32 Square(s32 num) { return static_cast(num * num); } -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) { - console = system.HIDCore().GetEmulatedConsole(); +Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { + console = hid_core.GetEmulatedConsole(); } Controller_Gesture::~Controller_Gesture() = default; diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 9bffde438..f924464e0 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -15,7 +15,7 @@ namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: - explicit Controller_Gesture(Core::System& system_); + explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); ~Controller_Gesture() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index acea68e24..1dc219bf5 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -5,7 +5,6 @@ #include #include "common/common_types.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" @@ -14,8 +13,9 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} { - emulated_devices = system.HIDCore().GetEmulatedDevices(); +Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + emulated_devices = hid_core.GetEmulatedDevices(); } Controller_Keyboard::~Controller_Keyboard() = default; diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index aba4f123e..ec5dd607c 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -8,7 +8,6 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" @@ -22,7 +21,7 @@ struct KeyboardKey; namespace Service::HID { class Controller_Keyboard final : public ControllerBase { public: - explicit Controller_Keyboard(Core::System& system_); + explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); ~Controller_Keyboard() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 21f7e48bb..83e69ca94 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -4,7 +4,6 @@ #include #include "common/common_types.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/hid/emulated_devices.h" @@ -14,8 +13,8 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} { - emulated_devices = system.HIDCore().GetEmulatedDevices(); +Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { + emulated_devices = hid_core.GetEmulatedDevices(); } Controller_Mouse::~Controller_Mouse() = default; diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index ce868a247..25017f117 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -7,7 +7,6 @@ #include #include "common/bit_field.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" @@ -20,7 +19,7 @@ struct MouseState; namespace Service::HID { class Controller_Mouse final : public ControllerBase { public: - explicit Controller_Mouse(Core::System& system_); + explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); ~Controller_Mouse() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index fcc36bbc1..b97e575f3 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -10,7 +10,6 @@ #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/emulated_controller.h" #include "core/hid/hid_core.h" @@ -97,12 +96,12 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { device_handle.device_index < DeviceIndex::MaxDeviceIndex; } -Controller_NPad::Controller_NPad(Core::System& system_, +Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) - : ControllerBase{system_}, service_context{service_context_} { + : ControllerBase{hid_core_}, service_context{service_context_} { for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; - controller.device = system.HIDCore().GetEmulatedControllerByIndex(i); + controller.device = hid_core.GetEmulatedControllerByIndex(i); controller.vibration[Core::HID::DeviceIndex::LeftIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; controller.vibration[Core::HID::DeviceIndex::RightIndex].latest_vibration_value = @@ -284,7 +283,7 @@ void Controller_NPad::OnInit() { service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } - if (system.HIDCore().GetSupportedStyleTag().raw == 0) { + if (hid_core.GetSupportedStyleTag().raw == 0) { // We want to support all controllers Core::HID::NpadStyleTag style{}; style.handheld.Assign(1); @@ -294,7 +293,7 @@ void Controller_NPad::OnInit() { style.fullkey.Assign(1); style.gamecube.Assign(1); style.palma.Assign(1); - system.HIDCore().SetSupportedStyleTag(style); + hid_core.SetSupportedStyleTag(style); } supported_npad_id_types.resize(npad_id_list.size()); @@ -678,11 +677,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing } void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { - system.HIDCore().SetSupportedStyleTag(style_set); + hid_core.SetSupportedStyleTag(style_set); } Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { - return system.HIDCore().GetSupportedStyleTag(); + return hid_core.GetSupportedStyleTag(); } void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 512fb5afc..a996755ed 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -11,7 +11,6 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" -#include "common/settings.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" @@ -37,7 +36,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? class Controller_NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::System& system_, + explicit Controller_NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); ~Controller_NPad() override; diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index a8c93909d..b7d7a5756 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -5,11 +5,12 @@ #include #include "common/common_types.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/stubbed.h" namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {} +Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} Controller_Stubbed::~Controller_Stubbed() = default; void Controller_Stubbed::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 10aecad4c..0044a4efa 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -10,7 +10,7 @@ namespace Service::HID { class Controller_Stubbed final : public ControllerBase { public: - explicit Controller_Stubbed(Core::System& system_); + explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); ~Controller_Stubbed() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 9ae2bf2b1..48978e5c6 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -10,13 +10,16 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/emulated_console.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/touchscreen.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} { - console = system.HIDCore().GetEmulatedConsole(); +Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + console = hid_core.GetEmulatedConsole(); } Controller_Touchscreen::~Controller_Touchscreen() = default; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 50dadd25f..135c2bf13 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,12 +9,14 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" +namespace Core::HID { +class EmulatedConsole; +} // namespace Core::HID + namespace Service::HID { class Controller_Touchscreen final : public ControllerBase { public: @@ -34,7 +36,7 @@ public: static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, "TouchScreenConfigurationForNx is an invalid size"); - explicit Controller_Touchscreen(Core::System& system_); + explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); ~Controller_Touchscreen() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index a2ed1e7c2..e4da16466 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -5,12 +5,13 @@ #include #include "common/common_types.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/xpad.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {} +Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} Controller_XPad::~Controller_XPad() = default; void Controller_XPad::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 75e0d2911..54dae0be1 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -15,7 +15,7 @@ namespace Service::HID { class Controller_XPad final : public ControllerBase { public: - explicit Controller_XPad(Core::System& system_); + explicit Controller_XPad(Core::HID::HIDCore& hid_core_); ~Controller_XPad() override; // Called when the controller is initialized diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 648e69de9..96e8fb7e1 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,6 +8,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 2e0c33c1c..973e6a8ac 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -60,12 +60,12 @@ public: private: template void MakeController(HidController controller) { - controllers[static_cast(controller)] = std::make_unique(system); + controllers[static_cast(controller)] = std::make_unique(system.HIDCore()); } template void MakeControllerWithServiceContext(HidController controller) { controllers[static_cast(controller)] = - std::make_unique(system, service_context); + std::make_unique(system.HIDCore(), service_context); } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4b3cd9f3e..3c5590a01 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -27,7 +27,6 @@ #include "common/assert.h" #include "common/microprofile.h" -#include "common/param_package.h" #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/settings.h" diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index aaca494b8..6b834c42e 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -6,17 +6,17 @@ #include #include #include "common/settings.h" -#include "core/core.h" #include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "input_common/drivers/tas_input.h" #include "input_common/main.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(Core::System& system_, +ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_, std::shared_ptr input_subsystem_, QWidget* parent) - : QWidget(parent, Qt::Dialog), system{system_}, input_subsystem{input_subsystem_} { + : QWidget(parent, Qt::Dialog), hid_core{hid_core_}, input_subsystem{input_subsystem_} { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -41,8 +41,8 @@ ControllerDialog::ControllerDialog(Core::System& system_, void ControllerDialog::refreshConfiguration() { UnloadController(); - auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto* player_1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); // Display the correct controller controller = handheld->IsConnected() ? handheld : player_1; diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index d08643baa..52cea3326 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -15,11 +15,8 @@ namespace InputCommon { class InputSubsystem; } -namespace Core { -class System; -} - namespace Core::HID { +class HIDCore; class EmulatedController; enum class ControllerTriggerType; } // namespace Core::HID @@ -28,7 +25,7 @@ class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(Core::System& system_, + explicit ControllerDialog(Core::HID::HIDCore& hid_core_, std::shared_ptr input_subsystem_, QWidget* parent = nullptr); @@ -55,6 +52,6 @@ private: QAction* toggle_view_action = nullptr; PlayerControlPreview* widget; - Core::System& system; + Core::HID::HIDCore& hid_core; std::shared_ptr input_subsystem; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index baf7b38b4..cd8ea221d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -928,7 +928,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(*system, input_subsystem, this); + controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); From a17550be9855a32a62a1358b23babab929a39cbb Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 4 Nov 2021 21:54:22 -0600 Subject: [PATCH 120/291] settings: Remove includes of core.h --- .../configure_debug_controller.cpp | 9 ++--- .../configure_debug_controller.h | 7 ++-- src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_input.cpp | 29 ++++++++------- src/yuzu/configuration/configure_input.h | 3 +- .../configuration/configure_input_player.cpp | 35 +++++++++---------- .../configuration/configure_input_player.h | 16 +++------ .../configure_input_player_widget.cpp | 3 +- .../configure_input_player_widget.h | 4 +-- .../configure_input_profile_dialog.cpp | 4 +-- 10 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp index 31ec48384..9a8de92a1 100644 --- a/src/yuzu/configuration/configure_debug_controller.cpp +++ b/src/yuzu/configuration/configure_debug_controller.cpp @@ -2,17 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/core.h" +#include "core/hid/hid_core.h" #include "ui_configure_debug_controller.h" #include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_input_player.h" ConfigureDebugController::ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, - InputProfiles* profiles, Core::System& system) + InputProfiles* profiles, + Core::HID::HIDCore& hid_core, bool is_powered_on) : QDialog(parent), ui(std::make_unique()), - debug_controller( - new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, true)) { + debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, + hid_core, is_powered_on, true)) { ui->setupUi(this); ui->controllerLayout->addWidget(debug_controller); diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h index 6e17c5aa0..d716edbc2 100644 --- a/src/yuzu/configuration/configure_debug_controller.h +++ b/src/yuzu/configuration/configure_debug_controller.h @@ -13,8 +13,8 @@ class ConfigureInputPlayer; class InputProfiles; -namespace Core { -class System; +namespace Core::HID { +class HIDCore; } namespace InputCommon { @@ -30,7 +30,8 @@ class ConfigureDebugController : public QDialog { public: explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, - InputProfiles* profiles, Core::System& system); + InputProfiles* profiles, Core::HID::HIDCore& hid_core, + bool is_powered_on); ~ConfigureDebugController() override; void ApplyConfiguration(); diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 1eb9d70e5..642a5f966 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -74,7 +74,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, hotkeys_tab->Populate(registry); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - input_tab->Initialize(input_subsystem, system_); + input_tab->Initialize(input_subsystem); general_tab->SetResetCallback([&] { this->close(); }); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index dece27fde..99450bc7d 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -10,6 +10,8 @@ #include #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -73,25 +75,27 @@ ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) ConfigureInput::~ConfigureInput() = default; -void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Core::System& system, +void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, std::size_t max_players) { + const bool is_powered_on = system.IsPoweredOn(); + auto& hid_core = system.HIDCore(); player_controllers = { new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(), - system), + hid_core, is_powered_on), }; player_tabs = { @@ -147,10 +151,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Co advanced = new ConfigureInputAdvanced(this); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->layout()->addWidget(advanced); + connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, - [this, input_subsystem, &system] { - CallConfigureDialog(*this, input_subsystem, - profiles.get(), system); + [this, input_subsystem, &hid_core, is_powered_on] { + CallConfigureDialog( + *this, input_subsystem, profiles.get(), hid_core, is_powered_on); }); connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 6e5edad58..4cafa3dab 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -42,8 +42,7 @@ public: ~ConfigureInput() override; /// Initializes the input dialog with the given input subsystem. - void Initialize(InputCommon::InputSubsystem* input_subsystem_, Core::System& system, - std::size_t max_players = 8); + void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8); /// Save all button configurations to settings file. void ApplyConfiguration(); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 95a9b8614..76f55eb54 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -12,7 +12,6 @@ #include #include #include "common/param_package.h" -#include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" @@ -134,18 +133,17 @@ QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, InputCommon::InputSubsystem* input_subsystem_, - InputProfiles* profiles_, Core::System& system_, - bool debug) + InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, + bool is_powered_on_, bool debug) : QWidget(parent), ui(std::make_unique()), player_index(player_index), - debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_), - timeout_timer(std::make_unique()), poll_timer(std::make_unique()), - bottom_row(bottom_row), system{system_} { - + debug(debug), is_powered_on{is_powered_on_}, input_subsystem{input_subsystem_}, + profiles(profiles_), timeout_timer(std::make_unique()), + poll_timer(std::make_unique()), bottom_row(bottom_row), hid_core{hid_core_} { if (player_index == 0) { auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->SaveCurrentConfig(); emulated_controller_p1->EnableConfiguration(); emulated_controller_hanheld->SaveCurrentConfig(); @@ -157,7 +155,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i emulated_controller = emulated_controller_p1; } } else { - emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index); + emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index); emulated_controller->SaveCurrentConfig(); emulated_controller->EnableConfiguration(); } @@ -487,9 +485,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (player_index == 0) { auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); bool is_connected = emulated_controller->IsConnected(true); emulated_controller_p1->SetNpadStyleIndex(type); @@ -547,9 +545,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i ConfigureInputPlayer::~ConfigureInputPlayer() { if (player_index == 0) { auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->DisableConfiguration(); emulated_controller_hanheld->DisableConfiguration(); } else { @@ -560,9 +558,9 @@ ConfigureInputPlayer::~ConfigureInputPlayer() { void ConfigureInputPlayer::ApplyConfiguration() { if (player_index == 0) { auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->DisableConfiguration(); emulated_controller_p1->SaveCurrentConfig(); emulated_controller_p1->EnableConfiguration(); @@ -846,12 +844,11 @@ void ConfigureInputPlayer::SetConnectableControllers() { } }; - if (!system.IsPoweredOn()) { + if (!is_powered_on) { add_controllers(true); - return; } - add_controllers(false, system.HIDCore().GetSupportedStyleTag()); + add_controllers(false, hid_core.GetSupportedStyleTag()); } Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 7bff4b196..47df6b3d3 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -29,10 +29,6 @@ class QWidget; class InputProfiles; -namespace Core { -class System; -} - namespace InputCommon { class InputSubsystem; } @@ -45,11 +41,8 @@ namespace Ui { class ConfigureInputPlayer; } -namespace Core { -class System; -} - namespace Core::HID { +class HIDCore; class EmulatedController; enum class NpadStyleIndex : u8; } // namespace Core::HID @@ -60,8 +53,8 @@ class ConfigureInputPlayer : public QWidget { public: explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, InputCommon::InputSubsystem* input_subsystem_, - InputProfiles* profiles_, Core::System& system_, - bool debug = false); + InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, + bool is_powered_on_, bool debug = false); ~ConfigureInputPlayer() override; /// Save all button configurations to settings file. @@ -173,6 +166,7 @@ private: std::size_t player_index; bool debug; + bool is_powered_on; InputCommon::InputSubsystem* input_subsystem; @@ -228,5 +222,5 @@ private: /// parent of the widget to this widget (but thats fine). QWidget* bottom_row; - Core::System& system; + Core::HID::HIDCore& hid_core; }; diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index af65cf64c..ff40f57f5 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -6,7 +6,8 @@ #include #include #include -#include "core/core.h" + +#include "core/hid/emulated_controller.h" #include "yuzu/configuration/configure_input_player_widget.h" PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index ee217f3c9..4cd5c3be0 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -7,10 +7,10 @@ #include #include #include + #include "common/input.h" -#include "common/settings.h" +#include "common/settings_input.h" #include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" class QLabel; diff --git a/src/yuzu/configuration/configure_input_profile_dialog.cpp b/src/yuzu/configuration/configure_input_profile_dialog.cpp index cd5a88cea..17bbe6b61 100644 --- a/src/yuzu/configuration/configure_input_profile_dialog.cpp +++ b/src/yuzu/configuration/configure_input_profile_dialog.cpp @@ -11,8 +11,8 @@ ConfigureInputProfileDialog::ConfigureInputProfileDialog( QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles, Core::System& system) : QDialog(parent), ui(std::make_unique()), - profile_widget( - new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, false)) { + profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, + system.HIDCore(), system.IsPoweredOn(), false)) { ui->setupUi(this); ui->controllerLayout->addWidget(profile_widget); From 71f9b90dd90c442425900ee16af8b4e39ac54aed Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 8 Nov 2021 20:28:09 -0600 Subject: [PATCH 121/291] core/hid: Remove usage of native types, fix a couple of errors with motion --- src/core/hid/emulated_console.cpp | 2 +- src/core/hid/emulated_controller.cpp | 4 +- src/core/hid/emulated_controller.h | 4 +- src/core/hid/hid_types.h | 67 ++- .../service/am/applets/applet_controller.cpp | 1 + .../service/am/applets/applet_controller.h | 6 +- src/core/hle/service/hid/controllers/npad.cpp | 498 +++++++++++------- src/core/hle/service/hid/controllers/npad.h | 159 +++--- src/core/hle/service/hid/hid.cpp | 289 +++++----- .../configuration/configure_input_player.cpp | 4 +- .../configure_input_player_widget.cpp | 24 +- 11 files changed, 631 insertions(+), 427 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 864481f52..374dd5d41 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -152,7 +152,7 @@ void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { motion.rotation = emulated.GetGyroscope(); motion.orientation = emulated.GetOrientation(); motion.quaternion = emulated.GetQuaternion(); - motion.is_at_rest = emulated.IsMoving(motion_sensitivity); + motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); TriggerOnChange(ConsoleTriggerType::Motion); } diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a9038e06f..54c1a2324 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -347,7 +347,7 @@ void EmulatedController::RestoreConfig() { } std::vector EmulatedController::GetMappedDevices( - DeviceIndex device_index) const { + EmulatedDeviceIndex device_index) const { std::vector devices; for (const auto& param : button_params) { if (!param.Has("engine")) { @@ -704,7 +704,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std:: motion.gyro = emulated.GetGyroscope(); motion.rotation = emulated.GetRotations(); motion.orientation = emulated.GetOrientation(); - motion.is_at_rest = emulated.IsMoving(motion_sensitivity); + motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); TriggerOnChange(ControllerTriggerType::Motion, true); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fa2e89c0b..2c5d51bc8 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -81,7 +81,7 @@ struct ControllerMotion { bool is_at_rest{}; }; -enum DeviceIndex : u8 { +enum EmulatedDeviceIndex : u8 { LeftIndex, RightIndex, DualIndex, @@ -202,7 +202,7 @@ public: void RestoreConfig(); /// Returns a vector of mapped devices from the mapped button and stick parameters - std::vector GetMappedDevices(DeviceIndex device_index) const; + std::vector GetMappedDevices(EmulatedDeviceIndex device_index) const; // Returns the current mapped button device Common::ParamPackage GetButtonParam(std::size_t index) const; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 22177b5ed..f224cb744 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -13,7 +13,7 @@ namespace Core::HID { // This is nn::hid::NpadIdType -enum class NpadIdType : u8 { +enum class NpadIdType : u32 { Player1 = 0x0, Player2 = 0x1, Player3 = 0x2, @@ -25,7 +25,7 @@ enum class NpadIdType : u8 { Other = 0x10, Handheld = 0x20, - Invalid = 0xFF, + Invalid = 0xFFFFFFFF, }; /// Converts a NpadIdType to an array index. @@ -104,10 +104,30 @@ enum class NpadStyleIndex : u8 { MaxNpadType = 34, }; +// This is nn::hid::NpadStyleSet +enum class NpadStyleSet : u32 { + None = 0, + Fullkey = 1U << 0, + Handheld = 1U << 1, + JoyDual = 1U << 2, + JoyLeft = 1U << 3, + JoyRight = 1U << 4, + Gc = 1U << 5, + Palma = 1U << 6, + Lark = 1U << 7, + HandheldLark = 1U << 8, + Lucia = 1U << 9, + Lagoon = 1U << 10, + Lager = 1U << 11, + SystemExt = 1U << 29, + System = 1U << 30, +}; +static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); + // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { - u32 raw{}; + NpadStyleSet raw{}; BitField<0, 1, u32> fullkey; BitField<1, 1, u32> handheld; @@ -322,6 +342,47 @@ struct DebugPadButton { }; static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"); +enum class DeviceIndex : u8 { + Left = 0, + Right = 1, + None = 2, + MaxDeviceIndex = 3, +}; + +// This is nn::hid::ConsoleSixAxisSensorHandle +struct ConsoleSixAxisSensorHandle { + u8 unknown_1; + u8 unknown_2; + INSERT_PADDING_BYTES_NOINIT(2); +}; +static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4, + "ConsoleSixAxisSensorHandle is an invalid size"); + +// This is nn::hid::SixAxisSensorHandle +struct SixAxisSensorHandle { + NpadStyleIndex npad_type; + u8 npad_id; + DeviceIndex device_index; + INSERT_PADDING_BYTES_NOINIT(1); +}; +static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size"); + +struct SixAxisSensorFusionParameters { + f32 parameter1; + f32 parameter2; +}; +static_assert(sizeof(SixAxisSensorFusionParameters) == 8, + "SixAxisSensorFusionParameters is an invalid size"); + +// This is nn::hid::VibrationDeviceHandle +struct VibrationDeviceHandle { + NpadStyleIndex npad_type; + u8 npad_id; + DeviceIndex device_index; + INSERT_PADDING_BYTES_NOINIT(1); +}; +static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); + // This is nn::hid::VibrationDeviceType enum class VibrationDeviceType : u32 { Unknown = 0, diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 374e0c7f4..d073f2210 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -12,6 +12,7 @@ #include "core/frontend/applets/controller.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h index 0a34c4fc0..1a832505e 100644 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/applets/applet_controller.h @@ -16,6 +16,10 @@ namespace Core { class System; } +namespace Core::HID { +enum class NpadStyleSet : u32; +} + namespace Service::AM::Applets { using IdentificationColor = std::array; @@ -52,7 +56,7 @@ struct ControllerSupportArgPrivate { bool flag_1{}; ControllerSupportMode mode{}; ControllerSupportCaller caller{}; - u32 style_set{}; + Core::HID::NpadStyleSet style_set{}; u32 joy_hold_type{}; }; static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index b97e575f3..eaec79139 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -21,68 +21,25 @@ namespace Service::HID { constexpr std::size_t NPAD_OFFSET = 0x9A00; -constexpr u32 MAX_NPAD_ID = 7; -constexpr std::size_t HANDHELD_INDEX = 8; -constexpr std::array npad_id_list{ - 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, +constexpr std::array npad_id_list{ + Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, + Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, + Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, + Core::HID::NpadIdType::Handheld, }; -std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { +bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { switch (npad_id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - return npad_id; - case HANDHELD_INDEX: - case NPAD_HANDHELD: - return HANDHELD_INDEX; - case 9: - case NPAD_UNKNOWN: - return 9; - default: - UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); - return 0; - } -} - -u32 Controller_NPad::IndexToNPad(std::size_t index) { - switch (index) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - return static_cast(index); - case HANDHELD_INDEX: - return NPAD_HANDHELD; - case 9: - return NPAD_UNKNOWN; - default: - UNIMPLEMENTED_MSG("Unknown npad index {}", index); - return 0; - } -} - -bool Controller_NPad::IsNpadIdValid(u32 npad_id) { - switch (npad_id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case NPAD_UNKNOWN: - case NPAD_HANDHELD: + case Core::HID::NpadIdType::Player1: + case Core::HID::NpadIdType::Player2: + case Core::HID::NpadIdType::Player3: + case Core::HID::NpadIdType::Player4: + case Core::HID::NpadIdType::Player5: + case Core::HID::NpadIdType::Player6: + case Core::HID::NpadIdType::Player7: + case Core::HID::NpadIdType::Player8: + case Core::HID::NpadIdType::Other: + case Core::HID::NpadIdType::Handheld: return true; default: LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); @@ -90,10 +47,16 @@ bool Controller_NPad::IsNpadIdValid(u32 npad_id) { } } -bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { - return IsNpadIdValid(device_handle.npad_id) && +bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { + return IsNpadIdValid(static_cast(device_handle.npad_id)) && device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && - device_handle.device_index < DeviceIndex::MaxDeviceIndex; + device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; +} + +bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) { + return IsNpadIdValid(static_cast(device_handle.npad_id)) && + device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && + device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; } Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, @@ -102,9 +65,9 @@ Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; controller.device = hid_core.GetEmulatedControllerByIndex(i); - controller.vibration[Core::HID::DeviceIndex::LeftIndex].latest_vibration_value = + controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; - controller.vibration[Core::HID::DeviceIndex::RightIndex].latest_vibration_value = + controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = DEFAULT_VIBRATION_VALUE; Core::HID::ControllerUpdateCallback engine_callback{ .on_change = [this, @@ -130,17 +93,21 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); return; } + if (controller_idx >= controller_data.size()) { + return; + } auto& controller = controller_data[controller_idx]; const auto is_connected = controller.device->IsConnected(); const auto npad_type = controller.device->GetNpadStyleIndex(); + const auto npad_id = controller.device->GetNpadIdType(); switch (type) { case Core::HID::ControllerTriggerType::Connected: case Core::HID::ControllerTriggerType::Disconnected: if (is_connected == controller.is_connected) { return; } - UpdateControllerAt(npad_type, controller_idx, is_connected); + UpdateControllerAt(npad_type, npad_id, is_connected); break; case Core::HID::ControllerTriggerType::Battery: { if (!controller.is_connected) { @@ -158,15 +125,16 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, } } -void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { - auto& controller = controller_data[controller_idx]; +void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { + LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); + auto& controller = GetControllerFromNpadIdType(npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); auto& shared_memory = controller.shared_memory_entry; if (controller_type == Core::HID::NpadStyleIndex::None) { controller.styleset_changed_event->GetWritableEvent().Signal(); return; } - shared_memory.style_set.raw = 0; // Zero out + shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; shared_memory.device_type.raw = 0; shared_memory.system_properties.raw = 0; switch (controller_type) { @@ -174,7 +142,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { UNREACHABLE(); break; case Core::HID::NpadStyleIndex::ProController: - shared_memory.style_set.fullkey.Assign(1); + shared_memory.style_tag.fullkey.Assign(1); shared_memory.device_type.fullkey.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); @@ -183,7 +151,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; break; case Core::HID::NpadStyleIndex::Handheld: - shared_memory.style_set.handheld.Assign(1); + shared_memory.style_tag.handheld.Assign(1); shared_memory.device_type.handheld_left.Assign(1); shared_memory.device_type.handheld_right.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); @@ -193,7 +161,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; case Core::HID::NpadStyleIndex::JoyconDual: - shared_memory.style_set.joycon_dual.Assign(1); + shared_memory.style_tag.joycon_dual.Assign(1); shared_memory.device_type.joycon_left.Assign(1); shared_memory.device_type.joycon_right.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); @@ -203,7 +171,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; break; case Core::HID::NpadStyleIndex::JoyconLeft: - shared_memory.style_set.joycon_left.Assign(1); + shared_memory.style_tag.joycon_left.Assign(1); shared_memory.device_type.joycon_left.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_minus.Assign(1); @@ -211,7 +179,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; break; case Core::HID::NpadStyleIndex::JoyconRight: - shared_memory.style_set.joycon_right.Assign(1); + shared_memory.style_tag.joycon_right.Assign(1); shared_memory.device_type.joycon_right.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_plus.Assign(1); @@ -219,32 +187,32 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; break; case Core::HID::NpadStyleIndex::GameCube: - shared_memory.style_set.gamecube.Assign(1); + shared_memory.style_tag.gamecube.Assign(1); shared_memory.device_type.fullkey.Assign(1); shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); break; case Core::HID::NpadStyleIndex::Pokeball: - shared_memory.style_set.palma.Assign(1); + shared_memory.style_tag.palma.Assign(1); shared_memory.device_type.palma.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; break; case Core::HID::NpadStyleIndex::NES: - shared_memory.style_set.lark.Assign(1); + shared_memory.style_tag.lark.Assign(1); shared_memory.device_type.fullkey.Assign(1); break; case Core::HID::NpadStyleIndex::SNES: - shared_memory.style_set.lucia.Assign(1); + shared_memory.style_tag.lucia.Assign(1); shared_memory.device_type.fullkey.Assign(1); shared_memory.applet_footer.type = AppletFooterUiType::Lucia; break; case Core::HID::NpadStyleIndex::N64: - shared_memory.style_set.lagoon.Assign(1); + shared_memory.style_tag.lagoon.Assign(1); shared_memory.device_type.fullkey.Assign(1); shared_memory.applet_footer.type = AppletFooterUiType::Lagon; break; case Core::HID::NpadStyleIndex::SegaGenesis: - shared_memory.style_set.lager.Assign(1); + shared_memory.style_tag.lager.Assign(1); shared_memory.device_type.fullkey.Assign(1); break; default: @@ -268,7 +236,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { controller.is_connected = true; controller.device->Connect(); - SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); + SignalStyleSetChangedEvent(npad_id); WriteEmptyEntry(controller.shared_memory_entry); } @@ -283,7 +251,7 @@ void Controller_NPad::OnInit() { service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } - if (hid_core.GetSupportedStyleTag().raw == 0) { + if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { // We want to support all controllers Core::HID::NpadStyleTag style{}; style.handheld.Assign(1); @@ -298,7 +266,7 @@ void Controller_NPad::OnInit() { supported_npad_id_types.resize(npad_id_list.size()); std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), - npad_id_list.size() * sizeof(u32)); + npad_id_list.size() * sizeof(Core::HID::NpadIdType)); // Prefill controller buffers for (auto& controller : controller_data) { @@ -322,8 +290,7 @@ void Controller_NPad::OnInit() { for (auto& controller : controller_data) { const auto& device = controller.device; if (device->IsConnected()) { - const std::size_t index = Core::HID::NpadIdTypeToIndex(device->GetNpadIdType()); - AddNewControllerAt(device->GetNpadStyleIndex(), index); + AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); } } } @@ -354,15 +321,14 @@ void Controller_NPad::OnRelease() { auto& controller = controller_data[i]; service_context.CloseEvent(controller.styleset_changed_event); for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { - VibrateControllerAtIndex(i, device_idx, {}); + VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); } } } -void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { +void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { std::lock_guard lock{mutex}; - const auto controller_idx = NPadIdToIndex(npad_id); - auto& controller = controller_data[controller_idx]; + auto& controller = GetControllerFromNpadIdType(npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); if (!controller.device->IsConnected()) { return; @@ -431,9 +397,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* &controller.shared_memory_entry, sizeof(NpadInternalState)); continue; } - const u32 npad_index = static_cast(i); - RequestPadStateUpdate(npad_index); + RequestPadStateUpdate(controller.device->GetNpadIdType()); auto& pad_state = controller.npad_pad_state; auto& libnx_state = controller.npad_libnx_state; auto& trigger_state = controller.npad_trigger_state; @@ -571,10 +536,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; - if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) { - sixaxis_at_rest = true; + if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { + controller.sixaxis_at_rest = true; for (std::size_t e = 0; e < motion_state.size(); ++e) { - sixaxis_at_rest = sixaxis_at_rest && motion_state[e].is_at_rest; + controller.sixaxis_at_rest = + controller.sixaxis_at_rest && motion_state[e].is_at_rest; } } @@ -584,7 +550,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing break; case Core::HID::NpadStyleIndex::ProController: sixaxis_fullkey_state.attribute.raw = 0; - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { sixaxis_fullkey_state.attribute.is_connected.Assign(1); sixaxis_fullkey_state.accel = motion_state[0].accel; sixaxis_fullkey_state.gyro = motion_state[0].gyro; @@ -594,7 +560,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing break; case Core::HID::NpadStyleIndex::Handheld: sixaxis_handheld_state.attribute.raw = 0; - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { sixaxis_handheld_state.attribute.is_connected.Assign(1); sixaxis_handheld_state.accel = motion_state[0].accel; sixaxis_handheld_state.gyro = motion_state[0].gyro; @@ -605,7 +571,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing case Core::HID::NpadStyleIndex::JoyconDual: sixaxis_dual_left_state.attribute.raw = 0; sixaxis_dual_right_state.attribute.raw = 0; - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { // Set motion for the left joycon sixaxis_dual_left_state.attribute.is_connected.Assign(1); sixaxis_dual_left_state.accel = motion_state[0].accel; @@ -613,7 +579,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_dual_left_state.rotation = motion_state[0].rotation; sixaxis_dual_left_state.orientation = motion_state[0].orientation; } - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { // Set motion for the right joycon sixaxis_dual_right_state.attribute.is_connected.Assign(1); sixaxis_dual_right_state.accel = motion_state[1].accel; @@ -624,7 +590,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing break; case Core::HID::NpadStyleIndex::JoyconLeft: sixaxis_left_lifo_state.attribute.raw = 0; - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { sixaxis_left_lifo_state.attribute.is_connected.Assign(1); sixaxis_left_lifo_state.accel = motion_state[0].accel; sixaxis_left_lifo_state.gyro = motion_state[0].gyro; @@ -634,7 +600,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing break; case Core::HID::NpadStyleIndex::JoyconRight: sixaxis_right_lifo_state.attribute.raw = 0; - if (sixaxis_sensors_enabled) { + if (controller.sixaxis_sensor_enabled) { sixaxis_right_lifo_state.attribute.is_connected.Assign(1); sixaxis_right_lifo_state.accel = motion_state[1].accel; sixaxis_right_lifo_state.gyro = motion_state[1].gyro; @@ -724,26 +690,30 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -void Controller_NPad::SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode) { - const std::size_t npad_index = NPadIdToIndex(npad_id); - ASSERT(npad_index < controller_data.size()); - auto& controller = controller_data[npad_index]; +void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, + NpadJoyAssignmentMode assignment_mode) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } + + auto& controller = GetControllerFromNpadIdType(npad_id); if (controller.shared_memory_entry.assignment_mode != assignment_mode) { controller.shared_memory_entry.assignment_mode = assignment_mode; } } -bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, - const VibrationValue& vibration_value) { - auto& controller = controller_data[npad_index]; - +bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, + std::size_t device_index, + const Core::HID::VibrationValue& vibration_value) { + auto& controller = GetControllerFromNpadIdType(npad_id); if (!controller.device->IsConnected()) { return false; } if (!controller.device->IsVibrationEnabled()) { - if (controller.vibration[device_index].latest_vibration_value.amp_low != 0.0f || - controller.vibration[device_index].latest_vibration_value.amp_high != 0.0f) { + if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || + controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { // Send an empty vibration to stop any vibrations. Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; controller.device->SetVibration(device_index, vibration); @@ -762,7 +732,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size const auto now = steady_clock::now(); // Filter out non-zero vibrations that are within 10ms of each other. - if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && + if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && duration_cast( now - controller.vibration[device_index].last_vibration_timepoint) < milliseconds(10)) { @@ -772,13 +742,15 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size controller.vibration[device_index].last_vibration_timepoint = now; } - Core::HID::VibrationValue vibration{vibration_value.amp_low, vibration_value.freq_low, - vibration_value.amp_high, vibration_value.freq_high}; + Core::HID::VibrationValue vibration{ + vibration_value.low_amplitude, vibration_value.low_frequency, + vibration_value.high_amplitude, vibration_value.high_frequency}; return controller.device->SetVibration(device_index, vibration); } -void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, - const VibrationValue& vibration_value) { +void Controller_NPad::VibrateController( + const Core::HID::VibrationDeviceHandle& vibration_device_handle, + const Core::HID::VibrationValue& vibration_value) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } @@ -787,15 +759,14 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han return; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); - auto& controller = controller_data[npad_index]; + auto& controller = GetControllerFromHandle(vibration_device_handle); const auto device_index = static_cast(vibration_device_handle.device_index); if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { return; } - if (vibration_device_handle.device_index == DeviceIndex::None) { + if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { UNREACHABLE_MSG("DeviceIndex should never be None!"); return; } @@ -803,28 +774,30 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han // Some games try to send mismatched parameters in the device handle, block these. if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || - vibration_device_handle.device_index == DeviceIndex::Right)) || + vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || - vibration_device_handle.device_index == DeviceIndex::Left))) { + vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) { return; } // Filter out vibrations with equivalent values to reduce unnecessary state changes. - if (vibration_value.amp_low == - controller.vibration[device_index].latest_vibration_value.amp_low && - vibration_value.amp_high == - controller.vibration[device_index].latest_vibration_value.amp_high) { + if (vibration_value.low_amplitude == + controller.vibration[device_index].latest_vibration_value.low_amplitude && + vibration_value.high_amplitude == + controller.vibration[device_index].latest_vibration_value.high_amplitude) { return; } - if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { + if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, + vibration_value)) { controller.vibration[device_index].latest_vibration_value = vibration_value; } } -void Controller_NPad::VibrateControllers(const std::vector& vibration_device_handles, - const std::vector& vibration_values) { +void Controller_NPad::VibrateControllers( + const std::vector& vibration_device_handles, + const std::vector& vibration_values) { if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { return; } @@ -839,31 +812,31 @@ void Controller_NPad::VibrateControllers(const std::vector& vibrat } } -Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( - const DeviceHandle& vibration_device_handle) const { +Core::HID::VibrationValue Controller_NPad::GetLastVibration( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return {}; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); - const auto& controller = controller_data[npad_index]; + const auto& controller = GetControllerFromHandle(vibration_device_handle); const auto device_index = static_cast(vibration_device_handle.device_index); return controller.vibration[device_index].latest_vibration_value; } -void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { +void Controller_NPad::InitializeVibrationDevice( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto npad_index = static_cast(vibration_device_handle.npad_id); const auto device_index = static_cast(vibration_device_handle.device_index); InitializeVibrationDeviceAtIndex(npad_index, device_index); } -void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, +void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index) { - auto& controller = controller_data[npad_index]; + auto& controller = GetControllerFromNpadIdType(npad_id); if (!Settings::values.vibration_enabled.GetValue()) { controller.vibration[device_index].device_mounted = false; return; @@ -877,58 +850,67 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { permit_vibration_session_enabled = permit_vibration_session; } -bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { +bool Controller_NPad::IsVibrationDeviceMounted( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return false; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); - const auto& controller = controller_data[npad_index]; + const auto& controller = GetControllerFromHandle(vibration_device_handle); const auto device_index = static_cast(vibration_device_handle.device_index); return controller.vibration[device_index].device_mounted; } -Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) { - const auto& controller = controller_data[NPadIdToIndex(npad_id)]; +Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + // Fallback to player 1 + const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); + return controller.styleset_changed_event->GetReadableEvent(); + } + + const auto& controller = GetControllerFromNpadIdType(npad_id); return controller.styleset_changed_event->GetReadableEvent(); } -void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { - const auto& controller = controller_data[NPadIdToIndex(npad_id)]; +void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { + const auto& controller = GetControllerFromNpadIdType(npad_id); controller.styleset_changed_event->GetWritableEvent().Signal(); } void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, - std::size_t npad_index) { - UpdateControllerAt(controller, npad_index, true); + Core::HID::NpadIdType npad_id) { + UpdateControllerAt(controller, npad_id, true); } -void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, std::size_t npad_index, - bool connected) { - auto& controller = controller_data[npad_index]; +void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, + Core::HID::NpadIdType npad_id, bool connected) { + auto& controller = GetControllerFromNpadIdType(npad_id); if (!connected) { - DisconnectNpadAtIndex(npad_index); + DisconnectNpad(npad_id); return; } controller.device->SetNpadStyleIndex(type); - InitNewlyAddedController(npad_index); + InitNewlyAddedController(npad_id); } -void Controller_NPad::DisconnectNpad(u32 npad_id) { - DisconnectNpadAtIndex(NPadIdToIndex(npad_id)); -} +void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } -void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { - auto& controller = controller_data[npad_index]; + LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); + auto& controller = GetControllerFromNpadIdType(npad_id); for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { // Send an empty vibration to stop any vibrations. - VibrateControllerAtIndex(npad_index, device_idx, {}); + VibrateControllerAtIndex(npad_id, device_idx, {}); controller.vibration[device_idx].device_mounted = false; } auto& shared_memory_entry = controller.shared_memory_entry; - shared_memory_entry.style_set.raw = 0; // Zero out + shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out shared_memory_entry.device_type.raw = 0; shared_memory_entry.system_properties.raw = 0; shared_memory_entry.button_properties.raw = 0; @@ -949,48 +931,102 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { controller.is_connected = false; controller.device->Disconnect(); - SignalStyleSetChangedEvent(IndexToNPad(npad_index)); + SignalStyleSetChangedEvent(npad_id); WriteEmptyEntry(controller.shared_memory_entry); } -void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { - gyroscope_zero_drift_mode = drift_mode; +void Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, + GyroscopeZeroDriftMode drift_mode) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.gyroscope_zero_drift_mode = drift_mode; } -Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const { - return gyroscope_zero_drift_mode; +Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode( + Core::HID::SixAxisSensorHandle sixaxis_handle) const { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Return the default value + return GyroscopeZeroDriftMode::Standard; + } + const auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.gyroscope_zero_drift_mode; } -bool Controller_NPad::IsSixAxisSensorAtRest() const { - return sixaxis_at_rest; +bool Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Return the default value + return true; + } + const auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.sixaxis_at_rest; } -void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { - sixaxis_sensors_enabled = six_axis_status; +void Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_status) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_sensor_enabled = sixaxis_status; } -void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) { - sixaxis_fusion_parameter1 = parameter1; - sixaxis_fusion_parameter2 = parameter2; +void Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_fusion_status) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_fusion_enabled = sixaxis_fusion_status; } -std::pair Controller_NPad::GetSixAxisFusionParameters() { - return { - sixaxis_fusion_parameter1, - sixaxis_fusion_parameter2, - }; +void Controller_NPad::SetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_fusion = sixaxis_fusion_parameters; } -void Controller_NPad::ResetSixAxisFusionParameters() { - sixaxis_fusion_parameter1 = 0.0f; - sixaxis_fusion_parameter2 = 0.0f; +Core::HID::SixAxisSensorFusionParameters Controller_NPad::GetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Since these parameters are unknow just return zeros + return {}; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.sixaxis_fusion; } -void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { - const auto npad_index_1 = NPadIdToIndex(npad_id_1); - const auto npad_index_2 = NPadIdToIndex(npad_id_2); - const auto& controller_1 = controller_data[npad_index_1].device; - const auto& controller_2 = controller_data[npad_index_2].device; +void Controller_NPad::ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + // Since these parameters are unknow just fill with zeros + controller.sixaxis_fusion = {}; +} + +void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, + Core::HID::NpadIdType npad_id_2) { + if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, + npad_id_2); + return; + } + auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; + auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; // If the controllers at both npad indices form a pair of left and right joycons, merge them. // Otherwise, do nothing. @@ -1000,7 +1036,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) { // Disconnect the joycon at the second id and connect the dual joycon at the first index. DisconnectNpad(npad_id_2); - AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_index_1); + AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); } } @@ -1014,15 +1050,20 @@ void Controller_NPad::StopLRAssignmentMode() { is_in_lr_assignment_mode = false; } -bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { - if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN || - npad_id_2 == NPAD_UNKNOWN) { +bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, + Core::HID::NpadIdType npad_id_2) { + if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, + npad_id_2); + return false; + } + if (npad_id_1 == Core::HID::NpadIdType::Handheld || + npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || + npad_id_2 == Core::HID::NpadIdType::Other) { return true; } - const auto npad_index_1 = NPadIdToIndex(npad_id_1); - const auto npad_index_2 = NPadIdToIndex(npad_id_2); - const auto& controller_1 = controller_data[npad_index_1].device; - const auto& controller_2 = controller_data[npad_index_2].device; + const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; + const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; const auto type_index_1 = controller_1->GetNpadStyleIndex(); const auto type_index_2 = controller_2->GetNpadStyleIndex(); @@ -1030,28 +1071,39 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { return false; } - AddNewControllerAt(type_index_2, npad_index_1); - AddNewControllerAt(type_index_1, npad_index_2); + AddNewControllerAt(type_index_2, npad_id_1); + AddNewControllerAt(type_index_1, npad_id_2); return true; } -Core::HID::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { - if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { - // These are controllers without led patterns +Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return Core::HID::LedPattern{0, 0, 0, 0}; } - return controller_data[npad_id].device->GetLedPattern(); + const auto& controller = GetControllerFromNpadIdType(npad_id).device; + return controller->GetLedPattern(); } -bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { - auto& controller = controller_data[NPadIdToIndex(npad_id)]; +bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( + Core::HID::NpadIdType npad_id) const { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + // Return the default value + return false; + } + const auto& controller = GetControllerFromNpadIdType(npad_id); return controller.unintended_home_button_input_protection; } void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, - u32 npad_id) { - auto& controller = controller_data[NPadIdToIndex(npad_id)]; + Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } + auto& controller = GetControllerFromNpadIdType(npad_id); controller.unintended_home_button_input_protection = is_protection_enabled; } @@ -1099,7 +1151,7 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller if (controller == Core::HID::NpadStyleIndex::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), - NPAD_HANDHELD) != supported_npad_id_types.end(); + Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); // Handheld is not even a supported type, lets stop here if (!support_handheld) { return false; @@ -1113,7 +1165,9 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller } if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), - [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { + [](Core::HID::NpadIdType npad_id) { + return npad_id <= Core::HID::NpadIdType::Player8; + })) { Core::HID::NpadStyleTag style = GetSupportedStyleSet(); switch (controller) { case Core::HID::NpadStyleIndex::ProController: @@ -1144,4 +1198,48 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return false; } +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) { + const auto npad_id = static_cast(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const { + const auto npad_id = static_cast(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) { + const auto npad_id = static_cast(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) const { + const auto npad_id = static_cast(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( + Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( + Core::HID::NpadIdType npad_id) const { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index a996755ed..3798c037f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -31,9 +31,6 @@ class ServiceContext; namespace Service::HID { -constexpr u32 NPAD_HANDHELD = 32; -constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? - class Controller_NPad final : public ControllerBase { public: explicit Controller_NPad(Core::HID::HIDCore& hid_core_, @@ -53,13 +50,6 @@ public: void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - enum class DeviceIndex : u8 { - Left = 0, - Right = 1, - None = 2, - MaxDeviceIndex = 3, - }; - // This is nn::hid::GyroscopeZeroDriftMode enum class GyroscopeZeroDriftMode : u32 { Loose = 0, @@ -79,6 +69,12 @@ public: Single = 1, }; + // This is nn::hid::NpadJoyDeviceType + enum class NpadJoyDeviceType : s64 { + Left = 0, + Right = 1, + }; + // This is nn::hid::NpadHandheldActivationMode enum class NpadHandheldActivationMode : u64 { Dual = 0, @@ -94,28 +90,11 @@ public: Default = 3, }; - struct DeviceHandle { - Core::HID::NpadStyleIndex npad_type; - u8 npad_id; - DeviceIndex device_index; - INSERT_PADDING_BYTES_NOINIT(1); - }; - static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); - - // This is nn::hid::VibrationValue - struct VibrationValue { - f32 amp_low; - f32 freq_low; - f32 amp_high; - f32 freq_high; - }; - static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); - - static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, + static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{ + .low_amplitude = 0.0f, + .low_frequency = 160.0f, + .high_amplitude = 0.0f, + .high_frequency = 320.0f, }; void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); @@ -134,68 +113,77 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - void SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode); + void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode); - bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, - const VibrationValue& vibration_value); + bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, + const Core::HID::VibrationValue& vibration_value); - void VibrateController(const DeviceHandle& vibration_device_handle, - const VibrationValue& vibration_value); + void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, + const Core::HID::VibrationValue& vibration_value); - void VibrateControllers(const std::vector& vibration_device_handles, - const std::vector& vibration_values); + void VibrateControllers( + const std::vector& vibration_device_handles, + const std::vector& vibration_values); - VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; + Core::HID::VibrationValue GetLastVibration( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); + void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); - void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); + void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); void SetPermitVibrationSession(bool permit_vibration_session); - bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; + bool IsVibrationDeviceMounted( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); - void SignalStyleSetChangedEvent(u32 npad_id) const; + Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); + void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; // Adds a new controller at an index. - void AddNewControllerAt(Core::HID::NpadStyleIndex controller, std::size_t npad_index); + void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); // Adds a new controller at an index with connection status. - void UpdateControllerAt(Core::HID::NpadStyleIndex controller, std::size_t npad_index, + void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, bool connected); - void DisconnectNpad(u32 npad_id); - void DisconnectNpadAtIndex(std::size_t index); + void DisconnectNpad(Core::HID::NpadIdType npad_id); - void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); - GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; - bool IsSixAxisSensorAtRest() const; - void SetSixAxisEnabled(bool six_axis_status); - void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); - std::pair GetSixAxisFusionParameters(); - void ResetSixAxisFusionParameters(); - Core::HID::LedPattern GetLedPattern(u32 npad_id); - bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; - void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); + void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, + GyroscopeZeroDriftMode drift_mode); + GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode( + Core::HID::SixAxisSensorHandle sixaxis_handle) const; + bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const; + void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status); + void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_fusion_status); + void SetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); + Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle); + void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle); + Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id); + bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const; + void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, + Core::HID::NpadIdType npad_id); void SetAnalogStickUseCenterClamp(bool use_center_clamp); void ClearAllConnectedControllers(); void DisconnectAllConnectedControllers(); void ConnectAllDisconnectedControllers(); void ClearAllControllers(); - void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); + void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); void StartLRAssignmentMode(); void StopLRAssignmentMode(); - bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); + bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); // Logical OR for all buttons presses on all controllers // Specifically for cheat engine and other features. u32 GetAndResetPressState(); - static std::size_t NPadIdToIndex(u32 npad_id); - static u32 IndexToNPad(std::size_t index); - static bool IsNpadIdValid(u32 npad_id); - static bool IsDeviceHandleValid(const DeviceHandle& device_handle); + static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); + static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); + static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); private: // This is nn::hid::detail::ColorAttribute @@ -441,7 +429,7 @@ private: // This is nn::hid::detail::NpadInternalState struct NpadInternalState { - Core::HID::NpadStyleTag style_set; + Core::HID::NpadStyleTag style_tag; NpadJoyAssignmentMode assignment_mode; NpadFullKeyColorState fullkey_color; NpadJoyColorState joycon_color; @@ -476,19 +464,19 @@ private: NpadLuciaType lucia_type; NpadLagonType lagon_type; NpadLagerType lager_type; - INSERT_PADDING_BYTES( - 0x4); // FW 13.x Investigate there is some sort of bitflag related to joycons + // FW 13.x Investigate there is some sort of bitflag related to joycons + INSERT_PADDING_BYTES(0x4); INSERT_PADDING_BYTES(0xc08); // Unknown }; static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); struct VibrationData { bool device_mounted{}; - VibrationValue latest_vibration_value{}; + Core::HID::VibrationValue latest_vibration_value{}; std::chrono::steady_clock::time_point last_vibration_timepoint{}; }; - struct ControllerData { + struct NpadControllerData { Core::HID::EmulatedController* device; Kernel::KEvent* styleset_changed_event{}; NpadInternalState shared_memory_entry{}; @@ -498,6 +486,13 @@ private: bool is_connected{}; Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; + // Motion parameters + bool sixaxis_at_rest{true}; + bool sixaxis_sensor_enabled{true}; + bool sixaxis_fusion_enabled{false}; + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{}; + GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; + // Current pad state NPadGenericState npad_pad_state{}; NPadGenericState npad_libnx_state{}; @@ -512,27 +507,33 @@ private: }; void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); - void InitNewlyAddedController(std::size_t controller_idx); + void InitNewlyAddedController(Core::HID::NpadIdType npad_id); bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; - void RequestPadStateUpdate(u32 npad_id); + void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); void WriteEmptyEntry(NpadInternalState& npad); + NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const; + NpadControllerData& GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) const; + NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); + const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; + std::atomic press_state{}; - std::array controller_data{}; + std::array controller_data{}; KernelHelpers::ServiceContext& service_context; std::mutex mutex; - std::vector supported_npad_id_types{}; + std::vector supported_npad_id_types{}; NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; bool permit_vibration_session_enabled{false}; bool analog_stick_use_center_clamp{}; - GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; - bool sixaxis_sensors_enabled{true}; - f32 sixaxis_fusion_parameter1{}; - f32 sixaxis_fusion_parameter2{}; - bool sixaxis_at_rest{true}; bool is_in_lr_assignment_mode{false}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 96e8fb7e1..496b55d0e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -161,7 +161,7 @@ public: private: void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw()}; + const auto vibration_device_handle{rp.PopRaw()}; if (applet_resource != nullptr) { applet_resource->GetController(HidController::NPad) @@ -417,6 +417,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -443,19 +444,18 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(true); + // This function does nothing on 10.0.0+ - 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); + 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); @@ -464,19 +464,18 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(false); + // This function does nothing on 10.0.0+ - 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); + 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); @@ -485,14 +484,16 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(true); + applet_resource->GetController(HidController::NPad) + .SetSixAxisEnabled(parameters.sixaxis_handle, true); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -506,14 +507,16 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(false); + applet_resource->GetController(HidController::NPad) + .SetSixAxisEnabled(parameters.sixaxis_handle, false); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -529,19 +532,23 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { struct Parameters { bool enable_sixaxis_sensor_fusion; INSERT_PADDING_BYTES_NOINIT(3); - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - LOG_WARNING(Service_HID, - "(STUBBED) 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); + applet_resource->GetController(HidController::NPad) + .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(ResultSuccess); @@ -550,9 +557,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; - f32 parameter1; - f32 parameter2; + 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."); @@ -560,14 +567,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); + .SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); - LOG_WARNING(Service_HID, - "(STUBBED) 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.parameter1, - parameters.parameter2, parameters.applet_resource_user_id); + 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(ResultSuccess); @@ -576,35 +583,33 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); - f32 parameter1 = 0; - f32 parameter2 = 0; const auto parameters{rp.PopRaw()}; - std::tie(parameter1, parameter2) = + const auto sixaxis_fusion_parameters = applet_resource->GetController(HidController::NPad) - .GetSixAxisFusionParameters(); + .GetSixAxisFusionParameters(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); + 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(ResultSuccess); - rb.Push(parameter1); - rb.Push(parameter2); + rb.PushRaw(sixaxis_fusion_parameters); } void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -612,13 +617,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .ResetSixAxisFusionParameters(); + .ResetSixAxisFusionParameters(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); + 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(ResultSuccess); @@ -626,12 +630,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto sixaxis_handle{rp.PopRaw()}; + const auto sixaxis_handle{rp.PopRaw()}; const auto drift_mode{rp.PopEnum()}; const auto applet_resource_user_id{rp.Pop()}; applet_resource->GetController(HidController::NPad) - .SetGyroscopeZeroDriftMode(drift_mode); + .SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " @@ -646,10 +650,11 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; @@ -661,21 +666,23 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.PushEnum(applet_resource->GetController(HidController::NPad) - .GetGyroscopeZeroDriftMode()); + .GetGyroscopeZeroDriftMode(parameters.sixaxis_handle)); } void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; + const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; applet_resource->GetController(HidController::NPad) - .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); + .SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -689,10 +696,11 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; @@ -704,16 +712,17 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(applet_resource->GetController(HidController::NPad) - .IsSixAxisSensorAtRest()); + .IsSixAxisSensorAtRest(parameters.sixaxis_handle)); } void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; @@ -735,13 +744,14 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->ActivateController(HidController::Gesture); - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, - parameters.applet_resource_user_id); + 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); @@ -749,12 +759,20 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto supported_styleset{rp.Pop()}; + 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()}; applet_resource->GetController(HidController::NPad) - .SetSupportedStyleSet({supported_styleset}); + .SetSupportedStyleSet({parameters.supported_styleset}); - LOG_DEBUG(Service_HID, "called, supported_styleset={}", 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); @@ -768,9 +786,9 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(applet_resource->GetController(HidController::NPad) - .GetSupportedStyleSet() - .raw); + rb.PushEnum(applet_resource->GetController(HidController::NPad) + .GetSupportedStyleSet() + .raw); } void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { @@ -813,11 +831,12 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + 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()}; @@ -833,10 +852,11 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + 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()}; @@ -852,7 +872,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop()}; + const auto npad_id{rp.PopEnum()}; LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); @@ -867,16 +887,17 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { // Should have no effect with how our npad sets up the data IPC::RequestParser rp{ctx}; struct Parameters { - u32 unknown; + 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()}; applet_resource->ActivateController(HidController::NPad); - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, + LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -911,10 +932,11 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + 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()}; @@ -932,11 +954,12 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; u64 npad_joy_device_type; }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -955,10 +978,11 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + 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()}; @@ -974,8 +998,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.Pop()}; - const auto npad_id_2{rp.Pop()}; + const auto npad_id_1{rp.PopEnum()}; + const auto npad_id_2{rp.PopEnum()}; const auto applet_resource_user_id{rp.Pop()}; applet_resource->GetController(HidController::NPad) @@ -1041,8 +1065,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.Pop()}; - const auto npad_id_2{rp.Pop()}; + const auto npad_id_1{rp.PopEnum()}; + const auto npad_id_2{rp.PopEnum()}; const auto applet_resource_user_id{rp.Pop()}; const bool res = applet_resource->GetController(HidController::NPad) @@ -1063,10 +1087,11 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + 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()}; @@ -1084,9 +1109,10 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c struct Parameters { bool unintended_home_button_input_protection; INSERT_PADDING_BYTES_NOINIT(3); - u32 npad_id; + Core::HID::NpadIdType npad_id; u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1108,6 +1134,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::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."); @@ -1127,7 +1154,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw()}; + const auto vibration_device_handle{rp.PopRaw()}; Core::HID::VibrationDeviceInfo vibration_device_info; @@ -1149,13 +1176,13 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { } switch (vibration_device_handle.device_index) { - case Controller_NPad::DeviceIndex::Left: + case Core::HID::DeviceIndex::Left: vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; break; - case Controller_NPad::DeviceIndex::Right: + case Core::HID::DeviceIndex::Right: vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; break; - case Controller_NPad::DeviceIndex::None: + case Core::HID::DeviceIndex::None: default: UNREACHABLE_MSG("DeviceIndex should never be None!"); vibration_device_info.position = Core::HID::VibrationDevicePosition::None; @@ -1173,11 +1200,12 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; - Controller_NPad::VibrationValue vibration_value; + 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()}; @@ -1197,10 +1225,11 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + 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()}; @@ -1251,10 +1280,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { const auto handles = ctx.ReadBuffer(0); const auto vibrations = ctx.ReadBuffer(1); - std::vector vibration_device_handles( - handles.size() / sizeof(Controller_NPad::DeviceHandle)); - std::vector vibration_values( - vibrations.size() / sizeof(Controller_NPad::VibrationValue)); + std::vector vibration_device_handles( + handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); + std::vector vibration_values(vibrations.size() / + sizeof(Core::HID::VibrationValue)); std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); @@ -1271,7 +1300,8 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; Core::HID::VibrationGcErmCommand gc_erm_command; }; @@ -1288,25 +1318,25 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { const auto vibration_value = [parameters] { switch (parameters.gc_erm_command) { case Core::HID::VibrationGcErmCommand::Stop: - return Controller_NPad::VibrationValue{ - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, + 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 Controller_NPad::VibrationValue{ - .amp_low = 1.0f, - .freq_low = 160.0f, - .amp_high = 1.0f, - .freq_high = 320.0f, + 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 Controller_NPad::VibrationValue{ - .amp_low = 0.0f, - .freq_low = 0.0f, - .amp_high = 0.0f, - .freq_high = 0.0f, + return Core::HID::VibrationValue{ + .low_amplitude = 0.0f, + .low_frequency = 0.0f, + .high_amplitude = 0.0f, + .high_frequency = 0.0f, }; default: return Controller_NPad::DEFAULT_VIBRATION_VALUE; @@ -1331,7 +1361,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -1342,7 +1372,7 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { .GetLastVibration(parameters.vibration_device_handle); const auto gc_erm_command = [last_vibration] { - if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { + if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { return Core::HID::VibrationGcErmCommand::Start; } @@ -1352,7 +1382,7 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { * 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.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { + if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { return Core::HID::VibrationGcErmCommand::StopHard; } @@ -1396,10 +1426,11 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + 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()}; @@ -1430,18 +1461,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - 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); + 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); @@ -1450,18 +1481,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + 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()}; - 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); + 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); @@ -1615,10 +1646,8 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", - applet_resource_user_id); + LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 76f55eb54..0254ea6fe 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -627,7 +627,8 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { return; } - const auto devices = emulated_controller->GetMappedDevices(Core::HID::DeviceIndex::AllDevices); + const auto devices = + emulated_controller->GetMappedDevices(Core::HID::EmulatedDeviceIndex::AllDevices); UpdateInputDevices(); if (devices.empty()) { @@ -846,6 +847,7 @@ void ConfigureInputPlayer::SetConnectableControllers() { if (!is_powered_on) { add_controllers(true); + return; } add_controllers(false, hid_core.GetSupportedStyleTag()); diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index ff40f57f5..6630321cb 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -357,7 +357,8 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) DrawCircle(p, center + QPoint(26, 71), 5); // Draw battery - DrawBattery(p, center + QPoint(-170, -140), battery_values[Core::HID::DeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(-170, -140), + battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) { @@ -483,7 +484,8 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5); // Draw battery - DrawBattery(p, center + QPoint(110, -140), battery_values[Core::HID::DeviceIndex::RightIndex]); + DrawBattery(p, center + QPoint(110, -140), + battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { @@ -619,8 +621,10 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f); // Draw battery - DrawBattery(p, center + QPoint(-100, -160), battery_values[Core::HID::DeviceIndex::LeftIndex]); - DrawBattery(p, center + QPoint(40, -160), battery_values[Core::HID::DeviceIndex::RightIndex]); + DrawBattery(p, center + QPoint(-100, -160), + battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(40, -160), + battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { @@ -721,8 +725,10 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f); // Draw battery - DrawBattery(p, center + QPoint(-200, 110), battery_values[Core::HID::DeviceIndex::LeftIndex]); - DrawBattery(p, center + QPoint(130, 110), battery_values[Core::HID::DeviceIndex::RightIndex]); + DrawBattery(p, center + QPoint(-200, 110), + battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(130, 110), + battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { @@ -812,7 +818,8 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); // Draw battery - DrawBattery(p, center + QPoint(-30, -160), battery_values[Core::HID::DeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(-30, -160), + battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { @@ -868,7 +875,8 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8); // Draw battery - DrawBattery(p, center + QPoint(-30, -165), battery_values[Core::HID::DeviceIndex::LeftIndex]); + DrawBattery(p, center + QPoint(-30, -165), + battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } constexpr std::array symbol_a = { From 7fcfe24a3edff903871bee6c249d97e64648ddfa Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 13 Nov 2021 02:39:01 -0600 Subject: [PATCH 122/291] core/hid: Fix keyboard alignment --- src/core/hid/hid_types.h | 25 ++++++++++--------- .../hle/service/hid/controllers/keyboard.cpp | 1 + 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index f224cb744..41bc65ce2 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -423,20 +423,21 @@ static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incor // This is nn::hid::KeyboardModifier struct KeyboardModifier { union { - u32 raw{}; - BitField<0, 1, u32> control; - BitField<1, 1, u32> shift; - BitField<2, 1, u32> left_alt; - BitField<3, 1, u32> right_alt; - BitField<4, 1, u32> gui; - BitField<8, 1, u32> caps_lock; - BitField<9, 1, u32> scroll_lock; - BitField<10, 1, u32> num_lock; - BitField<11, 1, u32> katakana; - BitField<12, 1, u32> hiragana; + u64 raw{}; + BitField<0, 1, u64> control; + BitField<1, 1, u64> shift; + BitField<2, 1, u64> left_alt; + BitField<3, 1, u64> right_alt; + BitField<4, 1, u64> gui; + BitField<8, 1, u64> caps_lock; + BitField<9, 1, u64> scroll_lock; + BitField<10, 1, u64> num_lock; + BitField<11, 1, u64> katakana; + BitField<12, 1, u64> hiragana; + BitField<32, 1, u64> unknown; }; }; -static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size"); +static_assert(sizeof(KeyboardModifier) == 0x8, "KeyboardModifier is an invalid size"); // This is nn::hid::KeyboardKey struct KeyboardKey { diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 1dc219bf5..d6505dbc5 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -42,6 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, next_state.key = keyboard_state; next_state.modifier = keyboard_modifier_state; + next_state.modifier.unknown.Assign(1); } keyboard_lifo.WriteNextEntry(next_state); From b673857d7dfc72f38d9242b315cd590b859795ff Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 13 Nov 2021 23:25:45 -0600 Subject: [PATCH 123/291] core/hid: Improve accuracy of the keyboard implementation --- src/common/settings_input.h | 35 +- src/core/hid/emulated_devices.cpp | 3 +- src/core/hid/hid_types.h | 398 ++++++++++++------ .../hle/service/hid/controllers/keyboard.cpp | 1 + src/core/hle/service/hid/hid.cpp | 35 +- src/core/hle/service/hid/hid.h | 2 + src/input_common/drivers/keyboard.cpp | 53 ++- src/input_common/drivers/keyboard.h | 7 + src/input_common/main.cpp | 9 + src/input_common/main.h | 3 + src/yuzu/bootmanager.cpp | 276 +++++++++++- src/yuzu/bootmanager.h | 6 + src/yuzu/configuration/config.cpp | 167 +------- 13 files changed, 682 insertions(+), 313 deletions(-) diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 2c0eb31d3..a2982fca4 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -129,7 +129,6 @@ extern const std::array mapping; namespace NativeKeyboard { enum Keys { None, - Error, A = 4, B, @@ -167,22 +166,22 @@ enum Keys { N8, N9, N0, - Enter, + Return, Escape, Backspace, Tab, Space, Minus, - Equal, - LeftBrace, - RightBrace, - Backslash, + Plus, + OpenBracket, + CloseBracket, + Pipe, Tilde, Semicolon, - Apostrophe, - Grave, + Quote, + Backquote, Comma, - Dot, + Period, Slash, CapsLockKey, @@ -199,7 +198,7 @@ enum Keys { F11, F12, - SystemRequest, + PrintScreen, ScrollLockKey, Pause, Insert, @@ -268,8 +267,18 @@ enum Keys { ScrollLockActive, KPComma, - KPLeftParenthesis, - KPRightParenthesis, + Ro = 0x87, + KatakanaHiragana, + Yen, + Henkan, + Muhenkan, + NumPadCommaPc98, + + HangulEnglish = 0x90, + Hanja, + KatakanaKey, + HiraganaKey, + ZenkakuHankaku, LeftControlKey = 0xE0, LeftShiftKey, @@ -318,6 +327,8 @@ enum Modifiers { CapsLock, ScrollLock, NumLock, + Katakana, + Hiragana, NumKeyboardMods, }; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index e97470240..0d840a003 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -170,13 +170,14 @@ void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, return; } + // Index should be converted from NativeKeyboard to KeyboardKeyIndex UpdateKey(index, current_status.value); TriggerOnChange(DeviceTriggerType::Keyboard); } void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { - constexpr u8 KEYS_PER_BYTE = 8; + constexpr std::size_t KEYS_PER_BYTE = 8; auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; const u8 mask = static_cast(1 << (key_index % KEYS_PER_BYTE)); if (status) { diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 41bc65ce2..af95f3aff 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -12,6 +12,195 @@ namespace Core::HID { +enum class DeviceIndex : u8 { + Left = 0, + Right = 1, + None = 2, + MaxDeviceIndex = 3, +}; + +// This is nn::hid::NpadButton +enum class NpadButton : u64 { + None = 0, + A = 1U << 0, + B = 1U << 1, + X = 1U << 2, + Y = 1U << 3, + StickL = 1U << 4, + StickR = 1U << 5, + L = 1U << 6, + R = 1U << 7, + ZL = 1U << 8, + ZR = 1U << 9, + Plus = 1U << 10, + Minus = 1U << 11, + + Left = 1U << 12, + Up = 1U << 13, + Right = 1U << 14, + Down = 1U << 15, + + StickLLeft = 1U << 16, + StickLUp = 1U << 17, + StickLRight = 1U << 18, + StickLDown = 1U << 19, + + StickRLeft = 1U << 20, + StickRUp = 1U << 21, + StickRRight = 1U << 22, + StickRDown = 1U << 23, + + LeftSL = 1U << 24, + LeftSR = 1U << 25, + + RightSL = 1U << 26, + RightSR = 1U << 27, + + Palma = 1U << 28, + Verification = 1U << 29, + HandheldLeftB = 1U << 30, + LagonCLeft = 1U << 31, + LagonCUp = 1ULL << 32, + LagonCRight = 1ULL << 33, + LagonCDown = 1ULL << 34, +}; +DECLARE_ENUM_FLAG_OPERATORS(NpadButton); + +enum class KeyboardKeyIndex : u32 { + A = 4, + B = 5, + C = 6, + D = 7, + E = 8, + F = 9, + G = 10, + H = 11, + I = 12, + J = 13, + K = 14, + L = 15, + M = 16, + N = 17, + O = 18, + P = 19, + Q = 20, + R = 21, + S = 22, + T = 23, + U = 24, + V = 25, + W = 26, + X = 27, + Y = 28, + Z = 29, + D1 = 30, + D2 = 31, + D3 = 32, + D4 = 33, + D5 = 34, + D6 = 35, + D7 = 36, + D8 = 37, + D9 = 38, + D0 = 39, + Return = 40, + Escape = 41, + Backspace = 42, + Tab = 43, + Space = 44, + Minus = 45, + Plus = 46, + OpenBracket = 47, + CloseBracket = 48, + Pipe = 49, + Tilde = 50, + Semicolon = 51, + Quote = 52, + Backquote = 53, + Comma = 54, + Period = 55, + Slash = 56, + CapsLock = 57, + F1 = 58, + F2 = 59, + F3 = 60, + F4 = 61, + F5 = 62, + F6 = 63, + F7 = 64, + F8 = 65, + F9 = 66, + F10 = 67, + F11 = 68, + F12 = 69, + PrintScreen = 70, + ScrollLock = 71, + Pause = 72, + Insert = 73, + Home = 74, + PageUp = 75, + Delete = 76, + End = 77, + PageDown = 78, + RightArrow = 79, + LeftArrow = 80, + DownArrow = 81, + UpArrow = 82, + NumLock = 83, + NumPadDivide = 84, + NumPadMultiply = 85, + NumPadSubtract = 86, + NumPadAdd = 87, + NumPadEnter = 88, + NumPad1 = 89, + NumPad2 = 90, + NumPad3 = 91, + NumPad4 = 92, + NumPad5 = 93, + NumPad6 = 94, + NumPad7 = 95, + NumPad8 = 96, + NumPad9 = 97, + NumPad0 = 98, + NumPadDot = 99, + Backslash = 100, + Application = 101, + Power = 102, + NumPadEquals = 103, + F13 = 104, + F14 = 105, + F15 = 106, + F16 = 107, + F17 = 108, + F18 = 109, + F19 = 110, + F20 = 111, + F21 = 112, + F22 = 113, + F23 = 114, + F24 = 115, + NumPadComma = 133, + Ro = 135, + KatakanaHiragana = 136, + Yen = 137, + Henkan = 138, + Muhenkan = 139, + NumPadCommaPc98 = 140, + HangulEnglish = 144, + Hanja = 145, + Katakana = 146, + Hiragana = 147, + ZenkakuHankaku = 148, + LeftControl = 224, + LeftShift = 225, + LeftAlt = 226, + LeftGui = 227, + RightControl = 228, + RightShift = 229, + RightAlt = 230, + RightGui = 231, +}; + // This is nn::hid::NpadIdType enum class NpadIdType : u32 { Player1 = 0x0, @@ -28,62 +217,6 @@ enum class NpadIdType : u32 { Invalid = 0xFFFFFFFF, }; -/// Converts a NpadIdType to an array index. -constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { - switch (npad_id_type) { - case NpadIdType::Player1: - return 0; - case NpadIdType::Player2: - return 1; - case NpadIdType::Player3: - return 2; - case NpadIdType::Player4: - return 3; - case NpadIdType::Player5: - return 4; - case NpadIdType::Player6: - return 5; - case NpadIdType::Player7: - return 6; - case NpadIdType::Player8: - return 7; - case NpadIdType::Handheld: - return 8; - case NpadIdType::Other: - return 9; - default: - return 0; - } -} - -/// Converts an array index to a NpadIdType -constexpr NpadIdType IndexToNpadIdType(size_t index) { - switch (index) { - case 0: - return NpadIdType::Player1; - case 1: - return NpadIdType::Player2; - case 2: - return NpadIdType::Player3; - case 3: - return NpadIdType::Player4; - case 4: - return NpadIdType::Player5; - case 5: - return NpadIdType::Player6; - case 6: - return NpadIdType::Player7; - case 7: - return NpadIdType::Player8; - case 8: - return NpadIdType::Handheld; - case 9: - return NpadIdType::Other; - default: - return NpadIdType::Invalid; - } -} - // This is nn::hid::NpadStyleIndex enum class NpadStyleIndex : u8 { None = 0, @@ -124,6 +257,27 @@ enum class NpadStyleSet : u32 { }; static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); +// This is nn::hid::VibrationDevicePosition +enum class VibrationDevicePosition : u32 { + None = 0, + Left = 1, + Right = 2, +}; + +// This is nn::hid::VibrationDeviceType +enum class VibrationDeviceType : u32 { + Unknown = 0, + LinearResonantActuator = 1, + GcErm = 2, +}; + +// This is nn::hid::VibrationGcErmCommand +enum class VibrationGcErmCommand : u64 { + Stop = 0, + Start = 1, + StopHard = 2, +}; + // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { @@ -220,53 +374,6 @@ struct LedPattern { }; }; -// This is nn::hid::NpadButton -enum class NpadButton : u64 { - None = 0, - A = 1U << 0, - B = 1U << 1, - X = 1U << 2, - Y = 1U << 3, - StickL = 1U << 4, - StickR = 1U << 5, - L = 1U << 6, - R = 1U << 7, - ZL = 1U << 8, - ZR = 1U << 9, - Plus = 1U << 10, - Minus = 1U << 11, - - Left = 1U << 12, - Up = 1U << 13, - Right = 1U << 14, - Down = 1U << 15, - - StickLLeft = 1U << 16, - StickLUp = 1U << 17, - StickLRight = 1U << 18, - StickLDown = 1U << 19, - - StickRLeft = 1U << 20, - StickRUp = 1U << 21, - StickRRight = 1U << 22, - StickRDown = 1U << 23, - - LeftSL = 1U << 24, - LeftSR = 1U << 25, - - RightSL = 1U << 26, - RightSR = 1U << 27, - - Palma = 1U << 28, - Verification = 1U << 29, - HandheldLeftB = 1U << 30, - LagonCLeft = 1U << 31, - LagonCUp = 1ULL << 32, - LagonCRight = 1ULL << 33, - LagonCDown = 1ULL << 34, -}; -DECLARE_ENUM_FLAG_OPERATORS(NpadButton); - struct NpadButtonState { union { NpadButton raw{}; @@ -342,13 +449,6 @@ struct DebugPadButton { }; static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"); -enum class DeviceIndex : u8 { - Left = 0, - Right = 1, - None = 2, - MaxDeviceIndex = 3, -}; - // This is nn::hid::ConsoleSixAxisSensorHandle struct ConsoleSixAxisSensorHandle { u8 unknown_1; @@ -383,20 +483,6 @@ struct VibrationDeviceHandle { }; static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); -// This is nn::hid::VibrationDeviceType -enum class VibrationDeviceType : u32 { - Unknown = 0, - LinearResonantActuator = 1, - GcErm = 2, -}; - -// This is nn::hid::VibrationDevicePosition -enum class VibrationDevicePosition : u32 { - None = 0, - Left = 1, - Right = 2, -}; - // This is nn::hid::VibrationValue struct VibrationValue { f32 low_amplitude; @@ -406,13 +492,6 @@ struct VibrationValue { }; static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); -// This is nn::hid::VibrationGcErmCommand -enum class VibrationGcErmCommand : u64 { - Stop = 0, - Start = 1, - StopHard = 2, -}; - // This is nn::hid::VibrationDeviceInfo struct VibrationDeviceInfo { VibrationDeviceType type{}; @@ -482,4 +561,61 @@ struct MouseState { MouseAttribute attribute; }; static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); + +/// Converts a NpadIdType to an array index. +constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { + switch (npad_id_type) { + case NpadIdType::Player1: + return 0; + case NpadIdType::Player2: + return 1; + case NpadIdType::Player3: + return 2; + case NpadIdType::Player4: + return 3; + case NpadIdType::Player5: + return 4; + case NpadIdType::Player6: + return 5; + case NpadIdType::Player7: + return 6; + case NpadIdType::Player8: + return 7; + case NpadIdType::Handheld: + return 8; + case NpadIdType::Other: + return 9; + default: + return 0; + } +} + +/// Converts an array index to a NpadIdType +constexpr NpadIdType IndexToNpadIdType(size_t index) { + switch (index) { + case 0: + return NpadIdType::Player1; + case 1: + return NpadIdType::Player2; + case 2: + return NpadIdType::Player3; + case 3: + return NpadIdType::Player4; + case 4: + return NpadIdType::Player5; + case 5: + return NpadIdType::Player6; + case 6: + return NpadIdType::Player7; + case 7: + return NpadIdType::Player8; + case 8: + return NpadIdType::Handheld; + case 9: + return NpadIdType::Other; + default: + return NpadIdType::Invalid; + } +} + } // namespace Core::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index d6505dbc5..0ef8af0e6 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -42,6 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, next_state.key = keyboard_state; next_state.modifier = keyboard_modifier_state; + // This is always enabled on HW. Check what it actually does next_state.modifier.unknown.Assign(1); } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 496b55d0e..e740b4331 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -35,8 +35,9 @@ 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 -constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) +constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) +constexpr auto keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) +constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -78,14 +79,21 @@ IAppletResource::IAppletResource(Core::System& system_, const auto guard = LockService(); UpdateControllers(user_data, ns_late); }); + keyboard_update_event = Core::Timing::CreateEvent( + "HID::UpdatekeyboardCallback", + [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + const auto guard = LockService(); + UpdateKeyboard(user_data, ns_late); + }); motion_update_event = Core::Timing::CreateEvent( - "HID::MotionPadCallback", + "HID::UpdateMotionCallback", [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { const auto guard = LockService(); UpdateMotion(user_data, ns_late); }); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); system.HIDCore().ReloadInputDevices(); @@ -101,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) { IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -117,18 +126,36 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, auto& core_timing = system.CoreTiming(); for (const auto& controller : controllers) { + // Keyboard has it's own update event + if (controller == controllers[static_cast(HidController::Keyboard)]) { + continue; + } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } // If ns_late is higher than the update rate ignore the delay - if (ns_late > motion_update_ns) { + if (ns_late > pad_update_ns) { ns_late = {}; } core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } +void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + auto& core_timing = system.CoreTiming(); + + controllers[static_cast(HidController::Keyboard)]->OnUpdate( + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); + + // If ns_late is higher than the update rate ignore the delay + if (ns_late > keyboard_update_ns) { + ns_late = {}; + } + + core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event); +} + void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 973e6a8ac..bbad165f8 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -70,11 +70,13 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + void UpdateKeyboard(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 pad_update_event; + std::shared_ptr keyboard_update_event; std::shared_ptr motion_update_event; std::array, static_cast(HidController::MaxControllers)> diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 549704e89..328fe1ac1 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -3,26 +3,71 @@ // Refer to the license.txt file included #include "common/param_package.h" +#include "common/settings_input.h" #include "input_common/drivers/keyboard.h" namespace InputCommon { -constexpr PadIdentifier identifier = { +constexpr PadIdentifier key_identifier = { .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; +constexpr PadIdentifier modifier_identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 1, +}; Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { - PreSetController(identifier); + PreSetController(key_identifier); + PreSetController(modifier_identifier); } void Keyboard::PressKey(int key_code) { - SetButton(identifier, key_code, true); + SetButton(key_identifier, key_code, true); } void Keyboard::ReleaseKey(int key_code) { - SetButton(identifier, key_code, false); + SetButton(key_identifier, key_code, false); +} + +void Keyboard::SetModifiers(int key_modifiers) { + for (int i = 0; i < 32; ++i) { + bool key_value = ((key_modifiers >> i) & 0x1) != 0; + SetButton(modifier_identifier, i, key_value); + // Use the modifier to press the key button equivalent + switch (i) { + case Settings::NativeKeyboard::LeftControl: + SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); + break; + case Settings::NativeKeyboard::LeftShift: + SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); + break; + case Settings::NativeKeyboard::LeftAlt: + SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); + break; + case Settings::NativeKeyboard::LeftMeta: + SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); + break; + case Settings::NativeKeyboard::RightControl: + SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value); + break; + case Settings::NativeKeyboard::RightShift: + SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); + break; + case Settings::NativeKeyboard::RightAlt: + SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); + break; + case Settings::NativeKeyboard::RightMeta: + SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); + break; + default: + // Other modifier keys should be pressed with PressKey since they stay enabled until + // next press + break; + } + } } void Keyboard::ReleaseAllKeys() { diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 46fe78576..2ab92fd6c 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -28,6 +28,13 @@ public: */ void ReleaseKey(int key_code); + /** + * Sets the status of all keyboard modifier keys + * @param key_modifiers the code of the key to release + */ + void SetModifiers(int key_modifiers); + + /// Sets all keys to the non pressed state void ReleaseAllKeys(); /// Used for automapping features diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index df36a337c..ae2518f53 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -402,6 +402,15 @@ std::string GenerateKeyboardParam(int key_code) { return param.Serialize(); } +std::string GenerateModdifierKeyboardParam(int key_code) { + Common::ParamPackage param; + param.Set("engine", "keyboard"); + param.Set("code", key_code); + param.Set("toggle", false); + param.Set("pad", 1); + return param.Serialize(); +} + std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale) { Common::ParamPackage circle_pad_param{ diff --git a/src/input_common/main.h b/src/input_common/main.h index a4a24d076..9ea395465 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -134,6 +134,9 @@ private: /// Generates a serialized param package for creating a keyboard button device. std::string GenerateKeyboardParam(int key_code); +/// Generates a serialized param package for creating a moddifier keyboard button device. +std::string GenerateModdifierKeyboardParam(int key_code); + /// Generates a serialized param package for creating an analog device taking input from keyboard. std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 3c5590a01..61513a5b4 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -392,15 +392,287 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } +int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { + switch (qt_key) { + case Qt::Key_A: + return Settings::NativeKeyboard::A; + case Qt::Key_B: + return Settings::NativeKeyboard::B; + case Qt::Key_C: + return Settings::NativeKeyboard::C; + case Qt::Key_D: + return Settings::NativeKeyboard::D; + case Qt::Key_E: + return Settings::NativeKeyboard::E; + case Qt::Key_F: + return Settings::NativeKeyboard::F; + case Qt::Key_G: + return Settings::NativeKeyboard::G; + case Qt::Key_H: + return Settings::NativeKeyboard::H; + case Qt::Key_I: + return Settings::NativeKeyboard::I; + case Qt::Key_J: + return Settings::NativeKeyboard::J; + case Qt::Key_K: + return Settings::NativeKeyboard::K; + case Qt::Key_L: + return Settings::NativeKeyboard::L; + case Qt::Key_M: + return Settings::NativeKeyboard::M; + case Qt::Key_N: + return Settings::NativeKeyboard::N; + case Qt::Key_O: + return Settings::NativeKeyboard::O; + case Qt::Key_P: + return Settings::NativeKeyboard::P; + case Qt::Key_Q: + return Settings::NativeKeyboard::Q; + case Qt::Key_R: + return Settings::NativeKeyboard::R; + case Qt::Key_S: + return Settings::NativeKeyboard::S; + case Qt::Key_T: + return Settings::NativeKeyboard::T; + case Qt::Key_U: + return Settings::NativeKeyboard::U; + case Qt::Key_V: + return Settings::NativeKeyboard::V; + case Qt::Key_W: + return Settings::NativeKeyboard::W; + case Qt::Key_X: + return Settings::NativeKeyboard::X; + case Qt::Key_Y: + return Settings::NativeKeyboard::Y; + case Qt::Key_Z: + return Settings::NativeKeyboard::Z; + case Qt::Key_1: + return Settings::NativeKeyboard::N1; + case Qt::Key_2: + return Settings::NativeKeyboard::N2; + case Qt::Key_3: + return Settings::NativeKeyboard::N3; + case Qt::Key_4: + return Settings::NativeKeyboard::N4; + case Qt::Key_5: + return Settings::NativeKeyboard::N5; + case Qt::Key_6: + return Settings::NativeKeyboard::N6; + case Qt::Key_7: + return Settings::NativeKeyboard::N7; + case Qt::Key_8: + return Settings::NativeKeyboard::N8; + case Qt::Key_9: + return Settings::NativeKeyboard::N9; + case Qt::Key_0: + return Settings::NativeKeyboard::N0; + case Qt::Key_Return: + return Settings::NativeKeyboard::Return; + case Qt::Key_Escape: + return Settings::NativeKeyboard::Escape; + case Qt::Key_Backspace: + return Settings::NativeKeyboard::Backspace; + case Qt::Key_Tab: + return Settings::NativeKeyboard::Tab; + case Qt::Key_Space: + return Settings::NativeKeyboard::Space; + case Qt::Key_Minus: + return Settings::NativeKeyboard::Minus; + case Qt::Key_Plus: + case Qt::Key_questiondown: + return Settings::NativeKeyboard::Plus; + case Qt::Key_BracketLeft: + case Qt::Key_BraceLeft: + return Settings::NativeKeyboard::OpenBracket; + case Qt::Key_BracketRight: + case Qt::Key_BraceRight: + return Settings::NativeKeyboard::CloseBracket; + case Qt::Key_Bar: + return Settings::NativeKeyboard::Pipe; + case Qt::Key_Dead_Tilde: + return Settings::NativeKeyboard::Tilde; + case Qt::Key_Ntilde: + case Qt::Key_Semicolon: + return Settings::NativeKeyboard::Semicolon; + case Qt::Key_Apostrophe: + return Settings::NativeKeyboard::Quote; + case Qt::Key_Dead_Grave: + return Settings::NativeKeyboard::Backquote; + case Qt::Key_Comma: + return Settings::NativeKeyboard::Comma; + case Qt::Key_Period: + return Settings::NativeKeyboard::Period; + case Qt::Key_Slash: + return Settings::NativeKeyboard::Slash; + case Qt::Key_CapsLock: + return Settings::NativeKeyboard::CapsLock; + case Qt::Key_F1: + return Settings::NativeKeyboard::F1; + case Qt::Key_F2: + return Settings::NativeKeyboard::F2; + case Qt::Key_F3: + return Settings::NativeKeyboard::F3; + case Qt::Key_F4: + return Settings::NativeKeyboard::F4; + case Qt::Key_F5: + return Settings::NativeKeyboard::F5; + case Qt::Key_F6: + return Settings::NativeKeyboard::F6; + case Qt::Key_F7: + return Settings::NativeKeyboard::F7; + case Qt::Key_F8: + return Settings::NativeKeyboard::F8; + case Qt::Key_F9: + return Settings::NativeKeyboard::F9; + case Qt::Key_F10: + return Settings::NativeKeyboard::F10; + case Qt::Key_F11: + return Settings::NativeKeyboard::F11; + case Qt::Key_F12: + return Settings::NativeKeyboard::F12; + case Qt::Key_Print: + return Settings::NativeKeyboard::PrintScreen; + case Qt::Key_ScrollLock: + return Settings::NativeKeyboard::ScrollLock; + case Qt::Key_Pause: + return Settings::NativeKeyboard::Pause; + case Qt::Key_Insert: + return Settings::NativeKeyboard::Insert; + case Qt::Key_Home: + return Settings::NativeKeyboard::Home; + case Qt::Key_PageUp: + return Settings::NativeKeyboard::PageUp; + case Qt::Key_Delete: + return Settings::NativeKeyboard::Delete; + case Qt::Key_End: + return Settings::NativeKeyboard::End; + case Qt::Key_PageDown: + return Settings::NativeKeyboard::PageDown; + case Qt::Key_Right: + return Settings::NativeKeyboard::Right; + case Qt::Key_Left: + return Settings::NativeKeyboard::Left; + case Qt::Key_Down: + return Settings::NativeKeyboard::Down; + case Qt::Key_Up: + return Settings::NativeKeyboard::Up; + case Qt::Key_NumLock: + return Settings::NativeKeyboard::NumLock; + // Numpad keys are missing here + case Qt::Key_F13: + return Settings::NativeKeyboard::F13; + case Qt::Key_F14: + return Settings::NativeKeyboard::F14; + case Qt::Key_F15: + return Settings::NativeKeyboard::F15; + case Qt::Key_F16: + return Settings::NativeKeyboard::F16; + case Qt::Key_F17: + return Settings::NativeKeyboard::F17; + case Qt::Key_F18: + return Settings::NativeKeyboard::F18; + case Qt::Key_F19: + return Settings::NativeKeyboard::F19; + case Qt::Key_F20: + return Settings::NativeKeyboard::F20; + case Qt::Key_F21: + return Settings::NativeKeyboard::F21; + case Qt::Key_F22: + return Settings::NativeKeyboard::F22; + case Qt::Key_F23: + return Settings::NativeKeyboard::F23; + case Qt::Key_F24: + return Settings::NativeKeyboard::F24; + // case Qt::: + // return Settings::NativeKeyboard::KPComma; + // case Qt::: + // return Settings::NativeKeyboard::Ro; + case Qt::Key_Hiragana_Katakana: + return Settings::NativeKeyboard::KatakanaHiragana; + case Qt::Key_yen: + return Settings::NativeKeyboard::Yen; + case Qt::Key_Henkan: + return Settings::NativeKeyboard::Henkan; + case Qt::Key_Muhenkan: + return Settings::NativeKeyboard::Muhenkan; + // case Qt::: + // return Settings::NativeKeyboard::NumPadCommaPc98; + case Qt::Key_Hangul: + return Settings::NativeKeyboard::HangulEnglish; + case Qt::Key_Hangul_Hanja: + return Settings::NativeKeyboard::Hanja; + case Qt::Key_Katakana: + return Settings::NativeKeyboard::KatakanaKey; + case Qt::Key_Hiragana: + return Settings::NativeKeyboard::HiraganaKey; + case Qt::Key_Zenkaku_Hankaku: + return Settings::NativeKeyboard::ZenkakuHankaku; + // Modifier keys are handled by the modifier property + default: + return 0; + } +} + +int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) { + int moddifier = 0; + // The values are obtained through testing, Qt doesn't seem to provide a proper enum + if ((qt_moddifiers & 0x1) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::LeftShift; + } + if ((qt_moddifiers & 0x2) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::LeftControl; + } + if ((qt_moddifiers & 0x4) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::LeftAlt; + } + if ((qt_moddifiers & 0x08) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::LeftMeta; + } + if ((qt_moddifiers & 0x10) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::RightShift; + } + if ((qt_moddifiers & 0x20) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::RightControl; + } + if ((qt_moddifiers & 0x40) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::RightAlt; + } + if ((qt_moddifiers & 0x80) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::RightMeta; + } + if ((qt_moddifiers & 0x100) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::CapsLock; + } + if ((qt_moddifiers & 0x200) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::NumLock; + } + // Verify the last two keys + if ((qt_moddifiers & 0x400) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::Katakana; + } + if ((qt_moddifiers & 0x800) != 0) { + moddifier |= 1 << Settings::NativeKeyboard::Hiragana; + } + return moddifier; +} + void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - input_subsystem->GetKeyboard()->PressKey(event->key()); + const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key + // buttons + const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); + input_subsystem->GetKeyboard()->SetModifiers(moddifier); + input_subsystem->GetKeyboard()->PressKey(key); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - input_subsystem->GetKeyboard()->ReleaseKey(event->key()); + const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); + input_subsystem->GetKeyboard()->SetModifiers(moddifier); + input_subsystem->GetKeyboard()->ReleaseKey(key); } } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 95594f81c..c42d139be 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -158,6 +158,12 @@ public: void resizeEvent(QResizeEvent* event) override; + /// Converts a Qt keybard key into NativeKeyboard key + static int QtKeyToSwitchKey(Qt::Key qt_keys); + + /// Converts a Qt modifier keys into NativeKeyboard modifier keys + static int QtModifierToSwitchModdifier(quint32 qt_moddifiers); + void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7669fe474..ccf274895 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -65,157 +65,6 @@ const std::array Config::defa Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, }; -const std::array Config::default_keyboard_keys = { - 0, - 0, - 0, - 0, - Qt::Key_A, - Qt::Key_B, - Qt::Key_C, - Qt::Key_D, - Qt::Key_E, - Qt::Key_F, - Qt::Key_G, - Qt::Key_H, - Qt::Key_I, - Qt::Key_J, - Qt::Key_K, - Qt::Key_L, - Qt::Key_M, - Qt::Key_N, - Qt::Key_O, - Qt::Key_P, - Qt::Key_Q, - Qt::Key_R, - Qt::Key_S, - Qt::Key_T, - Qt::Key_U, - Qt::Key_V, - Qt::Key_W, - Qt::Key_X, - Qt::Key_Y, - Qt::Key_Z, - Qt::Key_1, - Qt::Key_2, - Qt::Key_3, - Qt::Key_4, - Qt::Key_5, - Qt::Key_6, - Qt::Key_7, - Qt::Key_8, - Qt::Key_9, - Qt::Key_0, - Qt::Key_Enter, - Qt::Key_Escape, - Qt::Key_Backspace, - Qt::Key_Tab, - Qt::Key_Space, - Qt::Key_Minus, - Qt::Key_Equal, - Qt::Key_BracketLeft, - Qt::Key_BracketRight, - Qt::Key_Backslash, - Qt::Key_Dead_Tilde, - Qt::Key_Semicolon, - Qt::Key_Apostrophe, - Qt::Key_Dead_Grave, - Qt::Key_Comma, - Qt::Key_Period, - Qt::Key_Slash, - Qt::Key_CapsLock, - - Qt::Key_F1, - Qt::Key_F2, - Qt::Key_F3, - Qt::Key_F4, - Qt::Key_F5, - Qt::Key_F6, - Qt::Key_F7, - Qt::Key_F8, - Qt::Key_F9, - Qt::Key_F10, - Qt::Key_F11, - Qt::Key_F12, - - Qt::Key_SysReq, - Qt::Key_ScrollLock, - Qt::Key_Pause, - Qt::Key_Insert, - Qt::Key_Home, - Qt::Key_PageUp, - Qt::Key_Delete, - Qt::Key_End, - Qt::Key_PageDown, - Qt::Key_Right, - Qt::Key_Left, - Qt::Key_Down, - Qt::Key_Up, - - Qt::Key_NumLock, - Qt::Key_Slash, - Qt::Key_Asterisk, - Qt::Key_Minus, - Qt::Key_Plus, - Qt::Key_Enter, - Qt::Key_1, - Qt::Key_2, - Qt::Key_3, - Qt::Key_4, - Qt::Key_5, - Qt::Key_6, - Qt::Key_7, - Qt::Key_8, - Qt::Key_9, - Qt::Key_0, - Qt::Key_Period, - - 0, - 0, - Qt::Key_PowerOff, - Qt::Key_Equal, - - Qt::Key_F13, - Qt::Key_F14, - Qt::Key_F15, - Qt::Key_F16, - Qt::Key_F17, - Qt::Key_F18, - Qt::Key_F19, - Qt::Key_F20, - Qt::Key_F21, - Qt::Key_F22, - Qt::Key_F23, - Qt::Key_F24, - - Qt::Key_Open, - Qt::Key_Help, - Qt::Key_Menu, - 0, - Qt::Key_Stop, - Qt::Key_AudioRepeat, - Qt::Key_Undo, - Qt::Key_Cut, - Qt::Key_Copy, - Qt::Key_Paste, - Qt::Key_Find, - Qt::Key_VolumeMute, - Qt::Key_VolumeUp, - Qt::Key_VolumeDown, - Qt::Key_CapsLock, - Qt::Key_NumLock, - Qt::Key_ScrollLock, - Qt::Key_Comma, - - Qt::Key_ParenLeft, - Qt::Key_ParenRight, -}; - -const std::array Config::default_keyboard_mods = { - Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft, - Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight, -}; - // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as @@ -496,14 +345,14 @@ void Config::ReadDebugValues() { void Config::ReadKeyboardValues() { ReadBasicSetting(Settings::values.keyboard_enabled); - std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(), - Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); - std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), - Settings::values.keyboard_keys.begin() + - Settings::NativeKeyboard::LeftControlKey, - InputCommon::GenerateKeyboardParam); - std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), - Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); + for (std::size_t i = 0; i < Settings::values.keyboard_keys.size(); ++i) { + Settings::values.keyboard_keys[i] = InputCommon::GenerateKeyboardParam(static_cast(i)); + } + + for (std::size_t i = 0; i < Settings::values.keyboard_mods.size(); ++i) { + Settings::values.keyboard_mods[i] = + InputCommon::GenerateModdifierKeyboardParam(static_cast(i)); + } } void Config::ReadMouseValues() { From bca299e8e0489867f7d4bbfd264e221e7e61ae1e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 10:45:07 -0600 Subject: [PATCH 124/291] input_common: Allow keyboard to be backwards compatible --- src/common/settings.h | 2 -- src/core/hid/emulated_devices.cpp | 28 +++++++++++---- src/input_common/drivers/keyboard.cpp | 52 ++++++++++++++++++++------- src/input_common/drivers/keyboard.h | 14 +++++++- src/input_common/input_mapping.cpp | 25 +++++++++++++ src/input_common/input_mapping.h | 7 ++++ src/input_common/main.cpp | 9 ----- src/input_common/main.h | 3 -- src/yuzu/bootmanager.cpp | 14 +++++--- src/yuzu/configuration/config.cpp | 9 ----- 10 files changed, 115 insertions(+), 48 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index b52d0d1d0..ee9e0b5a1 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -572,8 +572,6 @@ struct Values { BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; BasicSetting keyboard_enabled{false, "keyboard_enabled"}; - KeyboardKeysRaw keyboard_keys; - KeyboardModsRaw keyboard_mods; BasicSetting debug_pad_enabled{false, "debug_pad_enabled"}; ButtonsRaw debug_pad_buttons; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 0d840a003..45e0bd80d 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -29,13 +29,29 @@ void EmulatedDevices::ReloadInput() { mouse_button_devices.begin(), Common::Input::CreateDevice); - std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_devices.begin(), - Common::Input::CreateDeviceFromString); + std::size_t key_index = 0; + for (auto& keyboard_device : keyboard_devices) { + // Keyboard keys are only mapped on port 1, pad 0 + Common::ParamPackage keyboard_params; + keyboard_params.Set("engine", "keyboard"); + keyboard_params.Set("button", static_cast(key_index)); + keyboard_params.Set("port", 1); + keyboard_params.Set("pad", 0); + keyboard_device = Common::Input::CreateDevice(keyboard_params); + key_index++; + } - std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), - keyboard_modifier_devices.begin(), - Common::Input::CreateDeviceFromString); + key_index = 0; + for (auto& keyboard_device : keyboard_modifier_devices) { + // Keyboard moddifiers are only mapped on port 1, pad 1 + Common::ParamPackage keyboard_params; + keyboard_params.Set("engine", "keyboard"); + keyboard_params.Set("button", static_cast(key_index)); + keyboard_params.Set("port", 1); + keyboard_params.Set("pad", 1); + keyboard_device = Common::Input::CreateDevice(keyboard_params); + key_index++; + } for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 328fe1ac1..23b0c0ccf 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -13,15 +13,26 @@ constexpr PadIdentifier key_identifier = { .port = 0, .pad = 0, }; -constexpr PadIdentifier modifier_identifier = { +constexpr PadIdentifier keyboard_key_identifier = { .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, + .port = 1, + .pad = 0, +}; +constexpr PadIdentifier keyboard_modifier_identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 1, .pad = 1, }; Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { + // Keyboard is broken into 3 diferent sets: + // key: Unfiltered intended for controllers. + // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. + // keyboard_modifier: Allows only Settings::NativeKeyboard::Modifiers intended for keyboard + // emulation. PreSetController(key_identifier); - PreSetController(modifier_identifier); + PreSetController(keyboard_key_identifier); + PreSetController(keyboard_modifier_identifier); } void Keyboard::PressKey(int key_code) { @@ -32,35 +43,50 @@ void Keyboard::ReleaseKey(int key_code) { SetButton(key_identifier, key_code, false); } -void Keyboard::SetModifiers(int key_modifiers) { +void Keyboard::PressKeyboardKey(int key_index) { + if (key_index == Settings::NativeKeyboard::None) { + return; + } + SetButton(keyboard_key_identifier, key_index, true); +} + +void Keyboard::ReleaseKeyboardKey(int key_index) { + if (key_index == Settings::NativeKeyboard::None) { + return; + } + SetButton(keyboard_key_identifier, key_index, false); +} + +void Keyboard::SetKeyboardModifiers(int key_modifiers) { for (int i = 0; i < 32; ++i) { bool key_value = ((key_modifiers >> i) & 0x1) != 0; - SetButton(modifier_identifier, i, key_value); + SetButton(keyboard_modifier_identifier, i, key_value); // Use the modifier to press the key button equivalent switch (i) { case Settings::NativeKeyboard::LeftControl: - SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); break; case Settings::NativeKeyboard::LeftShift: - SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); break; case Settings::NativeKeyboard::LeftAlt: - SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); break; case Settings::NativeKeyboard::LeftMeta: - SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); break; case Settings::NativeKeyboard::RightControl: - SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightControlKey, + key_value); break; case Settings::NativeKeyboard::RightShift: - SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); break; case Settings::NativeKeyboard::RightAlt: - SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); break; case Settings::NativeKeyboard::RightMeta: - SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); break; default: // Other modifier keys should be pressed with PressKey since they stay enabled until diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 2ab92fd6c..ad123b136 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -28,11 +28,23 @@ public: */ void ReleaseKey(int key_code); + /** + * Sets the status of the keyboard key to pressed + * @param key_index index of the key to press + */ + void PressKeyboardKey(int key_index); + + /** + * Sets the status of the keyboard key to released + * @param key_index index of the key to release + */ + void ReleaseKeyboardKey(int key_index); + /** * Sets the status of all keyboard modifier keys * @param key_modifiers the code of the key to release */ - void SetModifiers(int key_modifiers); + void SetKeyboardModifiers(int key_modifiers); /// Sets all keys to the non pressed state void ReleaseAllKeys(); diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0ffc71028..0eeeff372 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -28,6 +28,10 @@ void MappingFactory::RegisterInput(const MappingData& data) { if (!is_enabled) { return; } + if (!IsDriverValid(data)) { + return; + } + switch (input_type) { case Polling::InputType::Button: RegisterButton(data); @@ -168,4 +172,25 @@ void MappingFactory::RegisterMotion(const MappingData& data) { input_queue.Push(new_input); } +bool MappingFactory::IsDriverValid(const MappingData& data) const { + // Only port 0 can be mapped on the keyboard + if (data.engine == "keyboard" && data.pad.port != 0) { + return false; + } + // The following drivers don't need to be mapped + if (data.engine == "tas") { + return false; + } + if (data.engine == "touch") { + return false; + } + if (data.engine == "touch_from_button") { + return false; + } + if (data.engine == "analog_from_button") { + return false; + } + return true; +} + } // namespace InputCommon diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h index 2622dba70..44eb8ad9a 100644 --- a/src/input_common/input_mapping.h +++ b/src/input_common/input_mapping.h @@ -66,6 +66,13 @@ private: */ void RegisterMotion(const MappingData& data); + /** + * Returns true if driver can be mapped + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + bool IsDriverValid(const MappingData& data) const; + Common::SPSCQueue input_queue; Polling::InputType input_type{Polling::InputType::None}; bool is_enabled{}; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index ae2518f53..df36a337c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -402,15 +402,6 @@ std::string GenerateKeyboardParam(int key_code) { return param.Serialize(); } -std::string GenerateModdifierKeyboardParam(int key_code) { - Common::ParamPackage param; - param.Set("engine", "keyboard"); - param.Set("code", key_code); - param.Set("toggle", false); - param.Set("pad", 1); - return param.Serialize(); -} - std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale) { Common::ParamPackage circle_pad_param{ diff --git a/src/input_common/main.h b/src/input_common/main.h index 9ea395465..a4a24d076 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -134,9 +134,6 @@ private: /// Generates a serialized param package for creating a keyboard button device. std::string GenerateKeyboardParam(int key_code); -/// Generates a serialized param package for creating a moddifier keyboard button device. -std::string GenerateModdifierKeyboardParam(int key_code); - /// Generates a serialized param package for creating an analog device taking input from keyboard. std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 61513a5b4..9f4d1aac3 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -609,7 +609,7 @@ int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { return Settings::NativeKeyboard::ZenkakuHankaku; // Modifier keys are handled by the modifier property default: - return 0; + return Settings::NativeKeyboard::None; } } @@ -662,8 +662,10 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) { // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key // buttons const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetModifiers(moddifier); - input_subsystem->GetKeyboard()->PressKey(key); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->PressKeyboardKey(key); + // This is used for gamepads + input_subsystem->GetKeyboard()->PressKey(event->key()); } } @@ -671,8 +673,10 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetModifiers(moddifier); - input_subsystem->GetKeyboard()->ReleaseKey(key); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key); + // This is used for gamepads + input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ccf274895..5865359fe 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -344,15 +344,6 @@ void Config::ReadDebugValues() { void Config::ReadKeyboardValues() { ReadBasicSetting(Settings::values.keyboard_enabled); - - for (std::size_t i = 0; i < Settings::values.keyboard_keys.size(); ++i) { - Settings::values.keyboard_keys[i] = InputCommon::GenerateKeyboardParam(static_cast(i)); - } - - for (std::size_t i = 0; i < Settings::values.keyboard_mods.size(); ++i) { - Settings::values.keyboard_mods[i] = - InputCommon::GenerateModdifierKeyboardParam(static_cast(i)); - } } void Config::ReadMouseValues() { From 654d76e79e84a3384fa503fac9003a5d0a32f28b Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 14:09:29 -0600 Subject: [PATCH 125/291] core/hid: Fully implement native mouse --- src/common/settings.h | 1 - src/common/settings_input.h | 15 +- src/core/hid/emulated_console.cpp | 11 +- src/core/hid/emulated_devices.cpp | 124 +++++-- src/core/hid/emulated_devices.h | 56 +-- src/core/hid/input_converter.cpp | 21 ++ src/core/hid/input_converter.h | 9 + .../hle/service/hid/controllers/mouse.cpp | 9 +- src/input_common/drivers/mouse.cpp | 31 +- src/input_common/drivers/mouse.h | 7 + src/yuzu/CMakeLists.txt | 3 - src/yuzu/bootmanager.cpp | 6 + src/yuzu/bootmanager.h | 1 + src/yuzu/configuration/config.cpp | 30 -- src/yuzu/configuration/configure_input.cpp | 4 - .../configure_input_advanced.cpp | 2 - .../configuration/configure_input_advanced.ui | 204 +++++------ .../configure_mouse_advanced.cpp | 247 ------------- .../configuration/configure_mouse_advanced.h | 72 ---- .../configuration/configure_mouse_advanced.ui | 335 ------------------ src/yuzu_cmd/config.cpp | 174 --------- 21 files changed, 323 insertions(+), 1039 deletions(-) delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.cpp delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.h delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.ui diff --git a/src/common/settings.h b/src/common/settings.h index ee9e0b5a1..d7410fa9b 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -568,7 +568,6 @@ struct Values { BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; BasicSetting mouse_enabled{false, "mouse_enabled"}; - MouseButtonsRaw mouse_buttons; BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; BasicSetting keyboard_enabled{false, "keyboard_enabled"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index a2982fca4..9a8804488 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -126,6 +126,17 @@ constexpr int NUM_MOUSE_HID = NumMouseButtons; extern const std::array mapping; } // namespace NativeMouseButton +namespace NativeMouseWheel { +enum Values { + X, + Y, + + NumMouseWheels, +}; + +extern const std::array mapping; +} // namespace NativeMouseWheel + namespace NativeKeyboard { enum Keys { None, @@ -348,10 +359,6 @@ using ButtonsRaw = std::array; using MotionsRaw = std::array; using VibrationsRaw = std::array; -using MouseButtonsRaw = std::array; -using KeyboardKeysRaw = std::array; -using KeyboardModsRaw = std::array; - constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 374dd5d41..b224932dc 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -24,7 +24,10 @@ void EmulatedConsole::SetTouchParams() { std::size_t index = 0; // Hardcode mouse, touchscreen and cemuhook parameters - touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + if (!Settings::values.mouse_enabled) { + // We can't use mouse as touch if native mouse is enabled + touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + } touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; @@ -36,6 +39,9 @@ void EmulatedConsole::SetTouchParams() { // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { + if (index >= touch_params.size()) { + continue; + } Common::ParamPackage params{config_entry}; Common::ParamPackage touch_button_params; const int x = params.Get("x", 0); @@ -49,9 +55,6 @@ void EmulatedConsole::SetTouchParams() { touch_button_params.Set("touch_id", static_cast(index)); touch_params[index] = touch_button_params; index++; - if (index >= touch_params.size()) { - return; - } } } diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 45e0bd80d..70a494097 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -15,21 +15,34 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { - const auto& mouse = Settings::values.mouse_buttons; - - for (std::size_t index = 0; index < mouse.size(); ++index) { - mouse_button_params[index] = Common::ParamPackage(mouse[index]); - } ReloadInput(); } void EmulatedDevices::ReloadInput() { - std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, - mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, - mouse_button_devices.begin(), - Common::Input::CreateDevice); - + // If you load any device here add the equivalent to the UnloadInput() function std::size_t key_index = 0; + for (auto& mouse_device : mouse_button_devices) { + Common::ParamPackage mouse_params; + mouse_params.Set("engine", "mouse"); + mouse_params.Set("button", static_cast(key_index)); + mouse_device = Common::Input::CreateDevice(mouse_params); + key_index++; + } + + mouse_stick_device = Common::Input::CreateDeviceFromString( + "engine:mouse,axis_x:0,axis_y:1"); + + // First two axis are reserved for mouse position + key_index = 2; + for (auto& mouse_device : mouse_analog_devices) { + Common::ParamPackage mouse_params; + mouse_params.Set("engine", "mouse"); + mouse_params.Set("axis", static_cast(key_index)); + mouse_device = Common::Input::CreateDevice(mouse_params); + key_index++; + } + + key_index = 0; for (auto& keyboard_device : keyboard_devices) { // Keyboard keys are only mapped on port 1, pad 0 Common::ParamPackage keyboard_params; @@ -64,6 +77,23 @@ void EmulatedDevices::ReloadInput() { mouse_button_devices[index]->SetCallback(button_callback); } + for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) { + if (!mouse_analog_devices[index]) { + continue; + } + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetMouseAnalog(callback, index); + }}; + mouse_analog_devices[index]->SetCallback(button_callback); + } + + if (mouse_stick_device) { + Common::Input::InputCallback button_callback{ + [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }}; + mouse_stick_device->SetCallback(button_callback); + } + for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { if (!keyboard_devices[index]) { continue; @@ -91,6 +121,10 @@ void EmulatedDevices::UnloadInput() { for (auto& button : mouse_button_devices) { button.reset(); } + for (auto& analog : mouse_analog_devices) { + analog.reset(); + } + mouse_stick_device.reset(); for (auto& button : keyboard_devices) { button.reset(); } @@ -116,12 +150,6 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } - - auto& mouse = Settings::values.mouse_buttons; - - for (std::size_t index = 0; index < mouse.size(); ++index) { - mouse[index] = mouse_button_params[index].Serialize(); - } } void EmulatedDevices::RestoreConfig() { @@ -131,21 +159,6 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } -Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const { - if (index >= mouse_button_params.size()) { - return {}; - } - return mouse_button_params[index]; -} - -void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) { - if (index >= mouse_button_params.size()) { - return; - } - mouse_button_params[index] = param; - ReloadInput(); -} - void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { return; @@ -334,6 +347,51 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std TriggerOnChange(DeviceTriggerType::Mouse); } +void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { + if (index >= device_status.mouse_analog_values.size()) { + return; + } + std::lock_guard lock{mutex}; + const auto analog_value = TransformToAnalog(callback); + + device_status.mouse_analog_values[index] = analog_value; + + if (is_configuring) { + device_status.mouse_position_state = {}; + TriggerOnChange(DeviceTriggerType::Mouse); + return; + } + + switch (index) { + case Settings::NativeMouseWheel::X: + device_status.mouse_wheel_state.x = static_cast(analog_value.value); + break; + case Settings::NativeMouseWheel::Y: + device_status.mouse_wheel_state.y = static_cast(analog_value.value); + break; + } + + TriggerOnChange(DeviceTriggerType::Mouse); +} + +void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { + std::lock_guard lock{mutex}; + const auto stick_value = TransformToStick(callback); + + device_status.mouse_stick_value = stick_value; + + if (is_configuring) { + device_status.mouse_position_state = {}; + TriggerOnChange(DeviceTriggerType::Mouse); + return; + } + + device_status.mouse_position_state.x = stick_value.x.value; + device_status.mouse_position_state.y = stick_value.y.value; + + TriggerOnChange(DeviceTriggerType::Mouse); +} + KeyboardValues EmulatedDevices::GetKeyboardValues() const { return device_status.keyboard_values; } @@ -362,6 +420,10 @@ MousePosition EmulatedDevices::GetMousePosition() const { return device_status.mouse_position_state; } +AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const { + return device_status.mouse_wheel_state; +} + void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { for (const auto& poller_pair : callback_list) { const InterfaceUpdateCallback& poller = poller_pair.second; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index d49d6d78a..49edfd255 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -17,13 +17,15 @@ #include "core/hid/hid_types.h" namespace Core::HID { - using KeyboardDevices = std::array, Settings::NativeKeyboard::NumKeyboardKeys>; using KeyboardModifierDevices = std::array, Settings::NativeKeyboard::NumKeyboardMods>; using MouseButtonDevices = std::array, Settings::NativeMouseButton::NumMouseButtons>; +using MouseAnalogDevices = std::array, + Settings::NativeMouseWheel::NumMouseWheels>; +using MouseStickDevice = std::unique_ptr; using MouseButtonParams = std::array; @@ -34,12 +36,13 @@ using KeyboardModifierValues = std::array; using MouseButtonValues = std::array; +using MouseAnalogValues = + std::array; +using MouseStickValue = Common::Input::StickStatus; struct MousePosition { - s32 x; - s32 y; - s32 delta_wheel_x; - s32 delta_wheel_y; + f32 x; + f32 y; }; struct DeviceStatus { @@ -47,12 +50,15 @@ struct DeviceStatus { KeyboardValues keyboard_values{}; KeyboardModifierValues keyboard_moddifier_values{}; MouseButtonValues mouse_button_values{}; + MouseAnalogValues mouse_analog_values{}; + MouseStickValue mouse_stick_value{}; // Data for HID serices KeyboardKey keyboard_state{}; KeyboardModifier keyboard_moddifier_state{}; MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; + AnalogStickState mouse_wheel_state{}; }; enum class DeviceTriggerType { @@ -102,15 +108,6 @@ public: /// Reverts any mapped changes made that weren't saved void RestoreConfig(); - /// Returns the current mapped mouse button device - Common::ParamPackage GetMouseButtonParam(std::size_t index) const; - - /** - * Updates the current mapped mouse button device - * @param ParamPackage with controller data to be mapped - */ - void SetMouseButtonParam(std::size_t index, Common::ParamPackage param); - /// Returns the latest status of button input from the keyboard with parameters KeyboardValues GetKeyboardValues() const; @@ -132,9 +129,12 @@ public: /// Returns the latest mouse coordinates MousePosition GetMousePosition() const; + /// Returns the latest mouse wheel change + AnalogStickState GetMouseDeltaWheel() const; + /** * Adds a callback to the list of events - * @param ConsoleUpdateCallback that will be triggered + * @param InterfaceUpdateCallback that will be triggered * @return an unique key corresponding to the callback index in the list */ int SetCallback(InterfaceUpdateCallback update_callback); @@ -150,26 +150,40 @@ private: void UpdateKey(std::size_t key_index, bool status); /** - * Updates the touch status of the console + * Updates the touch status of the keyboard device * @param callback: A CallbackStatus containing the key status * @param index: key ID to be updated */ void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); /** - * Updates the touch status of the console + * Updates the keyboard status of the keyboard device * @param callback: A CallbackStatus containing the modifier key status * @param index: modifier key ID to be updated */ void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); /** - * Updates the touch status of the console + * Updates the mouse button status of the mouse device * @param callback: A CallbackStatus containing the button status - * @param index: Button ID of the to be updated + * @param index: Button ID to be updated */ void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); + /** + * Updates the mouse wheel status of the mouse device + * @param callback: A CallbackStatus containing the wheel status + * @param index: wheel ID to be updated + */ + void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the mouse position status of the mouse device + * @param callback: A CallbackStatus containing the position status + * @param index: stick ID to be updated + */ + void SetMouseStick(Common::Input::CallbackStatus callback); + /** * Triggers a callback that something has changed on the device status * @param Input type of the event to trigger @@ -178,11 +192,11 @@ private: bool is_configuring{false}; - MouseButtonParams mouse_button_params; - KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; + MouseAnalogDevices mouse_analog_devices; + MouseStickDevice mouse_stick_device; mutable std::mutex mutex; std::unordered_map callback_list; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 480b862fd..c4e653956 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -242,6 +242,27 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta return status; } +Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) { + Common::Input::AnalogStatus status{}; + + switch (callback.type) { + case Common::Input::InputType::Analog: + status.properties = callback.analog_status.properties; + status.raw_value = callback.analog_status.raw_value; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type); + break; + } + + SanitizeAnalog(status, false); + + // Adjust if value is inverted + status.value = status.properties.inverted ? -status.value : status.value; + + return status; +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 2a722b39f..1492489d7 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -68,6 +68,15 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& */ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); +/** + * Converts raw input data into a valid analog status. Applies offset, deadzone, range and + * invert properties to the output. + * + * @param Supported callbacks: Analog. + * @return A valid AnalogStatus object. + */ +Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); + /** * Converts raw analog data into a valid analog value * @param An analog object containing raw data and properties, bool that determines if the value diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 83e69ca94..9c408e7f4 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -38,13 +38,14 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (Settings::values.mouse_enabled) { const auto& mouse_button_state = emulated_devices->GetMouseButtons(); const auto& mouse_position_state = emulated_devices->GetMousePosition(); + const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel(); next_state.attribute.is_connected.Assign(1); - next_state.x = mouse_position_state.x; - next_state.y = mouse_position_state.y; + next_state.x = static_cast(mouse_position_state.x * Layout::ScreenUndocked::Width); + next_state.y = static_cast(mouse_position_state.y * Layout::ScreenUndocked::Height); next_state.delta_x = next_state.x - last_entry.x; next_state.delta_y = next_state.y - last_entry.y; - next_state.delta_wheel_x = mouse_position_state.delta_wheel_x; - next_state.delta_wheel_y = mouse_position_state.delta_wheel_y; + next_state.delta_wheel_x = mouse_wheel_state.x; + next_state.delta_wheel_y = mouse_wheel_state.y; next_state.button = mouse_button_state; } diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index afa92b458..478737db2 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -12,6 +12,10 @@ #include "input_common/drivers/mouse.h" namespace InputCommon { +constexpr int mouse_axis_x = 0; +constexpr int mouse_axis_y = 1; +constexpr int wheel_axis_x = 2; +constexpr int wheel_axis_y = 3; constexpr int touch_axis_x = 10; constexpr int touch_axis_y = 11; constexpr PadIdentifier identifier = { @@ -22,6 +26,12 @@ constexpr PadIdentifier identifier = { Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); + PreSetAxis(identifier, mouse_axis_x); + PreSetAxis(identifier, mouse_axis_y); + PreSetAxis(identifier, wheel_axis_x); + PreSetAxis(identifier, wheel_axis_y); + PreSetAxis(identifier, touch_axis_x); + PreSetAxis(identifier, touch_axis_x); update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); } @@ -34,14 +44,18 @@ void Mouse::UpdateThread(std::stop_token stop_token) { last_mouse_change *= 0.96f; const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; - SetAxis(identifier, 0, last_mouse_change.x * sensitivity); - SetAxis(identifier, 1, -last_mouse_change.y * sensitivity); + SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); + SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); } if (mouse_panning_timout++ > 20) { StopPanning(); } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); + + // Reset wheel position + SetAxis(identifier, wheel_axis_x, 0); + SetAxis(identifier, wheel_axis_y, 0); } } @@ -89,8 +103,8 @@ void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int if (button_pressed) { const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; - SetAxis(identifier, 0, static_cast(mouse_move.x) * sensitivity); - SetAxis(identifier, 1, static_cast(-mouse_move.y) * sensitivity); + SetAxis(identifier, mouse_axis_x, static_cast(mouse_move.x) * sensitivity); + SetAxis(identifier, mouse_axis_y, static_cast(-mouse_move.y) * sensitivity); } } @@ -108,12 +122,17 @@ void Mouse::ReleaseButton(MouseButton button) { SetButton(identifier, static_cast(button), false); if (!Settings::values.mouse_panning) { - SetAxis(identifier, 0, 0); - SetAxis(identifier, 1, 0); + SetAxis(identifier, mouse_axis_x, 0); + SetAxis(identifier, mouse_axis_y, 0); } button_pressed = false; } +void Mouse::MouseWheelChange(int x, int y) { + SetAxis(identifier, wheel_axis_x, static_cast(x)); + SetAxis(identifier, wheel_axis_y, static_cast(y)); +} + void Mouse::ReleaseAllButtons() { ResetButtonState(); button_pressed = false; diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 1be362b94..429502af9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -52,6 +52,13 @@ public: */ void ReleaseButton(MouseButton button); + /** + * Sets the status of the mouse wheel + * @param x delta movement in the x direction + * @param y delta movement in the y direction + */ + void MouseWheelChange(int x, int y); + void ReleaseAllButtons(); std::vector GetInputDevices() const override; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index d62fd566f..a44815e71 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -90,9 +90,6 @@ add_executable(yuzu configuration/configure_motion_touch.cpp configuration/configure_motion_touch.h configuration/configure_motion_touch.ui - configuration/configure_mouse_advanced.cpp - configuration/configure_mouse_advanced.h - configuration/configure_mouse_advanced.ui configuration/configure_per_game.cpp configuration/configure_per_game.h configuration/configure_per_game.ui diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 9f4d1aac3..1015e51b5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -746,6 +746,12 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { input_subsystem->GetMouse()->ReleaseButton(button); } +void GRenderWindow::wheelEvent(QWheelEvent* event) { + const int x = event->delta(); + const int y = 0; + input_subsystem->GetMouse()->MouseWheelChange(x, y); +} + void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { QList touch_points = event->touchPoints(); for (const auto& touch_point : touch_points) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index c42d139be..d6b2ab5f3 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -173,6 +173,7 @@ public: void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; bool event(QEvent* event) override; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 5865359fe..ae1684dd4 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -60,11 +60,6 @@ const std::array Config::default_stick_mod = { 0, }; -const std::array Config::default_mouse_buttons = - { - Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, -}; - // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as @@ -348,22 +343,6 @@ void Config::ReadKeyboardValues() { void Config::ReadMouseValues() { ReadBasicSetting(Settings::values.mouse_enabled); - - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const std::string default_param = - InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - auto& mouse_buttons = Settings::values.mouse_buttons[i]; - - mouse_buttons = qt_config - ->value(QStringLiteral("mouse_") + - QString::fromUtf8(Settings::NativeMouseButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (mouse_buttons.empty()) { - mouse_buttons = default_param; - } - } } void Config::ReadTouchscreenValues() { @@ -947,15 +926,6 @@ void Config::SaveDebugValues() { void Config::SaveMouseValues() { WriteBasicSetting(Settings::values.mouse_enabled); - - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const std::string default_param = - InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - WriteSetting(QStringLiteral("mouse_") + - QString::fromStdString(Settings::NativeMouseButton::mapping[i]), - QString::fromStdString(Settings::values.mouse_buttons[i]), - QString::fromStdString(default_param)); - } } void Config::SaveTouchscreenValues() { diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 99450bc7d..d53179dbb 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -24,7 +24,6 @@ #include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_motion_touch.h" -#include "yuzu/configuration/configure_mouse_advanced.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" @@ -157,9 +156,6 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, CallConfigureDialog( *this, input_subsystem, profiles.get(), hid_core, is_powered_on); }); - connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { - CallConfigureDialog(*this, input_subsystem); - }); connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, [this] { CallConfigureDialog(*this); }); connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog, diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index b30f09013..cf8aad4ab 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -82,7 +82,6 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) connect(ui->debug_configure, &QPushButton::clicked, this, [this] { CallDebugControllerDialog(); }); - connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); }); connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); connect(ui->buttonMotionTouch, &QPushButton::clicked, this, @@ -178,7 +177,6 @@ void ConfigureInputAdvanced::RetranslateUI() { } void ConfigureInputAdvanced::UpdateUIEnabled() { - ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked()); ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 9095206a0..75487a5d0 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2528,11 +2528,11 @@ 0 - + - Other + Emulated Devices - + @@ -2547,7 +2547,7 @@ - + 0 @@ -2555,53 +2555,18 @@ - Emulate Analog with Keyboard Input + Mouse - - - - 0 - 23 - - + - Enable mouse panning + Touchscreen - - - - Mouse sensitivity - - - Qt::AlignCenter - - - % - - - 1 - - - 100 - - - 100 - - - - - - - Advanced - - - - + Qt::Horizontal @@ -2617,80 +2582,117 @@ - - - - Advanced - - - - - - - Touchscreen - - - + + + + Advanced + + + - - - - 0 - 23 - - - - Mouse - - - - - - - Motion / Touch - - - - - - - Configure - - - - Debug Controller - + Configure - - - - Requires restarting yuzu - - - - 0 - 23 - - - - Enable XInput 8 player support (disables web applet) - - - + + + + Other + + + + + + + 0 + 23 + + + + Emulate Analog with Keyboard Input + + + + + + + Requires restarting yuzu + + + + 0 + 23 + + + + Enable XInput 8 player support (disables web applet) + + + + + + + + 0 + 23 + + + + Enable mouse panning + + + + + + + Mouse sensitivity + + + Qt::AlignCenter + + + % + + + 1 + + + 100 + + + 100 + + + + + + + Motion / Touch + + + + + + + Configure + + + + + + diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp deleted file mode 100644 index 1e7a3751d..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include -#include -#include - -#include "common/assert.h" -#include "common/param_package.h" -#include "input_common/drivers/keyboard.h" -#include "input_common/drivers/mouse.h" -#include "input_common/main.h" -#include "ui_configure_mouse_advanced.h" -#include "yuzu/bootmanager.h" -#include "yuzu/configuration/config.h" -#include "yuzu/configuration/configure_mouse_advanced.h" - -static QString GetKeyName(int key_code) { - switch (key_code) { - case Qt::LeftButton: - return QObject::tr("Click 0"); - case Qt::RightButton: - return QObject::tr("Click 1"); - case Qt::MiddleButton: - return QObject::tr("Click 2"); - case Qt::BackButton: - return QObject::tr("Click 3"); - case Qt::ForwardButton: - return QObject::tr("Click 4"); - case Qt::Key_Shift: - return QObject::tr("Shift"); - case Qt::Key_Control: - return QObject::tr("Ctrl"); - case Qt::Key_Alt: - return QObject::tr("Alt"); - case Qt::Key_Meta: - return {}; - default: - return QKeySequence(key_code).toString(); - } -} - -static QString ButtonToText(const Common::ParamPackage& param) { - if (!param.Has("engine")) { - return QObject::tr("[not set]"); - } - - if (param.Get("engine", "") == "keyboard") { - return GetKeyName(param.Get("code", 0)); - } - - if (param.Get("engine", "") == "sdl") { - if (param.Has("hat")) { - const QString hat_str = QString::fromStdString(param.Get("hat", "")); - const QString direction_str = QString::fromStdString(param.Get("direction", "")); - - return QObject::tr("Hat %1 %2").arg(hat_str, direction_str); - } - - if (param.Has("axis")) { - const QString axis_str = QString::fromStdString(param.Get("axis", "")); - const QString direction_str = QString::fromStdString(param.Get("direction", "")); - - return QObject::tr("Axis %1%2").arg(axis_str, direction_str); - } - - if (param.Has("button")) { - const QString button_str = QString::fromStdString(param.Get("button", "")); - - return QObject::tr("Button %1").arg(button_str); - } - return {}; - } - - return QObject::tr("[unknown]"); -} - -ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, - InputCommon::InputSubsystem* input_subsystem_) - : QDialog(parent), - ui(std::make_unique()), input_subsystem{input_subsystem_}, - timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { - ui->setupUi(this); - setFocusPolicy(Qt::ClickFocus); - - button_map = { - ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button, - }; - - for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) { - auto* const button = button_map[button_id]; - if (button == nullptr) { - continue; - } - - button->setContextMenuPolicy(Qt::CustomContextMenu); - connect(button, &QPushButton::clicked, [=, this] { - HandleClick( - button_map[button_id], - [=, this](const Common::ParamPackage& params) { - buttons_param[button_id] = params; - }, - InputCommon::Polling::InputType::Button); - }); - connect(button, &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - buttons_param[button_id].Clear(); - button_map[button_id]->setText(tr("[not set]")); - }); - context_menu.addAction(tr("Restore Default"), [&] { - buttons_param[button_id] = - Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_mouse_buttons[button_id])}; - button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); - }); - context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); - }); - } - - connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); - connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); - - timeout_timer->setSingleShot(true); - connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); - - connect(poll_timer.get(), &QTimer::timeout, [this] { - const auto& params = input_subsystem->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; - } - }); - - LoadConfiguration(); - resize(0, 0); -} - -ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default; - -void ConfigureMouseAdvanced::ApplyConfiguration() { - std::transform(buttons_param.begin(), buttons_param.end(), - Settings::values.mouse_buttons.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); -} - -void ConfigureMouseAdvanced::LoadConfiguration() { - std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), - buttons_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::changeEvent(QEvent* event) { - if (event->type() == QEvent::LanguageChange) { - RetranslateUI(); - } - - QDialog::changeEvent(event); -} - -void ConfigureMouseAdvanced::RetranslateUI() { - ui->retranslateUi(this); -} - -void ConfigureMouseAdvanced::RestoreDefaults() { - for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])}; - } - - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::ClearAll() { - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const auto* const button = button_map[i]; - if (button != nullptr && button->isEnabled()) { - buttons_param[i].Clear(); - } - } - - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::UpdateButtonLabels() { - for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) { - button_map[button]->setText(ButtonToText(buttons_param[button])); - } -} - -void ConfigureMouseAdvanced::HandleClick( - QPushButton* button, std::function new_input_setter, - InputCommon::Polling::InputType type) { - button->setText(tr("[press key]")); - button->setFocus(); - - input_setter = new_input_setter; - - input_subsystem->BeginMapping(type); - - QWidget::grabMouse(); - QWidget::grabKeyboard(); - - timeout_timer->start(2500); // Cancel after 2.5 seconds - poll_timer->start(50); // Check for new inputs every 50ms -} - -void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { - timeout_timer->stop(); - poll_timer->stop(); - input_subsystem->StopMapping(); - - QWidget::releaseMouse(); - QWidget::releaseKeyboard(); - - if (!abort) { - (*input_setter)(params); - } - - UpdateButtonLabels(); - input_setter = std::nullopt; -} - -void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) { - if (!input_setter || !event) { - return; - } - - const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); -} - -void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { - if (!input_setter || !event) { - return; - } - - if (event->key() != Qt::Key_Escape) { - input_subsystem->GetKeyboard()->PressKey(event->key()); - } -} diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h deleted file mode 100644 index 5fa534eaf..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -class QCheckBox; -class QPushButton; -class QTimer; - -namespace InputCommon { -class InputSubsystem; -} - -namespace Ui { -class ConfigureMouseAdvanced; -} - -class ConfigureMouseAdvanced : public QDialog { - Q_OBJECT - -public: - explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); - ~ConfigureMouseAdvanced() override; - - void ApplyConfiguration(); - -private: - void changeEvent(QEvent* event) override; - void RetranslateUI(); - - /// Load configuration settings. - void LoadConfiguration(); - /// Restore all buttons to their default values. - void RestoreDefaults(); - /// Clear all input configuration - void ClearAll(); - - /// Update UI to reflect current configuration. - void UpdateButtonLabels(); - - /// Called when the button was pressed. - void HandleClick(QPushButton* button, - std::function new_input_setter, - InputCommon::Polling::InputType type); - - /// Finish polling and configure input using the input_setter - void SetPollingResult(const Common::ParamPackage& params, bool abort); - - /// Handle mouse button press events. - void mousePressEvent(QMouseEvent* event) override; - - /// Handle key press events. - void keyPressEvent(QKeyEvent* event) override; - - std::unique_ptr ui; - - InputCommon::InputSubsystem* input_subsystem; - - /// This will be the the setting function when an input is awaiting configuration. - std::optional> input_setter; - - std::array button_map; - std::array buttons_param; - - std::unique_ptr timeout_timer; - std::unique_ptr poll_timer; -}; diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui deleted file mode 100644 index 5b99e1c37..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.ui +++ /dev/null @@ -1,335 +0,0 @@ - - - ConfigureMouseAdvanced - - - - 0 - 0 - 310 - 193 - - - - Configure Mouse - - - QPushButton { - min-width: 60px; -} - - - - - - Mouse Buttons - - - - - - - - - - Forward: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - - - - - - 54 - 0 - - - - Back: - - - - - - - - - - 68 - 0 - - - - - - - - - - - - - - - - - Left: - - - - - - - - - - 68 - 0 - - - - - - - - - - - - - - - - - Middle: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - - - - - Right: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - Clear - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - Defaults - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - ConfigureMouseAdvanced - accept() - - - buttonBox - rejected() - ConfigureMouseAdvanced - reject() - - - diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 7ca09a635..8e9c7d211 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -83,163 +83,6 @@ static const std::array, Settings::NativeAnalog::NumAnalogs> }, }}; -static const std::array default_mouse_buttons = { - SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_APOSTROPHE, - SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, -}; - -static const std::array keyboard_keys = { - 0, - 0, - 0, - 0, - SDL_SCANCODE_A, - SDL_SCANCODE_B, - SDL_SCANCODE_C, - SDL_SCANCODE_D, - SDL_SCANCODE_E, - SDL_SCANCODE_F, - SDL_SCANCODE_G, - SDL_SCANCODE_H, - SDL_SCANCODE_I, - SDL_SCANCODE_J, - SDL_SCANCODE_K, - SDL_SCANCODE_L, - SDL_SCANCODE_M, - SDL_SCANCODE_N, - SDL_SCANCODE_O, - SDL_SCANCODE_P, - SDL_SCANCODE_Q, - SDL_SCANCODE_R, - SDL_SCANCODE_S, - SDL_SCANCODE_T, - SDL_SCANCODE_U, - SDL_SCANCODE_V, - SDL_SCANCODE_W, - SDL_SCANCODE_X, - SDL_SCANCODE_Y, - SDL_SCANCODE_Z, - SDL_SCANCODE_1, - SDL_SCANCODE_2, - SDL_SCANCODE_3, - SDL_SCANCODE_4, - SDL_SCANCODE_5, - SDL_SCANCODE_6, - SDL_SCANCODE_7, - SDL_SCANCODE_8, - SDL_SCANCODE_9, - SDL_SCANCODE_0, - SDL_SCANCODE_RETURN, - SDL_SCANCODE_ESCAPE, - SDL_SCANCODE_BACKSPACE, - SDL_SCANCODE_TAB, - SDL_SCANCODE_SPACE, - SDL_SCANCODE_MINUS, - SDL_SCANCODE_EQUALS, - SDL_SCANCODE_LEFTBRACKET, - SDL_SCANCODE_RIGHTBRACKET, - SDL_SCANCODE_BACKSLASH, - 0, - SDL_SCANCODE_SEMICOLON, - SDL_SCANCODE_APOSTROPHE, - SDL_SCANCODE_GRAVE, - SDL_SCANCODE_COMMA, - SDL_SCANCODE_PERIOD, - SDL_SCANCODE_SLASH, - SDL_SCANCODE_CAPSLOCK, - - SDL_SCANCODE_F1, - SDL_SCANCODE_F2, - SDL_SCANCODE_F3, - SDL_SCANCODE_F4, - SDL_SCANCODE_F5, - SDL_SCANCODE_F6, - SDL_SCANCODE_F7, - SDL_SCANCODE_F8, - SDL_SCANCODE_F9, - SDL_SCANCODE_F10, - SDL_SCANCODE_F11, - SDL_SCANCODE_F12, - - 0, - SDL_SCANCODE_SCROLLLOCK, - SDL_SCANCODE_PAUSE, - SDL_SCANCODE_INSERT, - SDL_SCANCODE_HOME, - SDL_SCANCODE_PAGEUP, - SDL_SCANCODE_DELETE, - SDL_SCANCODE_END, - SDL_SCANCODE_PAGEDOWN, - SDL_SCANCODE_RIGHT, - SDL_SCANCODE_LEFT, - SDL_SCANCODE_DOWN, - SDL_SCANCODE_UP, - - SDL_SCANCODE_NUMLOCKCLEAR, - SDL_SCANCODE_KP_DIVIDE, - SDL_SCANCODE_KP_MULTIPLY, - SDL_SCANCODE_KP_MINUS, - SDL_SCANCODE_KP_PLUS, - SDL_SCANCODE_KP_ENTER, - SDL_SCANCODE_KP_1, - SDL_SCANCODE_KP_2, - SDL_SCANCODE_KP_3, - SDL_SCANCODE_KP_4, - SDL_SCANCODE_KP_5, - SDL_SCANCODE_KP_6, - SDL_SCANCODE_KP_7, - SDL_SCANCODE_KP_8, - SDL_SCANCODE_KP_9, - SDL_SCANCODE_KP_0, - SDL_SCANCODE_KP_PERIOD, - - 0, - 0, - SDL_SCANCODE_POWER, - SDL_SCANCODE_KP_EQUALS, - - SDL_SCANCODE_F13, - SDL_SCANCODE_F14, - SDL_SCANCODE_F15, - SDL_SCANCODE_F16, - SDL_SCANCODE_F17, - SDL_SCANCODE_F18, - SDL_SCANCODE_F19, - SDL_SCANCODE_F20, - SDL_SCANCODE_F21, - SDL_SCANCODE_F22, - SDL_SCANCODE_F23, - SDL_SCANCODE_F24, - - 0, - SDL_SCANCODE_HELP, - SDL_SCANCODE_MENU, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - SDL_SCANCODE_KP_COMMA, - SDL_SCANCODE_KP_LEFTPAREN, - SDL_SCANCODE_KP_RIGHTPAREN, - 0, - 0, - 0, - 0, -}; - -static const std::array keyboard_mods{ - SDL_SCANCODE_LCTRL, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI, - SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, -}; - template <> void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); @@ -283,14 +126,6 @@ void Config::ReadValues() { } ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - Settings::values.mouse_buttons[i] = sdl2_config->Get( - "ControlsGeneral", std::string("mouse_") + Settings::NativeMouseButton::mapping[i], - default_param); - if (Settings::values.mouse_buttons[i].empty()) - Settings::values.mouse_buttons[i] = default_param; - } ReadSetting("ControlsGeneral", Settings::values.touch_device); @@ -365,15 +200,6 @@ void Config::ReadValues() { ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); - std::transform(keyboard_keys.begin(), keyboard_keys.end(), - Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); - std::transform(keyboard_mods.begin(), keyboard_mods.end(), - Settings::values.keyboard_keys.begin() + - Settings::NativeKeyboard::LeftControlKey, - InputCommon::GenerateKeyboardParam); - std::transform(keyboard_mods.begin(), keyboard_mods.end(), - Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); - // Data Storage ReadSetting("Data Storage", Settings::values.use_virtual_sd); FS::SetYuzuPath(FS::YuzuPath::NANDDir, From f4e5f89e6fb9d68cd4ba7d98c281584c50f0e149 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 21:28:38 -0600 Subject: [PATCH 126/291] core/hid: Improve accuary of mouse implementation --- src/core/hid/emulated_devices.cpp | 10 +++--- src/core/hid/emulated_devices.h | 4 +-- src/core/hid/hid_types.h | 35 ++++++++++++------- src/core/hid/input_converter.cpp | 4 +++ .../hle/service/hid/controllers/keyboard.cpp | 3 +- .../hle/service/hid/controllers/keyboard.h | 1 + .../hle/service/hid/controllers/mouse.cpp | 7 ++-- src/core/hle/service/hid/controllers/mouse.h | 2 ++ src/core/hle/service/hid/hid.cpp | 29 +++++++++------ src/core/hle/service/hid/hid.h | 4 +-- src/input_common/drivers/mouse.cpp | 21 ++++++----- src/input_common/drivers/mouse.h | 1 + src/yuzu/bootmanager.cpp | 4 +-- .../configure_input_advanced.cpp | 2 ++ 14 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 70a494097..874780ec2 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -376,9 +376,9 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { std::lock_guard lock{mutex}; - const auto stick_value = TransformToStick(callback); + const auto touch_value = TransformToTouch(callback); - device_status.mouse_stick_value = stick_value; + device_status.mouse_stick_value = touch_value; if (is_configuring) { device_status.mouse_position_state = {}; @@ -386,8 +386,8 @@ void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { return; } - device_status.mouse_position_state.x = stick_value.x.value; - device_status.mouse_position_state.y = stick_value.y.value; + device_status.mouse_position_state.x = touch_value.x.value; + device_status.mouse_position_state.y = touch_value.y.value; TriggerOnChange(DeviceTriggerType::Mouse); } @@ -420,7 +420,7 @@ MousePosition EmulatedDevices::GetMousePosition() const { return device_status.mouse_position_state; } -AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const { +AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 49edfd255..05a945d08 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -38,7 +38,7 @@ using MouseButtonValues = std::array; using MouseAnalogValues = std::array; -using MouseStickValue = Common::Input::StickStatus; +using MouseStickValue = Common::Input::TouchStatus; struct MousePosition { f32 x; @@ -130,7 +130,7 @@ public: MousePosition GetMousePosition() const; /// Returns the latest mouse wheel change - AnalogStickState GetMouseDeltaWheel() const; + AnalogStickState GetMouseWheel() const; /** * Adds a callback to the list of events diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index af95f3aff..8b12f63ad 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -502,21 +502,30 @@ static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incor // This is nn::hid::KeyboardModifier struct KeyboardModifier { union { - u64 raw{}; - BitField<0, 1, u64> control; - BitField<1, 1, u64> shift; - BitField<2, 1, u64> left_alt; - BitField<3, 1, u64> right_alt; - BitField<4, 1, u64> gui; - BitField<8, 1, u64> caps_lock; - BitField<9, 1, u64> scroll_lock; - BitField<10, 1, u64> num_lock; - BitField<11, 1, u64> katakana; - BitField<12, 1, u64> hiragana; - BitField<32, 1, u64> unknown; + u32 raw{}; + BitField<0, 1, u32> control; + BitField<1, 1, u32> shift; + BitField<2, 1, u32> left_alt; + BitField<3, 1, u32> right_alt; + BitField<4, 1, u32> gui; + BitField<8, 1, u32> caps_lock; + BitField<9, 1, u32> scroll_lock; + BitField<10, 1, u32> num_lock; + BitField<11, 1, u32> katakana; + BitField<12, 1, u32> hiragana; }; }; -static_assert(sizeof(KeyboardModifier) == 0x8, "KeyboardModifier is an invalid size"); + +static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size"); + +// This is nn::hid::KeyboardAttribute +struct KeyboardAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> is_connected; + }; +}; +static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid size"); // This is nn::hid::KeyboardKey struct KeyboardKey { diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index c4e653956..f5acff6e0 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -175,6 +175,10 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& case Common::Input::InputType::Touch: status = callback.touch_status; break; + case Common::Input::InputType::Stick: + status.x = callback.stick_status.x; + status.y = callback.stick_status.y; + break; default: LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type); break; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 0ef8af0e6..9588a6910 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -42,8 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, next_state.key = keyboard_state; next_state.modifier = keyboard_modifier_state; - // This is always enabled on HW. Check what it actually does - next_state.modifier.unknown.Assign(1); + next_state.attribute.is_connected.Assign(1); } keyboard_lifo.WriteNextEntry(next_state); diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index ec5dd607c..0d61cb470 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -38,6 +38,7 @@ private: struct KeyboardState { s64 sampling_number; Core::HID::KeyboardModifier modifier; + Core::HID::KeyboardAttribute attribute; Core::HID::KeyboardKey key; }; static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 9c408e7f4..ba79888ae 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -38,15 +38,16 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (Settings::values.mouse_enabled) { const auto& mouse_button_state = emulated_devices->GetMouseButtons(); const auto& mouse_position_state = emulated_devices->GetMousePosition(); - const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel(); + const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); next_state.attribute.is_connected.Assign(1); next_state.x = static_cast(mouse_position_state.x * Layout::ScreenUndocked::Width); next_state.y = static_cast(mouse_position_state.y * Layout::ScreenUndocked::Height); next_state.delta_x = next_state.x - last_entry.x; next_state.delta_y = next_state.y - last_entry.y; - next_state.delta_wheel_x = mouse_wheel_state.x; - next_state.delta_wheel_y = mouse_wheel_state.y; + next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; + next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; + last_mouse_wheel_state = mouse_wheel_state; next_state.button = mouse_button_state; } diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 25017f117..1ac69aa6f 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -14,6 +14,7 @@ namespace Core::HID { class EmulatedDevices; struct MouseState; +struct AnalogStickState; } // namespace Core::HID namespace Service::HID { @@ -37,6 +38,7 @@ private: static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); Core::HID::MouseState next_state{}; + Core::HID::AnalogStickState last_mouse_wheel_state; Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e740b4331..95fc07325 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -35,9 +35,9 @@ 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 -constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) -constexpr auto keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) +constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) +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) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -79,11 +79,11 @@ IAppletResource::IAppletResource(Core::System& system_, const auto guard = LockService(); UpdateControllers(user_data, ns_late); }); - keyboard_update_event = Core::Timing::CreateEvent( - "HID::UpdatekeyboardCallback", + mouse_keyboard_update_event = Core::Timing::CreateEvent( + "HID::UpdateMouseKeyboardCallback", [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { const auto guard = LockService(); - UpdateKeyboard(user_data, ns_late); + UpdateMouseKeyboard(user_data, ns_late); }); motion_update_event = Core::Timing::CreateEvent( "HID::UpdateMotionCallback", @@ -93,7 +93,7 @@ IAppletResource::IAppletResource(Core::System& system_, }); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); - system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event); + system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); system.HIDCore().ReloadInputDevices(); @@ -109,7 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) { IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(pad_update_event, 0); - system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0); + system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -130,6 +130,10 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast(HidController::Keyboard)]) { continue; } + // Mouse has it's own update event + if (controller == controllers[static_cast(HidController::Mouse)]) { + continue; + } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } @@ -142,18 +146,21 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } -void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { +void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, + std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); + controllers[static_cast(HidController::Mouse)]->OnUpdate( + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); controllers[static_cast(HidController::Keyboard)]->OnUpdate( core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); // If ns_late is higher than the update rate ignore the delay - if (ns_late > keyboard_update_ns) { + if (ns_late > mouse_keyboard_update_ns) { ns_late = {}; } - core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event); + core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); } void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index bbad165f8..ab0084118 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -70,13 +70,13 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); - void UpdateKeyboard(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 pad_update_event; - std::shared_ptr keyboard_update_event; + std::shared_ptr mouse_keyboard_update_event; std::shared_ptr motion_update_event; std::array, static_cast(HidController::MaxControllers)> diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 478737db2..05fd7f9c0 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -39,7 +39,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) { Common::SetCurrentThreadName("yuzu:input:Mouse"); constexpr int update_time = 10; while (!stop_token.stop_requested()) { - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { // Slow movement by 4% last_mouse_change *= 0.96f; const float sensitivity = @@ -52,14 +52,17 @@ void Mouse::UpdateThread(std::stop_token stop_token) { StopPanning(); } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); - - // Reset wheel position - SetAxis(identifier, wheel_axis_x, 0); - SetAxis(identifier, wheel_axis_y, 0); } } void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) { + // If native mouse is enabled just set the screen coordinates + if (Settings::values.mouse_enabled) { + SetAxis(identifier, mouse_axis_x, touch_x); + SetAxis(identifier, mouse_axis_y, touch_y); + return; + } + SetAxis(identifier, touch_axis_x, touch_x); SetAxis(identifier, touch_axis_y, touch_y); @@ -121,7 +124,7 @@ void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton butt void Mouse::ReleaseButton(MouseButton button) { SetButton(identifier, static_cast(button), false); - if (!Settings::values.mouse_panning) { + if (!Settings::values.mouse_panning && !Settings::values.mouse_enabled) { SetAxis(identifier, mouse_axis_x, 0); SetAxis(identifier, mouse_axis_y, 0); } @@ -129,8 +132,10 @@ void Mouse::ReleaseButton(MouseButton button) { } void Mouse::MouseWheelChange(int x, int y) { - SetAxis(identifier, wheel_axis_x, static_cast(x)); - SetAxis(identifier, wheel_axis_y, static_cast(y)); + wheel_position.x += x; + wheel_position.y += y; + SetAxis(identifier, wheel_axis_x, static_cast(wheel_position.x)); + SetAxis(identifier, wheel_axis_y, static_cast(wheel_position.y)); } void Mouse::ReleaseAllButtons() { diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 429502af9..f7e6db0b5 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -72,6 +72,7 @@ private: Common::Vec2 mouse_origin; Common::Vec2 last_mouse_position; Common::Vec2 last_mouse_change; + Common::Vec2 wheel_position; bool button_pressed; int mouse_panning_timout{}; std::jthread update_thread; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1015e51b5..2313a4189 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -729,7 +729,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { const int center_y = height() / 2; input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { QCursor::setPos(mapToGlobal({center_x, center_y})); } @@ -1044,7 +1044,7 @@ void GRenderWindow::showEvent(QShowEvent* event) { bool GRenderWindow::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::HoverMove) { - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning || Settings::values.mouse_enabled) { auto* hover_event = static_cast(event); mouseMoveEvent(hover_event); return false; diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index cf8aad4ab..e6127f9e6 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -179,4 +179,6 @@ void ConfigureInputAdvanced::RetranslateUI() { void ConfigureInputAdvanced::UpdateUIEnabled() { ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); + ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); + ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); } From 42949738f2c01a4125a9a385c9100240181153ec Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 21:56:54 -0600 Subject: [PATCH 127/291] kraken: Address comments from review Fix compiler bug --- src/core/hid/hid_types.h | 3 +- src/core/hle/service/hid/controllers/npad.cpp | 2 +- src/core/hle/service/hid/ring_lifo.h | 7 +- src/input_common/drivers/gc_adapter.cpp | 16 +---- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/mouse.cpp | 2 +- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 2 +- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/drivers/tas_input.cpp | 2 +- src/input_common/drivers/tas_input.h | 2 +- src/input_common/drivers/touch_screen.cpp | 2 +- src/input_common/drivers/touch_screen.h | 2 +- src/input_common/input_engine.cpp | 4 +- src/input_common/input_engine.h | 2 +- src/yuzu/bootmanager.cpp | 66 +++++++++---------- src/yuzu/bootmanager.h | 2 +- 17 files changed, 54 insertions(+), 66 deletions(-) diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 8b12f63ad..3cbe16260 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -564,8 +564,9 @@ struct MouseState { s32 y; s32 delta_x; s32 delta_y; - s32 delta_wheel_x; + // Axis Order in HW is switched for the wheel s32 delta_wheel_y; + s32 delta_wheel_x; MouseButton button; MouseAttribute attribute; }; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index eaec79139..4b23230e1 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -345,7 +345,7 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | btn::StickRRight | btn::StickRDown; - pad_entry.npad_buttons.raw |= button_state.raw & right_button_mask; + pad_entry.npad_buttons.raw = button_state.raw & right_button_mask; pad_entry.r_stick = stick_state.right; } diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 6209ed0d1..f0e0bab7f 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -7,7 +7,6 @@ #include #include "common/common_types.h" -#include "common/swap.h" namespace Service::HID { constexpr std::size_t max_buffer_size = 17; @@ -21,7 +20,7 @@ struct AtomicStorage { template struct Lifo { s64 timestamp{}; - s64 total_buffer_count = max_buffer_size; + s64 total_buffer_count = static_cast(max_buffer_size); s64 buffer_tail{}; s64 buffer_count{}; std::array, max_buffer_size> entries{}; @@ -35,11 +34,11 @@ struct Lifo { } std::size_t GetPreviousEntryIndex() const { - return (buffer_tail + total_buffer_count - 1) % total_buffer_count; + return static_cast((buffer_tail + total_buffer_count - 1) % total_buffer_count); } std::size_t GetNextEntryIndex() const { - return (buffer_tail + 1) % total_buffer_count; + return static_cast((buffer_tail + 1) % total_buffer_count); } void WriteNextEntry(const State& new_state) { diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 2550f8cba..a1b9b6d98 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -69,7 +69,7 @@ private: libusb_device_handle* handle{}; }; -GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine_) { +GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { if (usb_adapter_handle) { return; } @@ -486,42 +486,30 @@ std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const switch (button) { case PadButton::ButtonLeft: return "left"; - break; case PadButton::ButtonRight: return "right"; - break; case PadButton::ButtonDown: return "down"; - break; case PadButton::ButtonUp: return "up"; - break; case PadButton::TriggerZ: return "Z"; - break; case PadButton::TriggerR: return "R"; - break; case PadButton::TriggerL: return "L"; - break; case PadButton::ButtonA: return "A"; - break; case PadButton::ButtonB: return "B"; - break; case PadButton::ButtonX: return "X"; - break; case PadButton::ButtonY: return "Y"; - break; case PadButton::ButtonStart: return "start"; - break; default: - return "Unkown GC"; + return "Unknown GC"; } } diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index fba90352e..3e4747040 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -24,7 +24,7 @@ class LibUSBDeviceHandle; class GCAdapter : public InputCommon::InputEngine { public: - explicit GCAdapter(const std::string input_engine_); + explicit GCAdapter(const std::string& input_engine_); ~GCAdapter(); Common::Input::VibrationError SetRumble( diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 05fd7f9c0..9a9a1987d 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { +Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); PreSetAxis(identifier, mouse_axis_x); PreSetAxis(identifier, mouse_axis_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index f7e6db0b5..11dd76e14 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -29,7 +29,7 @@ enum class MouseButton { */ class Mouse final : public InputCommon::InputEngine { public: - explicit Mouse(const std::string input_engine_); + explicit Mouse(const std::string& input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1e3741e0f..0b24f1858 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -929,7 +929,7 @@ std::string SDLDriver::GetHatButtonName(u8 direction_value) const { } } -u8 SDLDriver::GetHatButtonId(const std::string direction_name) const { +u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const { Uint8 direction; if (direction_name == "up") { direction = SDL_HAT_UP; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index b879df8ab..3faaca984 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -56,7 +56,7 @@ public: std::string GetUIName(const Common::ParamPackage& params) const override; std::string GetHatButtonName(u8 direction_value) const override; - u8 GetHatButtonId(const std::string direction_name) const override; + u8 GetHatButtonId(const std::string& direction_name) const override; Common::Input::VibrationError SetRumble( const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index bb9c236ea..0e01fb0d9 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -47,7 +47,7 @@ constexpr std::array, 20> text_to_tas_but {"KEY_ZR", TasButton::TRIGGER_ZR}, }; -Tas::Tas(const std::string input_engine_) : InputCommon::InputEngine(input_engine_) { +Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { PadIdentifier identifier{ .guid = Common::UUID{}, diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index bfb37a638..c95a130fc 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -83,7 +83,7 @@ enum class TasState { class Tas final : public InputCommon::InputEngine { public: - explicit Tas(const std::string input_engine_); + explicit Tas(const std::string& input_engine_); ~Tas(); /** diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 377c9ee2b..45b3086f6 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { +TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 0f4cd0e7a..25c11e8bf 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -14,7 +14,7 @@ namespace InputCommon { */ class TouchScreen final : public InputCommon::InputEngine { public: - explicit TouchScreen(const std::string input_engine_); + explicit TouchScreen(const std::string& input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 139d8d2e6..2b2105376 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -300,8 +300,8 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot if (!configuring || !mapping_callback.on_data) { return; } - if (std::abs(value.gyro_x) < 1.0f && std::abs(value.gyro_y) < 1.0f && - std::abs(value.gyro_z) < 1.0f) { + if (std::abs(value.gyro_x) < 0.6f && std::abs(value.gyro_y) < 0.6f && + std::abs(value.gyro_z) < 0.6f) { return; } mapping_callback.on_data(MappingData{ diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 5430c0cf8..c621686e5 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -166,7 +166,7 @@ public: }; /// Retrieves the index number of the given hat button direction - virtual u8 GetHatButtonId([[maybe_unused]] const std::string direction_name) const { + virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const { return 0; }; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 2313a4189..7390fc5bd 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -613,56 +613,56 @@ int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { } } -int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) { - int moddifier = 0; +int GRenderWindow::QtModifierToSwitchModifier(quint32 qt_modifiers) { + int modifier = 0; // The values are obtained through testing, Qt doesn't seem to provide a proper enum - if ((qt_moddifiers & 0x1) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftShift; + if ((qt_modifiers & 0x1) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftShift; } - if ((qt_moddifiers & 0x2) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftControl; + if ((qt_modifiers & 0x2) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftControl; } - if ((qt_moddifiers & 0x4) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftAlt; + if ((qt_modifiers & 0x4) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftAlt; } - if ((qt_moddifiers & 0x08) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftMeta; + if ((qt_modifiers & 0x08) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftMeta; } - if ((qt_moddifiers & 0x10) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightShift; + if ((qt_modifiers & 0x10) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightShift; } - if ((qt_moddifiers & 0x20) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightControl; + if ((qt_modifiers & 0x20) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightControl; } - if ((qt_moddifiers & 0x40) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightAlt; + if ((qt_modifiers & 0x40) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightAlt; } - if ((qt_moddifiers & 0x80) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightMeta; + if ((qt_modifiers & 0x80) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightMeta; } - if ((qt_moddifiers & 0x100) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::CapsLock; + if ((qt_modifiers & 0x100) != 0) { + modifier |= 1 << Settings::NativeKeyboard::CapsLock; } - if ((qt_moddifiers & 0x200) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::NumLock; + if ((qt_modifiers & 0x200) != 0) { + modifier |= 1 << Settings::NativeKeyboard::NumLock; } // Verify the last two keys - if ((qt_moddifiers & 0x400) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Katakana; + if ((qt_modifiers & 0x400) != 0) { + modifier |= 1 << Settings::NativeKeyboard::Katakana; } - if ((qt_moddifiers & 0x800) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Hiragana; + if ((qt_modifiers & 0x800) != 0) { + modifier |= 1 << Settings::NativeKeyboard::Hiragana; } - return moddifier; + return modifier; } void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto modifier = QtModifierToSwitchModifier(event->nativeModifiers()); // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key // buttons const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->PressKeyboardKey(key); // This is used for gamepads input_subsystem->GetKeyboard()->PressKey(event->key()); @@ -671,9 +671,9 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) { void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto modifier = QtModifierToSwitchModifier(event->nativeModifiers()); const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key); // This is used for gamepads input_subsystem->GetKeyboard()->ReleaseKey(event->key()); @@ -747,8 +747,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { } void GRenderWindow::wheelEvent(QWheelEvent* event) { - const int x = event->delta(); - const int y = 0; + const int x = event->angleDelta().x(); + const int y = event->angleDelta().y(); input_subsystem->GetMouse()->MouseWheelChange(x, y); } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index d6b2ab5f3..81e3c4eb0 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -162,7 +162,7 @@ public: static int QtKeyToSwitchKey(Qt::Key qt_keys); /// Converts a Qt modifier keys into NativeKeyboard modifier keys - static int QtModifierToSwitchModdifier(quint32 qt_moddifiers); + static int QtModifierToSwitchModifier(quint32 qt_modifiers); void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; From 922aa9410a78ef9d6fd5b5d4455375d512333239 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 19 Nov 2021 10:56:52 -0600 Subject: [PATCH 128/291] bootmanager: Use cross-platform keyboard input --- src/core/hid/hid_core.h | 2 +- src/yuzu/bootmanager.cpp | 93 ++++++++++++++++++++++++---------------- src/yuzu/bootmanager.h | 2 +- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 1fe2fd89b..609f40f3b 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -52,7 +52,7 @@ public: void UnloadInputDevices(); /// Number of emulated controllers - const std::size_t available_controllers{10}; + static constexpr std::size_t available_controllers{10}; private: std::unique_ptr player_1; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 7390fc5bd..5e19f8cb1 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -613,69 +613,88 @@ int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { } } -int GRenderWindow::QtModifierToSwitchModifier(quint32 qt_modifiers) { +int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) { int modifier = 0; - // The values are obtained through testing, Qt doesn't seem to provide a proper enum - if ((qt_modifiers & 0x1) != 0) { + + if ((qt_modifiers & Qt::KeyboardModifier::ShiftModifier) != 0) { modifier |= 1 << Settings::NativeKeyboard::LeftShift; } - if ((qt_modifiers & 0x2) != 0) { + if ((qt_modifiers & Qt::KeyboardModifier::ControlModifier) != 0) { modifier |= 1 << Settings::NativeKeyboard::LeftControl; } - if ((qt_modifiers & 0x4) != 0) { + if ((qt_modifiers & Qt::KeyboardModifier::AltModifier) != 0) { modifier |= 1 << Settings::NativeKeyboard::LeftAlt; } - if ((qt_modifiers & 0x08) != 0) { + if ((qt_modifiers & Qt::KeyboardModifier::MetaModifier) != 0) { modifier |= 1 << Settings::NativeKeyboard::LeftMeta; } - if ((qt_modifiers & 0x10) != 0) { - modifier |= 1 << Settings::NativeKeyboard::RightShift; - } - if ((qt_modifiers & 0x20) != 0) { - modifier |= 1 << Settings::NativeKeyboard::RightControl; - } - if ((qt_modifiers & 0x40) != 0) { - modifier |= 1 << Settings::NativeKeyboard::RightAlt; - } - if ((qt_modifiers & 0x80) != 0) { - modifier |= 1 << Settings::NativeKeyboard::RightMeta; - } - if ((qt_modifiers & 0x100) != 0) { - modifier |= 1 << Settings::NativeKeyboard::CapsLock; - } - if ((qt_modifiers & 0x200) != 0) { - modifier |= 1 << Settings::NativeKeyboard::NumLock; - } - // Verify the last two keys - if ((qt_modifiers & 0x400) != 0) { - modifier |= 1 << Settings::NativeKeyboard::Katakana; - } - if ((qt_modifiers & 0x800) != 0) { - modifier |= 1 << Settings::NativeKeyboard::Hiragana; - } + + // TODO: These keys can't be obtained with Qt::KeyboardModifier + + // if ((qt_modifiers & 0x10) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::RightShift; + // } + // if ((qt_modifiers & 0x20) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::RightControl; + // } + // if ((qt_modifiers & 0x40) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::RightAlt; + // } + // if ((qt_modifiers & 0x80) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::RightMeta; + // } + // if ((qt_modifiers & 0x100) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::CapsLock; + // } + // if ((qt_modifiers & 0x200) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::NumLock; + // } + // if ((qt_modifiers & ???) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::ScrollLock; + // } + // if ((qt_modifiers & ???) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::Katakana; + // } + // if ((qt_modifiers & ???) != 0) { + // modifier |= 1 << Settings::NativeKeyboard::Hiragana; + // } return modifier; } void GRenderWindow::keyPressEvent(QKeyEvent* event) { + /** + * This feature can be enhanced with the following functions, but they do not provide + * cross-platform behavior. + * + * event->nativeVirtualKey() can distinguish between keys on the numpad. + * event->nativeModifiers() can distinguish between left and right keys and numlock, + * capslock, scroll lock. + */ if (!event->isAutoRepeat()) { - const auto modifier = QtModifierToSwitchModifier(event->nativeModifiers()); - // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key - // buttons + const auto modifier = QtModifierToSwitchModifier(event->modifiers()); const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->PressKeyboardKey(key); - // This is used for gamepads + // This is used for gamepads that can have any key mapped input_subsystem->GetKeyboard()->PressKey(event->key()); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { + /** + * This feature can be enhanced with the following functions, but they do not provide + * cross-platform behavior. + * + * event->nativeVirtualKey() can distinguish between keys on the numpad. + * event->nativeModifiers() can distinguish between left and right buttons and numlock, + * capslock, scroll lock. + */ if (!event->isAutoRepeat()) { - const auto modifier = QtModifierToSwitchModifier(event->nativeModifiers()); + const auto modifier = QtModifierToSwitchModifier(event->modifiers()); const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key); - // This is used for gamepads + // This is used for gamepads that can have any key mapped input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 81e3c4eb0..c8a2c59b4 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -162,7 +162,7 @@ public: static int QtKeyToSwitchKey(Qt::Key qt_keys); /// Converts a Qt modifier keys into NativeKeyboard modifier keys - static int QtModifierToSwitchModifier(quint32 qt_modifiers); + static int QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers); void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; From c4760489a0386cdeaed68ecbed7f87532193743e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 21 Nov 2021 12:59:51 -0600 Subject: [PATCH 129/291] input_common: Fix SDL controller with inverted axis --- src/input_common/drivers/sdl_driver.cpp | 23 ----------------------- src/input_common/input_poller.cpp | 9 ++++++++- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 0b24f1858..d5af6c09b 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -220,24 +220,6 @@ public: return "Unknown"; } - bool IsYAxis(u8 index) { - if (!sdl_controller) { - return false; - } - - const auto& binding_left_y = - SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_LEFTY); - const auto& binding_right_y = - SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_RIGHTY); - if (index == binding_left_y.value.axis) { - return true; - } - if (index == binding_right_y.value.axis) { - return true; - } - return false; - } - private: std::string guid; int port; @@ -376,11 +358,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { case SDL_JOYAXISMOTION: { if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); - // Vertical axis is inverted on nintendo compared to SDL - if (joystick->IsYAxis(event.jaxis.axis)) { - SetAxis(identifier, event.jaxis.axis, -event.jaxis.value / 32767.0f); - break; - } SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f); } break; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 92cf690cd..7e4eafded 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -146,7 +146,8 @@ public: Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), - properties_y(properties_y_), input_engine(input_engine_) { + properties_y(properties_y_), + input_engine(input_engine_), invert_axis_y{input_engine_->GetEngineName() == "sdl"} { UpdateCallback engine_callback{[this]() { OnChange(); }}; const InputIdentifier x_input_identifier{ .identifier = identifier, @@ -181,6 +182,11 @@ public: .raw_value = input_engine->GetAxis(identifier, axis_y), .properties = properties_y, }; + // This is a workaround too keep compatibility with old yuzu versions. Vertical axis is + // inverted on SDL compared to Nintendo + if (invert_axis_y) { + status.y.raw_value = -status.y.raw_value; + } return status; } @@ -220,6 +226,7 @@ private: float last_axis_x_value; float last_axis_y_value; InputEngine* input_engine; + const bool invert_axis_y; }; class InputFromTouch final : public Common::Input::InputDevice { From 746c85b56011b87afb57e37b75953435389fc810 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 21 Nov 2021 14:12:01 -0600 Subject: [PATCH 130/291] input_common: Move button names to the frontend --- src/common/input.h | 22 +++++ src/input_common/drivers/gc_adapter.cpp | 36 ++++---- src/input_common/drivers/gc_adapter.h | 4 +- src/input_common/drivers/mouse.cpp | 9 +- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 15 ++-- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/input_engine.h | 5 +- src/input_common/input_mapping.cpp | 5 ++ src/input_common/main.cpp | 17 ++-- src/input_common/main.h | 9 +- .../configuration/configure_input_player.cpp | 86 ++++++++++++++++++- 12 files changed, 160 insertions(+), 52 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index d997853c6..cc0cbd9b8 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -175,6 +175,28 @@ struct LedStatus { bool led_4{}; }; +// List of buttons to be passed to Qt that can be translated +enum class ButtonNames { + Undefined, + Invalid, + // This will display the engine name instead of the button name + Engine, + // This will display the button by value instead of the button name + Value, + ButtonLeft, + ButtonRight, + ButtonDown, + ButtonUp, + TriggerZ, + TriggerR, + TriggerL, + ButtonA, + ButtonB, + ButtonX, + ButtonY, + ButtonStart, +}; + // Callback data consisting of an input type and the equivalent data status struct CallbackStatus { InputType type{InputType::None}; diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index a1b9b6d98..8b6574223 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -481,47 +481,47 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p return mapping; } -std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { PadButton button = static_cast(params.Get("button", 0)); switch (button) { case PadButton::ButtonLeft: - return "left"; + return Common::Input::ButtonNames::ButtonLeft; case PadButton::ButtonRight: - return "right"; + return Common::Input::ButtonNames::ButtonRight; case PadButton::ButtonDown: - return "down"; + return Common::Input::ButtonNames::ButtonDown; case PadButton::ButtonUp: - return "up"; + return Common::Input::ButtonNames::ButtonUp; case PadButton::TriggerZ: - return "Z"; + return Common::Input::ButtonNames::TriggerZ; case PadButton::TriggerR: - return "R"; + return Common::Input::ButtonNames::TriggerR; case PadButton::TriggerL: - return "L"; + return Common::Input::ButtonNames::TriggerL; case PadButton::ButtonA: - return "A"; + return Common::Input::ButtonNames::ButtonA; case PadButton::ButtonB: - return "B"; + return Common::Input::ButtonNames::ButtonB; case PadButton::ButtonX: - return "X"; + return Common::Input::ButtonNames::ButtonX; case PadButton::ButtonY: - return "Y"; + return Common::Input::ButtonNames::ButtonY; case PadButton::ButtonStart: - return "start"; + return Common::Input::ButtonNames::ButtonStart; default: - return "Unknown GC"; + return Common::Input::ButtonNames::Undefined; } } -std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames GCAdapter::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Button {}", GetUIButtonName(params)); + return GetUIButtonName(params); } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis", 0)); + return Common::Input::ButtonNames::Value; } - return "Bad GC Adapter"; + return Common::Input::ButtonNames::Invalid; } } // namespace InputCommon diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 3e4747040..8dc51d2e5 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -34,7 +34,7 @@ public: std::vector GetInputDevices() const override; ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; private: enum class PadButton { @@ -112,7 +112,7 @@ private: /// Updates vibration state of all controllers void SendVibrations(); - std::string GetUIButtonName(const Common::ParamPackage& params) const; + Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; std::unique_ptr usb_adapter_handle; std::array pads; diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 9a9a1987d..752118e97 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -171,12 +171,15 @@ AnalogMapping Mouse::GetAnalogMappingForDevice( return mapping; } -std::string Mouse::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Mouse {}", params.Get("button", 0)); + return Common::Input::ButtonNames::Value; + } + if (params.Has("axis")) { + return Common::Input::ButtonNames::Value; } - return "Bad Mouse"; + return Common::Input::ButtonNames::Invalid; } } // namespace InputCommon diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 11dd76e14..4a1fd2fd9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -63,7 +63,7 @@ public: std::vector GetInputDevices() const override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; private: void UpdateThread(std::stop_token stop_token); diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index d5af6c09b..90128b6cf 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -869,26 +869,25 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p return mapping; } -std::string SDLDriver::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { // TODO(German77): Find how to substitue the values for real button names - return fmt::format("Button {}", params.Get("button", 0)); + return Common::Input::ButtonNames::Value; } if (params.Has("hat")) { - return fmt::format("Hat {}", params.Get("direction", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { - return fmt::format("Axis {},{},{}", params.Get("axis_x", ""), params.Get("axis_y", ""), - params.Get("axis_z", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("motion")) { - return "SDL motion"; + return Common::Input::ButtonNames::Engine; } - return "Bad SDL"; + return Common::Input::ButtonNames::Invalid; } std::string SDLDriver::GetHatButtonName(u8 direction_value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index 3faaca984..d03ff4b84 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -53,7 +53,7 @@ public: ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string& direction_name) const override; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index c621686e5..02272b3f8 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -161,8 +161,9 @@ public: }; /// Retrieves the name of the given input. - virtual std::string GetUIName([[maybe_unused]] const Common::ParamPackage& params) const { - return GetEngineName(); + virtual Common::Input::ButtonNames GetUIName( + [[maybe_unused]] const Common::ParamPackage& params) const { + return Common::Input::ButtonNames::Engine; }; /// Retrieves the index number of the given hat button direction diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0eeeff372..c5218f2cb 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -61,6 +61,7 @@ void MappingFactory::RegisterButton(const MappingData& data) { } new_input.Set("port", static_cast(data.pad.port)); new_input.Set("pad", static_cast(data.pad.pad)); + switch (data.type) { case EngineInputType::Button: // Workaround for old compatibility @@ -75,6 +76,10 @@ void MappingFactory::RegisterButton(const MappingData& data) { new_input.Set("direction", data.hat_name); break; case EngineInputType::Analog: + // Ignore mouse axis when mapping buttons + if (data.engine == "mouse") { + return; + } new_input.Set("axis", data.index); new_input.Set("threshold", 0.5f); break; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index df36a337c..39e4935dc 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -205,9 +205,9 @@ struct InputSubsystem::Impl { return {}; } - std::string GetButtonName(const Common::ParamPackage& params) const { + Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { if (!params.Has("engine") || params.Get("engine", "") == "any") { - return "Unknown"; + return Common::Input::ButtonNames::Undefined; } const std::string engine = params.Get("engine", ""); if (engine == mouse->GetEngineName()) { @@ -227,7 +227,7 @@ struct InputSubsystem::Impl { return sdl->GetUIName(params); } #endif - return "Bad engine"; + return Common::Input::ButtonNames::Invalid; } bool IsController(const Common::ParamPackage& params) { @@ -361,15 +361,8 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka return impl->GetMotionMappingForDevice(device); } -std::string InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { - const std::string toggle = params.Get("toggle", false) ? "~" : ""; - const std::string inverted = params.Get("inverted", false) ? "!" : ""; - const std::string button_name = impl->GetButtonName(params); - std::string axis_direction = ""; - if (params.Has("axis")) { - axis_direction = params.Get("invert", "+"); - } - return fmt::format("{}{}{}{}", toggle, inverted, button_name, axis_direction); +Common::Input::ButtonNames InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { + return impl->GetButtonName(params); } bool InputSubsystem::IsController(const Common::ParamPackage& params) const { diff --git a/src/input_common/main.h b/src/input_common/main.h index a4a24d076..c6f97f691 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -13,6 +13,10 @@ namespace Common { class ParamPackage; } +namespace Common::Input { +enum class ButtonNames; +} + namespace Settings::NativeAnalog { enum Values : int; } @@ -108,8 +112,9 @@ public: /// Retrieves the motion mappings for the given device. [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; - /// Returns a string contaning the name of the button from the input engine. - [[nodiscard]] std::string GetButtonName(const Common::ParamPackage& params) const; + /// Returns an enum contaning the name to be displayed from the input engine. + [[nodiscard]] Common::Input::ButtonNames GetButtonName( + const Common::ParamPackage& params) const; /// Returns true if device is a controller. [[nodiscard]] bool IsController(const Common::ParamPackage& params) const; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 0254ea6fe..6219a09a8 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -52,6 +52,37 @@ QString GetKeyName(int key_code) { } } +QString GetButtonName(Common::Input::ButtonNames button_name) { + switch (button_name) { + case Common::Input::ButtonNames::ButtonLeft: + return QObject::tr("Left"); + case Common::Input::ButtonNames::ButtonRight: + return QObject::tr("Right"); + case Common::Input::ButtonNames::ButtonDown: + return QObject::tr("Down"); + case Common::Input::ButtonNames::ButtonUp: + return QObject::tr("Up"); + case Common::Input::ButtonNames::TriggerZ: + return QObject::tr("Z"); + case Common::Input::ButtonNames::TriggerR: + return QObject::tr("R"); + case Common::Input::ButtonNames::TriggerL: + return QObject::tr("L"); + case Common::Input::ButtonNames::ButtonA: + return QObject::tr("A"); + case Common::Input::ButtonNames::ButtonB: + return QObject::tr("B"); + case Common::Input::ButtonNames::ButtonX: + return QObject::tr("X"); + case Common::Input::ButtonNames::ButtonY: + return QObject::tr("Y"); + case Common::Input::ButtonNames::ButtonStart: + return QObject::tr("Start"); + default: + return QObject::tr("[undefined]"); + } +} + void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, const std::string& button_name) { // The poller returned a complete axis, so set all the buttons @@ -75,15 +106,64 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { return QObject::tr("[not set]"); } + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); + const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : ""); + const auto common_button_name = input_subsystem->GetButtonName(param); + // Retrieve the names from Qt if (param.Get("engine", "") == "keyboard") { const QString button_str = GetKeyName(param.Get("code", 0)); - const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); return QObject::tr("%1%2").arg(toggle, button_str); } - std::string button_name = input_subsystem->GetButtonName(param); - return QString::fromStdString(button_name); + if (common_button_name == Common::Input::ButtonNames::Invalid) { + return QObject::tr("[invalid]"); + } + + if (common_button_name == Common::Input::ButtonNames::Engine) { + return QString::fromStdString(param.Get("engine", "")); + } + + if (common_button_name == Common::Input::ButtonNames::Value) { + if (param.Has("hat")) { + const QString hat = QString::fromStdString(param.Get("direction", "")); + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); + } + if (param.Has("axis")) { + const QString axis = QString::fromStdString(param.Get("axis", "")); + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, axis); + } + if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { + const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); + const QString axis_y = QString::fromStdString(param.Get("axis_y", "")); + const QString axis_z = QString::fromStdString(param.Get("axis_z", "")); + return QObject::tr("%1%2Axis %3,%4,%5").arg(toggle, inverted, axis_x, axis_y, axis_z); + } + if (param.Has("motion")) { + const QString motion = QString::fromStdString(param.Get("motion", "")); + return QObject::tr("%1%2Motion %3").arg(toggle, inverted, motion); + } + if (param.Has("button")) { + const QString button = QString::fromStdString(param.Get("button", "")); + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); + } + } + + QString button_name = GetButtonName(common_button_name); + if (param.Has("hat")) { + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); + } + if (param.Has("axis")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("motion")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("button")) { + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); + } + + return QObject::tr("[unknown]"); } QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, From e64ee99f00c6d2d884113f79785d4aec9fc05db8 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 21 Nov 2021 22:37:50 -0600 Subject: [PATCH 131/291] yuzu: Fix TAS from rebase --- src/yuzu/bootmanager.cpp | 3 ++- src/yuzu/bootmanager.h | 10 +++++----- src/yuzu/main.cpp | 7 ++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5e19f8cb1..114f17c06 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -320,7 +320,8 @@ GRenderWindow::~GRenderWindow() { void GRenderWindow::OnFrameDisplayed() { input_subsystem->GetTas()->UpdateThread(); - const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus()); + const InputCommon::TasInput::TasState new_tas_state = + std::get<0>(input_subsystem->GetTas()->GetStatus()); if (!first_frame) { last_tas_state = new_tas_state; diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index c8a2c59b4..92297a43b 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -33,15 +33,15 @@ class InputSubsystem; enum class MouseButton; } // namespace InputCommon +namespace InputCommon::TasInput { +enum class TasState; +} // namespace InputCommon::TasInput + namespace VideoCore { enum class LoadCallbackStage; class RendererBase; } // namespace VideoCore -namespace TasInput { -enum class TasState; -} - class EmuThread final : public QThread { Q_OBJECT @@ -245,7 +245,7 @@ private: QWidget* child_widget = nullptr; bool first_frame = false; - TasInput::TasState last_tas_state; + InputCommon::TasInput::TasState last_tas_state; std::array touch_ids{}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index cd8ea221d..09ea21f5e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2992,9 +2992,10 @@ void GMainWindow::OnTasStateChanged() { bool is_running = false; bool is_recording = false; if (emulation_running) { - const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus()); - is_running = tas_status == TasInput::TasState::Running; - is_recording = tas_status == TasInput::TasState::Recording; + const InputCommon::TasInput::TasState tas_status = + std::get<0>(input_subsystem->GetTas()->GetStatus()); + is_running = tas_status == InputCommon::TasInput::TasState::Running; + is_recording = tas_status == InputCommon::TasInput::TasState::Recording; } ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start")); From 23bf2e3bb6fe0881e28767e768ad9c0a9f851d57 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Mon, 22 Nov 2021 22:15:34 -0600 Subject: [PATCH 132/291] service/hid: Finish converting LIFO objects and address some nits --- src/core/hid/emulated_controller.cpp | 2 +- src/core/hid/hid_types.h | 6 +- .../hid/controllers/console_sixaxis.cpp | 31 ++++------ .../service/hid/controllers/console_sixaxis.h | 31 ++-------- .../service/hid/controllers/controller_base.h | 2 + .../hle/service/hid/controllers/debug_pad.h | 2 +- .../hle/service/hid/controllers/gesture.h | 2 +- .../hle/service/hid/controllers/keyboard.h | 2 +- src/core/hle/service/hid/controllers/mouse.h | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 2 + src/core/hle/service/hid/controllers/npad.h | 56 ++++++------------- .../hle/service/hid/controllers/touchscreen.h | 2 +- src/core/hle/service/hid/controllers/xpad.h | 2 +- src/core/hle/service/hid/ring_lifo.h | 3 +- 14 files changed, 50 insertions(+), 95 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 54c1a2324..54d4ed93d 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -723,7 +723,7 @@ void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std: bool is_charging = false; bool is_powered = false; - BatteryLevel battery_level = 0; + NpadBatteryLevel battery_level = 0; switch (controller.battery_values[index]) { case Common::Input::BatteryLevel::Charging: is_charging = true; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 3cbe16260..acf54e233 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -346,15 +346,15 @@ struct NpadGcTriggerState { static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); // This is nn::hid::system::NpadBatteryLevel -using BatteryLevel = u32; -static_assert(sizeof(BatteryLevel) == 0x4, "BatteryLevel is an invalid size"); +using NpadBatteryLevel = u32; +static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid size"); // This is nn::hid::system::NpadPowerInfo struct NpadPowerInfo { bool is_powered; bool is_charging; INSERT_PADDING_BYTES(0x6); - BatteryLevel battery_level; + NpadBatteryLevel battery_level; }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index ea7e8f18f..f0f3105dc 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -24,34 +24,25 @@ void Controller_ConsoleSixAxis::OnRelease() {} void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - seven_six_axis.header.timestamp = core_timing.GetCPUTicks(); - seven_six_axis.header.total_entry_count = 17; - if (!IsControllerActivated() || !is_transfer_memory_set) { - seven_six_axis.header.entry_count = 0; - seven_six_axis.header.last_entry_index = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; return; } - seven_six_axis.header.entry_count = 16; - const auto& last_entry = - seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17; - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; + next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; // Try to read sixaxis sensor states const auto motion_status = console->GetMotion(); console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - cur_entry.accel = motion_status.accel; + next_seven_sixaxis_state.accel = motion_status.accel; // Zero gyro values as they just mess up with the camera // Note: Probably a correct sensivity setting must be set - cur_entry.gyro = {}; - cur_entry.quaternion = { + next_seven_sixaxis_state.gyro = {}; + next_seven_sixaxis_state.quaternion = { { motion_status.quaternion.xyz.y, motion_status.quaternion.xyz.x, @@ -68,7 +59,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti // Update console six axis shared memory std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); // Update seven six axis transfer memory - std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); + seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); + std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); } void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { @@ -77,8 +69,7 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { } void Controller_ConsoleSixAxis::ResetTimestamp() { - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - cur_entry.sampling_number = 0; - cur_entry.sampling_number2 = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 7c92413e8..279241858 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -10,6 +10,7 @@ #include "common/quaternion.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Core::HID { class EmulatedConsole; @@ -40,50 +41,30 @@ private: struct SevenSixAxisState { INSERT_PADDING_WORDS(4); // unused s64 sampling_number{}; - s64 sampling_number2{}; u64 unknown{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Quaternion quaternion{}; }; - static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); - - struct CommonHeader { - s64 timestamp; - s64 total_entry_count; - s64 last_entry_index; - s64 entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - // TODO(german77): SevenSixAxisMemory doesn't follow the standard lifo. Investigate - struct SevenSixAxisMemory { - CommonHeader header{}; - std::array sevensixaxis_states{}; - }; - static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); + static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { u64 sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; + INSERT_PADDING_BYTES(4); // padding f32 verticalization_error{}; Common::Vec3f gyro_bias{}; }; static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); - struct MotionDevice { - Common::Vec3f accel; - Common::Vec3f gyro; - Common::Vec3f rotation; - std::array orientation; - Common::Quaternion quaternion; - }; + Lifo seven_sixaxis_lifo{}; + static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); Core::HID::EmulatedConsole* console; u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; ConsoleSharedMemory console_six_axis{}; - SevenSixAxisMemory seven_six_axis{}; + SevenSixAxisState next_seven_sixaxis_state{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 8125bbc84..7450eb20a 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -41,6 +41,8 @@ public: bool IsControllerActivated() const; + static const std::size_t hid_entry_count = 17; + protected: bool is_activated{false}; diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 15b3afb7a..afe374fc2 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -54,7 +54,7 @@ private: static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); // This is nn::hid::detail::DebugPadLifo - Lifo debug_pad_lifo{}; + Lifo debug_pad_lifo{}; static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); DebugPadState next_state{}; diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index f924464e0..0936a3fa3 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -136,7 +136,7 @@ private: GestureProperties GetGestureProperties(); // This is nn::hid::detail::GestureLifo - Lifo gesture_lifo{}; + Lifo gesture_lifo{}; static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); GestureState next_state{}; diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 0d61cb470..cf62d3896 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -44,7 +44,7 @@ private: static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); // This is nn::hid::detail::KeyboardLifo - Lifo keyboard_lifo{}; + Lifo keyboard_lifo{}; static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); KeyboardState next_state{}; diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 1ac69aa6f..7559fc78d 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -34,7 +34,7 @@ public: private: // This is nn::hid::detail::MouseLifo - Lifo mouse_lifo{}; + Lifo mouse_lifo{}; static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); Core::HID::MouseState next_state{}; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4b23230e1..dd4d954aa 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -157,6 +157,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); + shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; @@ -167,6 +168,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); + shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; break; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 3798c037f..9fa113bb6 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -339,26 +339,6 @@ private: static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, "NfcXcdDeviceHandleStateImpl is an invalid size"); - // nn::hid::detail::NfcXcdDeviceHandleStateImplAtomicStorage - struct NfcXcdDeviceHandleStateImplAtomicStorage { - u64 sampling_number; - NfcXcdDeviceHandleStateImpl nfc_xcd_device_handle_state; - }; - static_assert(sizeof(NfcXcdDeviceHandleStateImplAtomicStorage) == 0x20, - "NfcXcdDeviceHandleStateImplAtomicStorage is an invalid size"); - - // This is nn::hid::detail::NfcXcdDeviceHandleState - struct NfcXcdDeviceHandleState { - // TODO(german77): Make this struct a ring lifo object - INSERT_PADDING_BYTES(0x8); // Unused - s64 total_buffer_count = max_buffer_size; - s64 buffer_tail{}; - s64 buffer_count{}; - std::array nfc_xcd_device_handle_storage; - }; - static_assert(sizeof(NfcXcdDeviceHandleState) == 0x60, - "NfcXcdDeviceHandleState is an invalid size"); - // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); @@ -433,32 +413,32 @@ private: NpadJoyAssignmentMode assignment_mode; NpadFullKeyColorState fullkey_color; NpadJoyColorState joycon_color; - Lifo fullkey_lifo; - Lifo handheld_lifo; - Lifo joy_dual_lifo; - Lifo joy_left_lifo; - Lifo joy_right_lifo; - Lifo palma_lifo; - Lifo system_ext_lifo; - Lifo sixaxis_fullkey_lifo; - Lifo sixaxis_handheld_lifo; - Lifo sixaxis_dual_left_lifo; - Lifo sixaxis_dual_right_lifo; - Lifo sixaxis_left_lifo; - Lifo sixaxis_right_lifo; + Lifo fullkey_lifo; + Lifo handheld_lifo; + Lifo joy_dual_lifo; + Lifo joy_left_lifo; + Lifo joy_right_lifo; + Lifo palma_lifo; + Lifo system_ext_lifo; + Lifo sixaxis_fullkey_lifo; + Lifo sixaxis_handheld_lifo; + Lifo sixaxis_dual_left_lifo; + Lifo sixaxis_dual_right_lifo; + Lifo sixaxis_left_lifo; + Lifo sixaxis_right_lifo; DeviceType device_type; INSERT_PADDING_BYTES(0x4); // Reserved NPadSystemProperties system_properties; NpadSystemButtonProperties button_properties; - Core::HID::BatteryLevel battery_level_dual; - Core::HID::BatteryLevel battery_level_left; - Core::HID::BatteryLevel battery_level_right; + Core::HID::NpadBatteryLevel battery_level_dual; + Core::HID::NpadBatteryLevel battery_level_left; + Core::HID::NpadBatteryLevel battery_level_right; union { - NfcXcdDeviceHandleState nfc_xcd_device_handle; + Lifo nfc_xcd_device_lifo{}; AppletFooterUi applet_footer; }; INSERT_PADDING_BYTES(0x20); // Unknown - Lifo gc_trigger_lifo; + Lifo gc_trigger_lifo; NpadLarkType lark_type_l_and_main; NpadLarkType lark_type_r; NpadLuciaType lucia_type; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 135c2bf13..708dde4f0 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -61,7 +61,7 @@ private: static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); // This is nn::hid::detail::TouchScreenLifo - Lifo touch_screen_lifo{}; + Lifo touch_screen_lifo{}; static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); TouchScreenState next_state{}; diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 54dae0be1..ba8db8d9d 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -102,7 +102,7 @@ private: static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); // This is nn::hid::detail::BasicXpadLifo - Lifo basic_xpad_lifo{}; + Lifo basic_xpad_lifo{}; static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); BasicXpadState next_state{}; }; diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index f0e0bab7f..44c20d967 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -9,7 +9,6 @@ #include "common/common_types.h" namespace Service::HID { -constexpr std::size_t max_buffer_size = 17; template struct AtomicStorage { @@ -17,7 +16,7 @@ struct AtomicStorage { State state; }; -template +template struct Lifo { s64 timestamp{}; s64 total_buffer_count = static_cast(max_buffer_size); From 5303161aa129e2a7a2fb1d7e8665ad4edc96e1d8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Nov 2021 23:08:42 -0500 Subject: [PATCH 133/291] CMakeLists: Update fmt to 8.0.1 Ensures that we're using the latest version of fmt. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c044c1ea..61510cc0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,7 +167,7 @@ macro(yuzu_find_packages) set(REQUIRED_LIBS # Cmake Pkg Prefix Version Conan Pkg "Catch2 2.13.7 catch2/2.13.7" - "fmt 8.0 fmt/8.0.0" + "fmt 8.0.1 fmt/8.0.1" "lz4 1.8 lz4/1.9.2" "nlohmann_json 3.8 nlohmann_json/3.8.0" "ZLIB 1.2 zlib/1.2.11" From 1624f307d0ebd68751b567f6a616f635567754fa Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 26 Nov 2021 17:03:48 +0100 Subject: [PATCH 134/291] Texture Cache: Further fix regressions. --- src/video_core/texture_cache/texture_cache.h | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 9548abec8..570da2b04 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1088,19 +1088,23 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( ImageId src_id; do { has_deleted_images = false; - dst_id = FindImage(dst_info, dst_addr, FIND_OPTIONS); src_id = FindImage(src_info, src_addr, FIND_OPTIONS); - const ImageBase* const dst_image = dst_id ? &slot_images[dst_id] : nullptr; const ImageBase* const src_image = src_id ? &slot_images[src_id] : nullptr; - DeduceBlitImages(dst_info, src_info, dst_image, src_image); - ASSERT(GetFormatType(dst_info.format) == GetFormatType(src_info.format)); - RelaxedOptions find_options{}; - if (src_info.num_samples > 1) { - // it's a resolve, we must enforce the same format. - find_options = RelaxedOptions::ForceBrokenViews; + if (src_image && src_image->info.num_samples > 1) { + RelaxedOptions find_options{FIND_OPTIONS | RelaxedOptions::ForceBrokenViews}; + src_id = FindOrInsertImage(src_info, src_addr, find_options); + dst_id = FindOrInsertImage(dst_info, dst_addr, find_options); + if (has_deleted_images) { + continue; + } + } + dst_id = FindImage(dst_info, dst_addr, FIND_OPTIONS); + if (!src_id) { + src_id = InsertImage(src_info, src_addr, RelaxedOptions{}); + } + if (!dst_id) { + dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); } - src_id = FindOrInsertImage(src_info, src_addr, find_options); - dst_id = FindOrInsertImage(dst_info, dst_addr, find_options); } while (has_deleted_images); return BlitImages{ .dst_id = dst_id, From 639402850ac65c694967ef6519becb65abe89b39 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Fri, 26 Nov 2021 15:45:37 -0600 Subject: [PATCH 135/291] input_common: Fully implement UDP controllers --- src/common/input.h | 14 ++ src/common/settings.h | 1 + src/core/hid/emulated_console.cpp | 6 +- src/input_common/drivers/udp_client.cpp | 206 +++++++++++++++++- src/input_common/drivers/udp_client.h | 56 +++++ src/input_common/helpers/udp_protocol.h | 75 +++++-- src/input_common/input_mapping.cpp | 6 + src/input_common/main.cpp | 26 ++- src/yuzu/configuration/config.cpp | 2 + .../configure_input_advanced.cpp | 2 + .../configuration/configure_input_advanced.ui | 19 +- .../configuration/configure_input_player.cpp | 24 ++ 12 files changed, 397 insertions(+), 40 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index cc0cbd9b8..eaee0bdea 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -195,6 +195,20 @@ enum class ButtonNames { ButtonX, ButtonY, ButtonStart, + + // DS4 button names + L1, + L2, + L3, + R1, + R2, + R3, + Circle, + Cross, + Square, + Triangle, + Share, + Options, }; // Callback data consisting of an input type and the equivalent data status diff --git a/src/common/settings.h b/src/common/settings.h index d7410fa9b..e4e049f67 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -560,6 +560,7 @@ struct Values { Setting motion_enabled{true, "motion_enabled"}; BasicSetting udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; + BasicSetting enable_udp_controller{false, "enable_udp_controller"}; BasicSetting pause_tas_on_load{true, "pause_tas_on_load"}; BasicSetting tas_enable{false, "tas_enable"}; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index b224932dc..80db8e9c6 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -30,8 +30,10 @@ void EmulatedConsole::SetTouchParams() { } touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; - touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; - touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; + touch_params[index++] = + Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; + touch_params[index++] = + Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 7cab707da..fdee0f2d5 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -103,7 +103,7 @@ private: // Send a request for getting pad data for the pad const Request::PadData pad_data{ - Request::PadData::Flags::AllPorts, + Request::RegisterFlags::AllPads, 0, EMPTY_MAC_ADDRESS, }; @@ -247,7 +247,12 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { for (std::size_t id = 0; id < data.touch.size(); ++id) { const auto touch_pad = data.touch[id]; - const int touch_id = static_cast(client * 2 + id); + const auto touch_axis_x_id = + static_cast(id == 0 ? PadAxes::Touch1X : PadAxes::Touch2X); + const auto touch_axis_y_id = + static_cast(id == 0 ? PadAxes::Touch1Y : PadAxes::Touch2Y); + const auto touch_button_id = + static_cast(id == 0 ? PadButton::Touch1 : PadButton::touch2); // TODO: Use custom calibration per device const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); @@ -264,14 +269,35 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { static_cast(max_y - min_y); if (touch_pad.is_active) { - SetAxis(identifier, touch_id * 2, x); - SetAxis(identifier, touch_id * 2 + 1, y); - SetButton(identifier, touch_id, true); + SetAxis(identifier, touch_axis_x_id, x); + SetAxis(identifier, touch_axis_y_id, y); + SetButton(identifier, touch_button_id, true); continue; } - SetAxis(identifier, touch_id * 2, 0); - SetAxis(identifier, touch_id * 2 + 1, 0); - SetButton(identifier, touch_id, false); + SetAxis(identifier, touch_axis_x_id, 0); + SetAxis(identifier, touch_axis_y_id, 0); + SetButton(identifier, touch_button_id, false); + } + + SetAxis(identifier, static_cast(PadAxes::LeftStickX), + (data.left_stick_x - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::LeftStickY), + (data.left_stick_y - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::RightStickX), + (data.right_stick_x - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::RightStickY), + (data.right_stick_y - 127.0f) / 127.0f); + + static constexpr std::array buttons{ + PadButton::Share, PadButton::L3, PadButton::R3, PadButton::Options, + PadButton::Up, PadButton::Right, PadButton::Down, PadButton::Left, + PadButton::L2, PadButton::R2, PadButton::L1, PadButton::R1, + PadButton::Triangle, PadButton::Circle, PadButton::Cross, PadButton::Square}; + + for (std::size_t i = 0; i < buttons.size(); ++i) { + const bool button_status = (data.digital_button & (1U << i)) != 0; + const int button = static_cast(buttons[i]); + SetButton(identifier, button, button_status); } } @@ -317,6 +343,170 @@ void UDPClient::Reset() { } } +std::vector UDPClient::GetInputDevices() const { + std::vector devices; + if (!Settings::values.enable_udp_controller) { + return devices; + } + for (std::size_t client = 0; client < clients.size(); client++) { + if (clients[client].active != 1) { + continue; + } + for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { + const std::size_t pad_index = client * PADS_PER_CLIENT + index; + if (!pads[pad_index].connected) { + continue; + } + const auto pad_identifier = GetPadIdentifier(pad_index); + Common::ParamPackage identifier{}; + identifier.Set("engine", GetEngineName()); + identifier.Set("display", fmt::format("UDP Controller {}", pad_identifier.pad)); + identifier.Set("guid", pad_identifier.guid.Format()); + identifier.Set("port", static_cast(pad_identifier.port)); + identifier.Set("pad", static_cast(pad_identifier.pad)); + devices.emplace_back(identifier); + } + } + return devices; +} + +ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) { + // This list excludes any button that can't be really mapped + static constexpr std::array, 18> + switch_to_dsu_button = { + std::pair{Settings::NativeButton::A, PadButton::Circle}, + {Settings::NativeButton::B, PadButton::Cross}, + {Settings::NativeButton::X, PadButton::Triangle}, + {Settings::NativeButton::Y, PadButton::Square}, + {Settings::NativeButton::Plus, PadButton::Options}, + {Settings::NativeButton::Minus, PadButton::Share}, + {Settings::NativeButton::DLeft, PadButton::Left}, + {Settings::NativeButton::DUp, PadButton::Up}, + {Settings::NativeButton::DRight, PadButton::Right}, + {Settings::NativeButton::DDown, PadButton::Down}, + {Settings::NativeButton::L, PadButton::L1}, + {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::LStick, PadButton::L3}, + {Settings::NativeButton::RStick, PadButton::R3}, + }; + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + ButtonMapping mapping{}; + for (const auto& [switch_button, dsu_button] : switch_to_dsu_button) { + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); + button_params.Set("guid", params.Get("guid", "")); + button_params.Set("port", params.Get("port", 0)); + button_params.Set("pad", params.Get("pad", 0)); + button_params.Set("button", static_cast(dsu_button)); + mapping.insert_or_assign(switch_button, std::move(button_params)); + } + + return mapping; +} + +AnalogMapping UDPClient::GetAnalogMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + AnalogMapping mapping = {}; + Common::ParamPackage left_analog_params; + left_analog_params.Set("engine", GetEngineName()); + left_analog_params.Set("guid", params.Get("guid", "")); + left_analog_params.Set("port", params.Get("port", 0)); + left_analog_params.Set("pad", params.Get("pad", 0)); + left_analog_params.Set("axis_x", static_cast(PadAxes::LeftStickX)); + left_analog_params.Set("axis_y", static_cast(PadAxes::LeftStickY)); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); + Common::ParamPackage right_analog_params; + right_analog_params.Set("engine", GetEngineName()); + right_analog_params.Set("guid", params.Get("guid", "")); + right_analog_params.Set("port", params.Get("port", 0)); + right_analog_params.Set("pad", params.Get("pad", 0)); + right_analog_params.Set("axis_x", static_cast(PadAxes::RightStickX)); + right_analog_params.Set("axis_y", static_cast(PadAxes::RightStickY)); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + return mapping; +} + +MotionMapping UDPClient::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + MotionMapping mapping = {}; + Common::ParamPackage motion_params; + motion_params.Set("engine", GetEngineName()); + motion_params.Set("guid", params.Get("guid", "")); + motion_params.Set("port", params.Get("port", 0)); + motion_params.Set("pad", params.Get("pad", 0)); + motion_params.Set("motion", 0); + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(motion_params)); + mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(motion_params)); + return mapping; +} + +Common::Input::ButtonNames UDPClient::GetUIButtonName(const Common::ParamPackage& params) const { + PadButton button = static_cast(params.Get("button", 0)); + switch (button) { + case PadButton::Left: + return Common::Input::ButtonNames::ButtonLeft; + case PadButton::Right: + return Common::Input::ButtonNames::ButtonRight; + case PadButton::Down: + return Common::Input::ButtonNames::ButtonDown; + case PadButton::Up: + return Common::Input::ButtonNames::ButtonUp; + case PadButton::L1: + return Common::Input::ButtonNames::L1; + case PadButton::L2: + return Common::Input::ButtonNames::L2; + case PadButton::L3: + return Common::Input::ButtonNames::L3; + case PadButton::R1: + return Common::Input::ButtonNames::R1; + case PadButton::R2: + return Common::Input::ButtonNames::R2; + case PadButton::R3: + return Common::Input::ButtonNames::R3; + case PadButton::Circle: + return Common::Input::ButtonNames::Circle; + case PadButton::Cross: + return Common::Input::ButtonNames::Cross; + case PadButton::Square: + return Common::Input::ButtonNames::Square; + case PadButton::Triangle: + return Common::Input::ButtonNames::Triangle; + case PadButton::Share: + return Common::Input::ButtonNames::Share; + case PadButton::Options: + return Common::Input::ButtonNames::Options; + default: + return Common::Input::ButtonNames::Undefined; + } +} + +Common::Input::ButtonNames UDPClient::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return GetUIButtonName(params); + } + if (params.Has("axis")) { + return Common::Input::ButtonNames::Value; + } + if (params.Has("motion")) { + return Common::Input::ButtonNames::Engine; + } + + return Common::Input::ButtonNames::Invalid; +} + void TestCommunication(const std::string& host, u16 port, const std::function& success_callback, const std::function& failure_callback) { diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 1f02adba5..5d483f26b 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -56,7 +56,61 @@ public: void ReloadSockets(); + /// Used for automapping features + std::vector GetInputDevices() const override; + ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; + private: + enum class PadButton { + Undefined = 0x0000, + Share = 0x0001, + L3 = 0x0002, + R3 = 0x0004, + Options = 0x0008, + Up = 0x0010, + Right = 0x0020, + Down = 0x0040, + Left = 0x0080, + L2 = 0x0100, + R2 = 0x0200, + L1 = 0x0400, + R1 = 0x0800, + Triangle = 0x1000, + Circle = 0x2000, + Cross = 0x4000, + Square = 0x8000, + Touch1 = 0x10000, + touch2 = 0x20000, + }; + + enum class PadAxes : u8 { + LeftStickX, + LeftStickY, + RightStickX, + RightStickY, + AnalogLeft, + AnalogDown, + AnalogRight, + AnalogUp, + AnalogSquare, + AnalogCross, + AnalogCircle, + AnalogTriangle, + AnalogR1, + AnalogL1, + AnalogR2, + AnalogL3, + AnalogR3, + Touch1X, + Touch1Y, + Touch2X, + Touch2Y, + Undefined, + }; + struct PadData { std::size_t pad_index{}; bool connected{}; @@ -90,6 +144,8 @@ private: const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; const Common::UUID GetHostUUID(const std::string host) const; + Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; + // Allocate clients for 8 udp servers static constexpr std::size_t MAX_UDP_CLIENTS = 8; static constexpr std::size_t PADS_PER_CLIENT = 4; diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index 1bdc9209e..bcba12c58 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h @@ -56,6 +56,12 @@ constexpr Type GetMessageType(); namespace Request { +enum RegisterFlags : u8 { + AllPads, + PadID, + PadMACAdddress, +}; + struct Version {}; /** * Requests the server to send information about what controllers are plugged into the ports @@ -77,13 +83,8 @@ static_assert(std::is_trivially_copyable_v, * timeout seems to be 5 seconds. */ struct PadData { - enum class Flags : u8 { - AllPorts, - Id, - Mac, - }; /// Determines which method will be used as a look up for the controller - Flags flags{}; + RegisterFlags flags{}; /// Index of the port of the controller to retrieve data about u8 port_id{}; /// Mac address of the controller to retrieve data about @@ -113,6 +114,36 @@ Message Create(const T data, const u32 client_id = 0) { namespace Response { +enum class ConnectionType : u8 { + None, + Usb, + Bluetooth, +}; + +enum class State : u8 { + Disconnected, + Reserved, + Connected, +}; + +enum class Model : u8 { + None, + PartialGyro, + FullGyro, + Generic, +}; + +enum class Battery : u8 { + None = 0x00, + Dying = 0x01, + Low = 0x02, + Medium = 0x03, + High = 0x04, + Full = 0x05, + Charging = 0xEE, + Charged = 0xEF, +}; + struct Version { u16_le version{}; }; @@ -122,11 +153,11 @@ static_assert(std::is_trivially_copyable_v, struct PortInfo { u8 id{}; - u8 state{}; - u8 model{}; - u8 connection_type{}; + State state{}; + Model model{}; + ConnectionType connection_type{}; MacAddress mac; - u8 battery{}; + Battery battery{}; u8 is_pad_active{}; }; static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); @@ -177,18 +208,18 @@ struct PadData { u8 right_stick_y{}; struct AnalogButton { - u8 button_8{}; - u8 button_7{}; - u8 button_6{}; - u8 button_5{}; - u8 button_12{}; - u8 button_11{}; - u8 button_10{}; - u8 button_9{}; - u8 button_16{}; - u8 button_15{}; - u8 button_14{}; - u8 button_13{}; + u8 button_dpad_left_analog{}; + u8 button_dpad_down_analog{}; + u8 button_dpad_right_analog{}; + u8 button_dpad_up_analog{}; + u8 button_square_analog{}; + u8 button_cross_analog{}; + u8 button_circle_analog{}; + u8 button_triangle_analog{}; + u8 button_r1_analog{}; + u8 button_l1_analog{}; + u8 trigger_r2{}; + u8 trigger_l2{}; } analog_button; std::array touch; diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index c5218f2cb..6e0024b2d 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included #include "common/common_types.h" +#include "common/settings.h" #include "input_common/input_engine.h" #include "input_common/input_mapping.h" @@ -182,6 +183,11 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const { if (data.engine == "keyboard" && data.pad.port != 0) { return false; } + // To prevent mapping with two devices we disable any UDP except motion + if (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" && + data.type != EngineInputType::Motion) { + return false; + } // The following drivers don't need to be mapped if (data.engine == "tas") { return false; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 39e4935dc..940744c5f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -63,9 +63,12 @@ struct InputSubsystem::Impl { udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); - udp_client_factory = std::make_shared(udp_client); + udp_client_input_factory = std::make_shared(udp_client); + udp_client_output_factory = std::make_shared(udp_client); Common::Input::RegisterFactory(udp_client->GetEngineName(), - udp_client_factory); + udp_client_input_factory); + Common::Input::RegisterFactory(udp_client->GetEngineName(), + udp_client_output_factory); tas_input = std::make_shared("tas"); tas_input->SetMappingCallback(mapping_callback); @@ -110,6 +113,7 @@ struct InputSubsystem::Impl { gcadapter.reset(); Common::Input::UnregisterFactory(udp_client->GetEngineName()); + Common::Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); Common::Input::UnregisterFactory(tas_input->GetEngineName()); @@ -137,6 +141,8 @@ struct InputSubsystem::Impl { devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); auto gcadapter_devices = gcadapter->GetInputDevices(); devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); + auto udp_devices = udp_client->GetInputDevices(); + devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); #ifdef HAVE_SDL2 auto sdl_devices = sdl->GetInputDevices(); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); @@ -157,6 +163,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return gcadapter->GetAnalogMappingForDevice(params); } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetAnalogMappingForDevice(params); + } if (engine == tas_input->GetEngineName()) { return tas_input->GetAnalogMappingForDevice(params); } @@ -177,6 +186,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return gcadapter->GetButtonMappingForDevice(params); } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetButtonMappingForDevice(params); + } if (engine == tas_input->GetEngineName()) { return tas_input->GetButtonMappingForDevice(params); } @@ -194,8 +206,8 @@ struct InputSubsystem::Impl { return {}; } const std::string engine = params.Get("engine", ""); - if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetMotionMappingForDevice(params); + if (engine == udp_client->GetEngineName()) { + return udp_client->GetMotionMappingForDevice(params); } #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { @@ -238,6 +250,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return true; } + if (engine == udp_client->GetEngineName()) { + return true; + } if (engine == tas_input->GetEngineName()) { return true; } @@ -286,12 +301,13 @@ struct InputSubsystem::Impl { std::shared_ptr mouse_factory; std::shared_ptr gcadapter_input_factory; std::shared_ptr touch_screen_factory; - std::shared_ptr udp_client_factory; + std::shared_ptr udp_client_input_factory; std::shared_ptr tas_input_factory; std::shared_ptr keyboard_output_factory; std::shared_ptr mouse_output_factory; std::shared_ptr gcadapter_output_factory; + std::shared_ptr udp_client_output_factory; std::shared_ptr tas_output_factory; #ifdef HAVE_SDL2 diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ae1684dd4..38fd6e93b 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -447,6 +447,7 @@ void Config::ReadMotionTouchValues() { Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); ReadBasicSetting(Settings::values.udp_input_servers); + ReadBasicSetting(Settings::values.enable_udp_controller); } void Config::ReadCoreValues() { @@ -942,6 +943,7 @@ void Config::SaveMotionTouchValues() { WriteBasicSetting(Settings::values.touch_device); WriteBasicSetting(Settings::values.touch_from_button_map_index); WriteBasicSetting(Settings::values.udp_input_servers); + WriteBasicSetting(Settings::values.enable_udp_controller); qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index e6127f9e6..65c8e59ac 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -130,6 +130,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { static_cast(ui->mouse_panning_sensitivity->value()); Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); + Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -160,6 +161,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); + ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); UpdateUIEnabled(); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 75487a5d0..df0e4d602 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2642,6 +2642,19 @@ + + + + 0 + 23 + + + + Enable UDP controllers (not needed for motion) + + + + @@ -2654,7 +2667,7 @@ - + Mouse sensitivity @@ -2676,14 +2689,14 @@ - + Motion / Touch - + Configure diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 6219a09a8..ec071d6ec 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -78,6 +78,30 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { return QObject::tr("Y"); case Common::Input::ButtonNames::ButtonStart: return QObject::tr("Start"); + case Common::Input::ButtonNames::L1: + return QObject::tr("L1"); + case Common::Input::ButtonNames::L2: + return QObject::tr("L2"); + case Common::Input::ButtonNames::L3: + return QObject::tr("L3"); + case Common::Input::ButtonNames::R1: + return QObject::tr("R1"); + case Common::Input::ButtonNames::R2: + return QObject::tr("R2"); + case Common::Input::ButtonNames::R3: + return QObject::tr("R3"); + case Common::Input::ButtonNames::Circle: + return QObject::tr("Circle"); + case Common::Input::ButtonNames::Cross: + return QObject::tr("Cross"); + case Common::Input::ButtonNames::Square: + return QObject::tr("Square"); + case Common::Input::ButtonNames::Triangle: + return QObject::tr("Triangle"); + case Common::Input::ButtonNames::Share: + return QObject::tr("Share"); + case Common::Input::ButtonNames::Options: + return QObject::tr("Options"); default: return QObject::tr("[undefined]"); } From a4a0638bc8043ddaea13025dd7e07b198cdb3cee Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 26 Nov 2021 18:55:28 -0600 Subject: [PATCH 136/291] applet/controller: Enable configuring mode while the applet is open --- src/yuzu/applets/qt_controller.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 6a2cdda63..eaa0f39f2 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -29,7 +29,7 @@ namespace { void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadStyleIndex controller_type, bool connected) { - if (controller->IsConnected()) { + if (controller->IsConnected(true)) { controller->Disconnect(); } controller->SetNpadStyleIndex(controller_type); @@ -139,6 +139,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( DisableUnsupportedPlayers(); for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { + system.HIDCore().GetEmulatedControllerByIndex(player_index)->EnableConfiguration(); SetEmulatedControllers(player_index); } @@ -233,20 +234,24 @@ void QtControllerSelectorDialog::ApplyConfiguration() { Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); + for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { + system.HIDCore().GetEmulatedControllerByIndex(player_index)->DisableConfiguration(); + } } void QtControllerSelectorDialog::LoadConfiguration() { const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); - const auto connected = controller->IsConnected() || (index == 0 && handheld->IsConnected()); + const auto connected = + controller->IsConnected(true) || (index == 0 && handheld->IsConnected(true)); player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); emulated_controllers[index]->setCurrentIndex( - GetIndexFromControllerType(controller->GetNpadStyleIndex(), index)); + GetIndexFromControllerType(controller->GetNpadStyleIndex(true), index)); } - UpdateDockedState(handheld->IsConnected()); + UpdateDockedState(handheld->IsConnected(true)); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -510,8 +515,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) const auto player_connected = player_groupboxes[player_index]->isChecked() && controller_type != Core::HID::NpadStyleIndex::Handheld; - if (controller->GetNpadStyleIndex() == controller_type && - controller->IsConnected() == player_connected) { + if (controller->GetNpadStyleIndex(true) == controller_type && + controller->IsConnected(true) == player_connected) { // Set vibration devices in the event that the input device has changed. ConfigureVibration::SetVibrationDevices(player_index); return; @@ -633,7 +638,7 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); // Disconnect any unsupported players here and disable or hide them if applicable. - UpdateController(controller, controller->GetNpadStyleIndex(), false); + UpdateController(controller, controller->GetNpadStyleIndex(true), false); // Hide the player widgets when max_supported_controllers is less than or equal to 4. if (max_supported_players <= 4) { player_widgets[index]->hide(); From 182cd9004f75df21979d0edd47910fecbd129b63 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 26 Nov 2021 19:29:08 -0600 Subject: [PATCH 137/291] config: Remove vibration configuration --- src/common/settings_input.h | 2 - src/core/hid/emulated_controller.cpp | 5 +- src/yuzu/applets/qt_controller.cpp | 4 - src/yuzu/configuration/config.cpp | 17 ----- .../configuration/configure_vibration.cpp | 74 ------------------- src/yuzu/configuration/configure_vibration.h | 3 - src/yuzu/main.cpp | 2 - 7 files changed, 3 insertions(+), 104 deletions(-) diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 9a8804488..9e3df7376 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -357,7 +357,6 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods; using AnalogsRaw = std::array; using ButtonsRaw = std::array; using MotionsRaw = std::array; -using VibrationsRaw = std::array; constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; @@ -378,7 +377,6 @@ struct PlayerInput { ControllerType controller_type; ButtonsRaw buttons; AnalogsRaw analogs; - VibrationsRaw vibrations; MotionsRaw motions; bool vibration_enabled; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 54d4ed93d..06ae41c3e 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -92,10 +92,11 @@ void EmulatedController::ReloadFromSettings() { ReloadInput(); } + void EmulatedController::LoadDevices() { // TODO(german77): Use more buttons to detect the correct device - const auto left_joycon = button_params[Settings::NativeButton::A]; - const auto right_joycon = button_params[Settings::NativeButton::DRight]; + const auto left_joycon = button_params[Settings::NativeButton::DRight]; + const auto right_joycon = button_params[Settings::NativeButton::A]; // Triggers for GC controllers trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index eaa0f39f2..589e0577a 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -517,16 +517,12 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) if (controller->GetNpadStyleIndex(true) == controller_type && controller->IsConnected(true) == player_connected) { - // Set vibration devices in the event that the input device has changed. - ConfigureVibration::SetVibrationDevices(player_index); return; } // Disconnect the controller first. UpdateController(controller, controller_type, false); - ConfigureVibration::SetVibrationDevices(player_index); - // Handheld if (player_index == 0) { if (controller_type == Core::HID::NpadStyleIndex::Handheld) { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 38fd6e93b..2c70d0548 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -273,18 +273,6 @@ void Config::ReadPlayerValue(std::size_t player_index) { } } - for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) { - auto& player_vibrations = player.vibrations[i]; - - player_vibrations = - qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeVibration::mapping[i]), - QString{}) - .toString() - .toStdString(); - } - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); auto& player_motions = player.motions[i]; @@ -891,11 +879,6 @@ void Config::SavePlayerValue(std::size_t player_index) { QString::fromStdString(player.analogs[i]), QString::fromStdString(default_param)); } - for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) { - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeVibration::mapping[i]), - QString::fromStdString(player.vibrations[i]), QString{}); - } for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); WriteSetting(QStringLiteral("%1").arg(player_prefix) + diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index f1ce7205d..adce04b27 100644 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp @@ -59,80 +59,6 @@ void ConfigureVibration::ApplyConfiguration() { ui->checkBoxAccurateVibration->isChecked()); } -void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { - using namespace Settings::NativeButton; - static constexpr std::array, 2> buttons{{ - {DLeft, DUp, DRight, DDown, L, ZL}, // Left Buttons - {A, B, X, Y, R, ZR}, // Right Buttons - }}; - - auto& player = Settings::values.players.GetValue()[player_index]; - - for (std::size_t device_idx = 0; device_idx < buttons.size(); ++device_idx) { - std::unordered_map params_count; - - for (const auto button_index : buttons[device_idx]) { - const auto& player_button = player.buttons[button_index]; - - if (params_count.find(player_button) != params_count.end()) { - ++params_count[player_button]; - continue; - } - - params_count.insert_or_assign(player_button, 1); - } - - const auto it = std::max_element( - params_count.begin(), params_count.end(), - [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }); - - auto& vibration_param_str = player.vibrations[device_idx]; - vibration_param_str.clear(); - - if (it->first.empty()) { - continue; - } - - const auto param = Common::ParamPackage(it->first); - - const auto engine = param.Get("engine", ""); - const auto guid = param.Get("guid", ""); - const auto port = param.Get("port", 0); - - if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") { - continue; - } - - vibration_param_str += fmt::format("engine:{}", engine); - - if (port != 0) { - vibration_param_str += fmt::format(",port:{}", port); - } - if (!guid.empty()) { - vibration_param_str += fmt::format(",guid:{}", guid); - } - } - - if (player.vibrations[0] != player.vibrations[1]) { - return; - } - - if (!player.vibrations[0].empty() && - player.controller_type != Settings::ControllerType::RightJoycon) { - player.vibrations[1].clear(); - } else if (!player.vibrations[1].empty() && - player.controller_type == Settings::ControllerType::RightJoycon) { - player.vibrations[0].clear(); - } -} - -void ConfigureVibration::SetAllVibrationDevices() { - // Set vibration devices for all player indices including handheld - for (std::size_t player_idx = 0; player_idx < NUM_PLAYERS + 1; ++player_idx) { - SetVibrationDevices(player_idx); - } -} - void ConfigureVibration::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { RetranslateUI(); diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h index 07411a86f..37bbc2653 100644 --- a/src/yuzu/configuration/configure_vibration.h +++ b/src/yuzu/configuration/configure_vibration.h @@ -24,9 +24,6 @@ public: void ApplyConfiguration(); - static void SetVibrationDevices(std::size_t player_index); - static void SetAllVibrationDevices(); - private: void changeEvent(QEvent* event) override; void RetranslateUI(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 09ea21f5e..552db6387 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1380,8 +1380,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig); } - ConfigureVibration::SetAllVibrationDevices(); - // Disable fps limit toggle when booting a new title Settings::values.disable_fps_limit.SetValue(false); From ecefc932e64bf4ab8442d3c9808a2e54429e7001 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 26 Nov 2021 21:36:53 +0100 Subject: [PATCH 138/291] Texture Cache: Redesigning the blitting system (again). --- src/video_core/texture_cache/texture_cache.h | 52 +++++++++++++++---- .../texture_cache/texture_cache_base.h | 3 +- src/video_core/texture_cache/util.cpp | 28 ++++++---- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 570da2b04..f24de9a38 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -472,7 +472,7 @@ template void TextureCache

::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, const Tegra::Engines::Fermi2D::Config& copy) { - const BlitImages images = GetBlitImages(dst, src); + const BlitImages images = GetBlitImages(dst, src, copy); const ImageId dst_id = images.dst_id; const ImageId src_id = images.src_id; @@ -762,12 +762,15 @@ ImageId TextureCache

::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, const bool broken_views = runtime.HasBrokenTextureViewFormats() || True(options & RelaxedOptions::ForceBrokenViews); const bool native_bgr = runtime.HasNativeBgr(); - ImageId image_id; + const bool flexible_formats = True(options & RelaxedOptions::Format); + ImageId image_id{}; + boost::container::small_vector image_ids; const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { if (True(existing_image.flags & ImageFlagBits::Remapped)) { return false; } - if (info.type == ImageType::Linear || existing_image.info.type == ImageType::Linear) { + if (info.type == ImageType::Linear || existing_image.info.type == ImageType::Linear) + [[unlikely]] { const bool strict_size = False(options & RelaxedOptions::Size) && True(existing_image.flags & ImageFlagBits::Strong); const ImageInfo& existing = existing_image.info; @@ -776,17 +779,27 @@ ImageId TextureCache

::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, IsPitchLinearSameSize(existing, info, strict_size) && IsViewCompatible(existing.format, info.format, broken_views, native_bgr)) { image_id = existing_image_id; - return true; + image_ids.push_back(existing_image_id); + return !flexible_formats && existing.format == info.format; } } else if (IsSubresource(info, existing_image, gpu_addr, options, broken_views, native_bgr)) { image_id = existing_image_id; - return true; + image_ids.push_back(existing_image_id); + return !flexible_formats && existing_image.info.format == info.format; } return false; }; ForEachImageInRegion(*cpu_addr, CalculateGuestSizeInBytes(info), lambda); - return image_id; + if (image_ids.size() <= 1) [[likely]] { + return image_id; + } + auto image_ids_compare = [this](ImageId a, ImageId b) { + auto& image_a = slot_images[a]; + auto& image_b = slot_images[b]; + return image_a.modification_tick < image_b.modification_tick; + }; + return *std::ranges::max_element(image_ids, image_ids_compare); } template @@ -1078,17 +1091,26 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA template typename TextureCache

::BlitImages TextureCache

::GetBlitImages( - const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src) { + const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, + const Tegra::Engines::Fermi2D::Config& copy) { + static constexpr auto FIND_OPTIONS = RelaxedOptions::Samples; const GPUVAddr dst_addr = dst.Address(); const GPUVAddr src_addr = src.Address(); ImageInfo dst_info(dst); ImageInfo src_info(src); + const bool can_be_depth_blit = + dst_info.format == src_info.format && copy.filter == Tegra::Engines::Fermi2D::Filter::Point; ImageId dst_id; ImageId src_id; + RelaxedOptions try_options = FIND_OPTIONS; + if (can_be_depth_blit) { + try_options |= RelaxedOptions::Format; + } do { has_deleted_images = false; - src_id = FindImage(src_info, src_addr, FIND_OPTIONS); + src_id = FindImage(src_info, src_addr, try_options); + dst_id = FindImage(dst_info, dst_addr, try_options); const ImageBase* const src_image = src_id ? &slot_images[src_id] : nullptr; if (src_image && src_image->info.num_samples > 1) { RelaxedOptions find_options{FIND_OPTIONS | RelaxedOptions::ForceBrokenViews}; @@ -1097,8 +1119,15 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( if (has_deleted_images) { continue; } + break; + } + if (can_be_depth_blit) { + const ImageBase* const dst_image = src_id ? &slot_images[src_id] : nullptr; + DeduceBlitImages(dst_info, src_info, dst_image, src_image); + if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { + continue; + } } - dst_id = FindImage(dst_info, dst_addr, FIND_OPTIONS); if (!src_id) { src_id = InsertImage(src_info, src_addr, RelaxedOptions{}); } @@ -1106,6 +1135,11 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); } } while (has_deleted_images); + if (GetFormatType(dst_info.format) != SurfaceType::ColorTexture) { + // Make sure the images are depth and/or stencil textures. + src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{}); + dst_id = FindOrInsertImage(dst_info, dst_addr, RelaxedOptions{}); + } return BlitImages{ .dst_id = dst_id, .src_id = src_id, diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 643ad811c..7107887a6 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -252,7 +252,8 @@ private: /// Return a blit image pair from the given guest blit parameters [[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst, - const Tegra::Engines::Fermi2D::Surface& src); + const Tegra::Engines::Fermi2D::Surface& src, + const Tegra::Engines::Fermi2D::Config& copy); /// Find or create a sampler from a guest descriptor sampler [[nodiscard]] SamplerId FindSampler(const TSCEntry& config); diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 9b1613008..7bd31b211 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1151,19 +1151,25 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, const ImageBase* src) { - bool is_resolve = false; - if (src) { - is_resolve = src->info.num_samples > 1; - src_info.num_samples = src->info.num_samples; - src_info.size.width = src->info.size.width; - src_info.size.height = src->info.size.height; + const auto original_dst_format = dst_info.format; + if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { + src_info.format = src->info.format; } - if (dst) { - dst_info.num_samples = dst->info.num_samples; - dst_info.size.width = dst->info.size.width; - dst_info.size.height = dst->info.size.height; + if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { + dst_info.format = dst->info.format; + } + if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { + dst_info.format = src->info.format; + } + if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { + if (src) { + if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) { + dst_info.format = original_dst_format; + } + } else { + src_info.format = dst->info.format; + } } - ASSERT(!is_resolve || dst_info.format == src_info.format); } u32 MapSizeBytes(const ImageBase& image) { From f966c05a74e2406a6416cf6295459e25c0d675ec Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 25 Nov 2021 20:12:47 -0600 Subject: [PATCH 139/291] core/hid: Stub GetUniquePadsFromNpad Used in checkpoint homebrew --- src/core/hle/service/hid/hid.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 95fc07325..b36689552 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -1883,7 +1883,7 @@ public: {317, nullptr, "GetNpadLeftRightInterfaceType"}, {318, nullptr, "HasBattery"}, {319, nullptr, "HasLeftRightBattery"}, - {321, nullptr, "GetUniquePadsFromNpad"}, + {321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, {322, nullptr, "GetIrSensorState"}, {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, {324, nullptr, "GetUniquePadButtonSet"}, @@ -2054,6 +2054,18 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } + + void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id_type{rp.PopEnum()}; + + const s64 total_entries = 0; + LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(total_entries); + } }; class HidTmp final : public ServiceFramework { From 51df96b7c0ac7086b26fa766e87e18749e0395b1 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 27 Nov 2021 20:05:45 -0600 Subject: [PATCH 140/291] settings: Add debug setting to enable all controllers --- src/common/settings.h | 1 + src/common/settings_input.h | 5 +++ src/core/hid/emulated_controller.cpp | 20 +++++++++++ src/core/hle/service/hid/controllers/npad.cpp | 4 +++ src/yuzu/configuration/config.cpp | 2 ++ src/yuzu/configuration/configure_debug.cpp | 2 ++ src/yuzu/configuration/configure_debug.ui | 7 ++++ .../configuration/configure_input_player.cpp | 34 +++++++++++++++++++ 8 files changed, 75 insertions(+) diff --git a/src/common/settings.h b/src/common/settings.h index e4e049f67..313f1fa7f 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -604,6 +604,7 @@ struct Values { BasicSetting extended_logging{false, "extended_logging"}; BasicSetting use_debug_asserts{false, "use_debug_asserts"}; BasicSetting use_auto_stub{false, "use_auto_stub"}; + BasicSetting enable_all_controllers{false, "enable_all_controllers"}; // Miscellaneous BasicSetting log_filter{"*:Info", "log_filter"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 9e3df7376..4ff37e186 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -370,6 +370,11 @@ enum class ControllerType { RightJoycon, Handheld, GameCube, + Pokeball, + NES, + SNES, + N64, + SegaGenesis, }; struct PlayerInput { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 06ae41c3e..466ff5542 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -27,6 +27,16 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp return NpadStyleIndex::Handheld; case Settings::ControllerType::GameCube: return NpadStyleIndex::GameCube; + case Settings::ControllerType::Pokeball: + return NpadStyleIndex::Pokeball; + case Settings::ControllerType::NES: + return NpadStyleIndex::NES; + case Settings::ControllerType::SNES: + return NpadStyleIndex::SNES; + case Settings::ControllerType::N64: + return NpadStyleIndex::N64; + case Settings::ControllerType::SegaGenesis: + return NpadStyleIndex::SegaGenesis; default: return NpadStyleIndex::ProController; } @@ -46,6 +56,16 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleInde return Settings::ControllerType::Handheld; case NpadStyleIndex::GameCube: return Settings::ControllerType::GameCube; + case NpadStyleIndex::Pokeball: + return Settings::ControllerType::Pokeball; + case NpadStyleIndex::NES: + return Settings::ControllerType::NES; + case NpadStyleIndex::SNES: + return Settings::ControllerType::SNES; + case NpadStyleIndex::N64: + return Settings::ControllerType::N64; + case NpadStyleIndex::SegaGenesis: + return Settings::ControllerType::SegaGenesis; default: return Settings::ControllerType::ProController; } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index dd4d954aa..04b3a68c3 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -263,6 +263,10 @@ void Controller_NPad::OnInit() { style.fullkey.Assign(1); style.gamecube.Assign(1); style.palma.Assign(1); + style.lark.Assign(1); + style.lucia.Assign(1); + style.lagoon.Assign(1); + style.lager.Assign(1); hid_core.SetSupportedStyleTag(style); } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 2c70d0548..463d500c2 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -508,6 +508,7 @@ void Config::ReadDebuggingValues() { ReadBasicSetting(Settings::values.extended_logging); ReadBasicSetting(Settings::values.use_debug_asserts); ReadBasicSetting(Settings::values.use_auto_stub); + ReadBasicSetting(Settings::values.enable_all_controllers); qt_config->endGroup(); } @@ -1051,6 +1052,7 @@ void Config::SaveDebuggingValues() { WriteBasicSetting(Settings::values.quest_flag); WriteBasicSetting(Settings::values.use_debug_asserts); WriteBasicSetting(Settings::values.disable_macro_jit); + WriteBasicSetting(Settings::values.enable_all_controllers); qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 07bfa0360..633fc295b 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -42,6 +42,7 @@ void ConfigureDebug::SetConfiguration() { ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue()); ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue()); ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue()); + ui->enable_all_controllers->setChecked(Settings::values.enable_all_controllers.GetValue()); ui->enable_graphics_debugging->setEnabled(runtime_lock); ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); ui->enable_shader_feedback->setEnabled(runtime_lock); @@ -67,6 +68,7 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.quest_flag = ui->quest_flag->isChecked(); Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); + Settings::values.enable_all_controllers = ui->enable_all_controllers->isChecked(); Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index b884a56b0..0f3b51c8d 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -198,6 +198,13 @@ + + + + Enable all Controller Types + + + diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index ec071d6ec..16284d5a6 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -947,6 +947,40 @@ void ConfigureInputPlayer::SetConnectableControllers() { Core::HID::NpadStyleIndex::GameCube); ui->comboControllerType->addItem(tr("GameCube Controller")); } + + // Disable all unsupported controllers + if (!Settings::values.enable_all_controllers) { + return; + } + if (enable_all || npad_style_set.palma == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::Pokeball); + ui->comboControllerType->addItem(tr("Poke Ball Plus")); + } + + if (enable_all || npad_style_set.lark == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::NES); + ui->comboControllerType->addItem(tr("NES Controller")); + } + + if (enable_all || npad_style_set.lucia == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::SNES); + ui->comboControllerType->addItem(tr("SNES Controller")); + } + + if (enable_all || npad_style_set.lagoon == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::N64); + ui->comboControllerType->addItem(tr("N64 Controller")); + } + + if (enable_all || npad_style_set.lager == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::SegaGenesis); + ui->comboControllerType->addItem(tr("Sega Genesis")); + } }; if (!is_powered_on) { From 50d8e753c525f8f00a67678c56351eccf72aa1f4 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 25 Nov 2021 20:36:44 -0600 Subject: [PATCH 141/291] core/pdm: Stub QueryPlayStatisticsByApplicationIdAndUserAccountId Used in checkpoint homebrew --- src/core/CMakeLists.txt | 2 + src/core/hle/service/ns/ns.cpp | 3 ++ src/core/hle/service/ns/pdm_qry.cpp | 69 +++++++++++++++++++++++++++++ src/core/hle/service/ns/pdm_qry.h | 33 ++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 src/core/hle/service/ns/pdm_qry.cpp create mode 100644 src/core/hle/service/ns/pdm_qry.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 582c15f7e..eee8e2ccd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -479,6 +479,8 @@ add_library(core STATIC hle/service/ns/language.h hle/service/ns/ns.cpp hle/service/ns/ns.h + hle/service/ns/pdm_qry.cpp + hle/service/ns/pdm_qry.h hle/service/ns/pl_u.cpp hle/service/ns/pl_u.h hle/service/nvdrv/devices/nvdevice.h diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 64ffc8572..0d6fab746 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -12,6 +12,7 @@ #include "core/hle/service/ns/errors.h" #include "core/hle/service/ns/language.h" #include "core/hle/service/ns/ns.h" +#include "core/hle/service/ns/pdm_qry.h" #include "core/hle/service/ns/pl_u.h" #include "core/hle/service/set/set.h" @@ -738,6 +739,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp new file mode 100644 index 000000000..e2fab5c3f --- /dev/null +++ b/src/core/hle/service/ns/pdm_qry.cpp @@ -0,0 +1,69 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include + +#include "common/logging/log.h" +#include "common/uuid.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/ns/pdm_qry.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::NS { + +PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "QueryAppletEvent"}, + {1, nullptr, "QueryPlayStatistics"}, + {2, nullptr, "QueryPlayStatisticsByUserAccountId"}, + {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"}, + {4, nullptr, "QueryPlayStatisticsByApplicationId"}, + {5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"}, + {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"}, + {7, nullptr, "QueryLastPlayTimeV0"}, + {8, nullptr, "QueryPlayEvent"}, + {9, nullptr, "GetAvailablePlayEventRange"}, + {10, nullptr, "QueryAccountEvent"}, + {11, nullptr, "QueryAccountPlayEvent"}, + {12, nullptr, "GetAvailableAccountPlayEventRange"}, + {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"}, + {14, nullptr, "QueryRecentlyPlayedApplication"}, + {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"}, + {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"}, + {17, nullptr, "QueryLastPlayTime"}, + {18, nullptr, "QueryApplicationPlayStatisticsForSystem"}, + {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +PDM_QRY::~PDM_QRY() = default; + +void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown = rp.Pop(); + rp.Pop(); // Padding + const auto application_id = rp.Pop(); + const auto user_account_uid = rp.PopRaw(); + + // TODO(German77): Read statistics of the game + PlayStatistics statistics{ + .application_id = application_id, + .total_launches = 1, + }; + + LOG_WARNING(Service_NS, + "(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}", + unknown, application_id, user_account_uid.Format()); + + IPC::ResponseBuilder rb{ctx, 12}; + rb.Push(ResultSuccess); + rb.PushRaw(statistics); +} + +} // namespace Service::NS diff --git a/src/core/hle/service/ns/pdm_qry.h b/src/core/hle/service/ns/pdm_qry.h new file mode 100644 index 000000000..516136314 --- /dev/null +++ b/src/core/hle/service/ns/pdm_qry.h @@ -0,0 +1,33 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::NS { + +struct PlayStatistics { + u64 application_id{}; + u32 first_entry_index{}; + u32 first_timestamp_user{}; + u32 first_timestamp_network{}; + u32 last_entry_index{}; + u32 last_timestamp_user{}; + u32 last_timestamp_network{}; + u32 play_time_in_minutes{}; + u32 total_launches{}; +}; +static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size"); + +class PDM_QRY final : public ServiceFramework { +public: + explicit PDM_QRY(Core::System& system_); + ~PDM_QRY() override; + +private: + void QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::NS From 54f007efc6ed311a8356238ea136b9744b68eb75 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 25 Nov 2021 20:39:38 -0600 Subject: [PATCH 142/291] core/ns: Implement GetReadOnlyApplicationControlDataInterface Used in checkpoint homebrew --- src/core/hle/service/ns/ns.cpp | 20 +++++++++++++++++++- src/core/hle/service/ns/ns.h | 7 +++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 0d6fab746..382ddcae5 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -571,11 +571,29 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) IFactoryResetInterface::~IFactoryResetInterface() = default; +IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( + Core::System& system_) + : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetApplicationControlData"}, + {1, nullptr, "GetApplicationDesiredLanguage"}, + {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, + {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, + {4, nullptr, "SelectApplicationDesiredLanguage"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; + NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { // clang-format off static const FunctionInfo functions[] = { {7988, nullptr, "GetDynamicRightsInterface"}, - {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"}, + {7989, &NS::PushInterface, "GetReadOnlyApplicationControlDataInterface"}, {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, {7992, &NS::PushInterface, "GetECommerceInterface"}, {7993, &NS::PushInterface, "GetApplicationVersionInterface"}, diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 218eec3ec..43540b0fb 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -74,6 +74,13 @@ public: ~IFactoryResetInterface() override; }; +class IReadOnlyApplicationControlDataInterface final + : public ServiceFramework { +public: + explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); + ~IReadOnlyApplicationControlDataInterface() override; +}; + class NS final : public ServiceFramework { public: explicit NS(const char* name, Core::System& system_); From 5a3463bc2b1489dda6b5fe90110f9260f6b68463 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Nov 2021 23:49:56 +0100 Subject: [PATCH 143/291] Texture Cache: Secure insertions against deletions. --- src/video_core/texture_cache/texture_cache.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index f24de9a38..565b99254 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1137,8 +1137,11 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( } while (has_deleted_images); if (GetFormatType(dst_info.format) != SurfaceType::ColorTexture) { // Make sure the images are depth and/or stencil textures. - src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{}); - dst_id = FindOrInsertImage(dst_info, dst_addr, RelaxedOptions{}); + do { + has_deleted_images = false; + src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{}); + dst_id = FindOrInsertImage(dst_info, dst_addr, RelaxedOptions{}); + } while (has_deleted_images); } return BlitImages{ .dst_id = dst_id, @@ -1196,7 +1199,14 @@ template ImageViewId TextureCache

::FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr, bool is_clear) { const auto options = is_clear ? RelaxedOptions::Samples : RelaxedOptions{}; - const ImageId image_id = FindOrInsertImage(info, gpu_addr, options); + ImageId image_id{}; + bool delete_state = has_deleted_images; + do { + has_deleted_images = false; + image_id = FindOrInsertImage(info, gpu_addr, options); + delete_state |= has_deleted_images; + } while (has_deleted_images); + has_deleted_images = delete_state; if (!image_id) { return NULL_IMAGE_VIEW_ID; } From dcc468555758531016eec2ba61bbc5dfdc86f6f6 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 28 Nov 2021 21:03:42 -0600 Subject: [PATCH 144/291] qt_controller: Fix input when the controller applet is ignored --- src/yuzu/applets/qt_controller.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 589e0577a..7e80e7836 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -205,6 +205,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( // If all the parameters are met AND only allows a single player, // stop the constructor here as we do not need to continue. if (CheckIfParametersMet() && parameters.enable_single_mode) { + for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { + system.HIDCore().GetEmulatedControllerByIndex(player_index)->DisableConfiguration(); + } return; } From 524a9baa7ea33125d5e6ba48f277c81fb7a612e3 Mon Sep 17 00:00:00 2001 From: Feng Chen Date: Mon, 29 Nov 2021 12:39:37 +0800 Subject: [PATCH 145/291] Add missing pixel format mapping --- src/video_core/texture_cache/format_lookup_table.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp index ddfb726fe..afa807d5d 100644 --- a/src/video_core/texture_cache/format_lookup_table.cpp +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -139,6 +139,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, return PixelFormat::D16_UNORM; case Hash(TextureFormat::S8D24, UINT, UNORM, UNORM, UNORM, LINEAR): return PixelFormat::S8_UINT_D24_UNORM; + case Hash(TextureFormat::S8D24, UINT, UNORM, UINT, UINT, LINEAR): + return PixelFormat::S8_UINT_D24_UNORM; case Hash(TextureFormat::R8G24, UINT, UNORM, UNORM, UNORM, LINEAR): return PixelFormat::S8_UINT_D24_UNORM; case Hash(TextureFormat::D32S8, FLOAT, UINT, UNORM, UNORM, LINEAR): From b9b28c0457e81d80fc51670b88692a062ea9e08e Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 16:16:05 -0500 Subject: [PATCH 146/291] core: hid: Cleanup and amend documentation --- src/core/hid/emulated_console.h | 26 +++++++------- src/core/hid/emulated_controller.h | 58 +++++++++++++++--------------- src/core/hid/emulated_devices.h | 38 ++++++++++---------- src/core/hid/input_converter.h | 23 ++++++------ 4 files changed, 76 insertions(+), 69 deletions(-) diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 25c183eee..67981b844 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -78,7 +78,7 @@ struct ConsoleUpdateCallback { class EmulatedConsole { public: /** - * Contains all input data related to the console like motion and touch input + * Contains all input data within the emulated switch console tablet such as touch and motion */ EmulatedConsole(); ~EmulatedConsole(); @@ -89,14 +89,16 @@ public: /// Removes all callbacks created from input devices void UnloadInput(); - /// Sets the emulated console into configuring mode. Locking all HID service events from being - /// moddified + /** + * Sets the emulated console into configuring mode + * This prevents the modification of the HID state of the emulated console by input commands + */ void EnableConfiguration(); - /// Returns the emulated console to the normal behaivour + /// Returns the emulated console into normal mode, allowing the modification of the HID state void DisableConfiguration(); - /// Returns true if the emulated console is on configuring mode + /// Returns true if the emulated console is in configuring mode bool IsConfiguring() const; /// Reload all input devices @@ -116,7 +118,7 @@ public: /** * Updates the current mapped motion device - * @param ParamPackage with controller data to be mapped + * @param param ParamPackage with controller data to be mapped */ void SetMotionParam(Common::ParamPackage param); @@ -134,14 +136,14 @@ public: /** * Adds a callback to the list of events - * @param ConsoleUpdateCallback that will be triggered + * @param update_callback A ConsoleUpdateCallback that will be triggered * @return an unique key corresponding to the callback index in the list */ int SetCallback(ConsoleUpdateCallback update_callback); /** * Removes a callback from the list stopping any future events to this object - * @param Key corresponding to the callback index in the list + * @param key Key corresponding to the callback index in the list */ void DeleteCallback(int key); @@ -151,20 +153,20 @@ private: /** * Updates the motion status of the console - * @param A CallbackStatus containing gyro and accelerometer data + * @param callback A CallbackStatus containing gyro and accelerometer data */ void SetMotion(Common::Input::CallbackStatus callback); /** * Updates the touch status of the console - * @param callback: A CallbackStatus containing the touch position - * @param index: Finger ID to be updated + * @param callback A CallbackStatus containing the touch position + * @param index Finger ID to be updated */ void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the console status - * @param Input type of the event to trigger + * @param type Input type of the event to trigger */ void TriggerOnChange(ConsoleTriggerType type); diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 2c5d51bc8..5887e3e38 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -132,8 +132,8 @@ struct ControllerUpdateCallback { class EmulatedController { public: /** - * Contains all input data related to this controller. Like buttons, joysticks, motion. - * @param Npad id type for this specific controller + * Contains all input data (buttons, joysticks, vibration, and motion) within this controller. + * @param npad_id_type npad id type for this specific controller */ explicit EmulatedController(NpadIdType npad_id_type_); ~EmulatedController(); @@ -155,7 +155,7 @@ public: /** * Gets the NpadStyleIndex for this controller - * @param If true tmp_npad_type will be returned + * @param get_temporary_value If true tmp_npad_type will be returned * @return NpadStyleIndex set on the controller */ NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const; @@ -168,7 +168,7 @@ public: /** * Is the emulated connected - * @param If true tmp_is_connected will be returned + * @param get_temporary_value If true tmp_is_connected will be returned * @return true if the controller has the connected status */ bool IsConnected(bool get_temporary_value = false) const; @@ -179,14 +179,16 @@ public: /// Removes all callbacks created from input devices void UnloadInput(); - /// Sets the emulated console into configuring mode. Locking all HID service events from being - /// moddified + /** + * Sets the emulated controller into configuring mode + * This prevents the modification of the HID state of the emulated controller by input commands + */ void EnableConfiguration(); - /// Returns the emulated console to the normal behaivour + /// Returns the emulated controller into normal mode, allowing the modification of the HID state void DisableConfiguration(); - /// Returns true if the emulated device is on configuring mode + /// Returns true if the emulated controller is in configuring mode bool IsConfiguring() const; /// Reload all input devices @@ -215,19 +217,19 @@ public: /** * Updates the current mapped button device - * @param ParamPackage with controller data to be mapped + * @param param ParamPackage with controller data to be mapped */ void SetButtonParam(std::size_t index, Common::ParamPackage param); /** * Updates the current mapped stick device - * @param ParamPackage with controller data to be mapped + * @param param ParamPackage with controller data to be mapped */ void SetStickParam(std::size_t index, Common::ParamPackage param); /** * Updates the current mapped motion device - * @param ParamPackage with controller data to be mapped + * @param param ParamPackage with controller data to be mapped */ void SetMotionParam(std::size_t index, Common::ParamPackage param); @@ -270,13 +272,13 @@ public: /// Returns the latest battery status from the controller BatteryLevelState GetBattery() const; - /* + /** * Sends a specific vibration to the output device * @return returns true if vibration had no errors */ bool SetVibration(std::size_t device_index, VibrationValue vibration); - /* + /** * Sends a small vibration to the output device * @return returns true if SetVibration was successfull */ @@ -290,14 +292,14 @@ public: /** * Adds a callback to the list of events - * @param ConsoleUpdateCallback that will be triggered + * @param update_callback A ConsoleUpdateCallback that will be triggered * @return an unique key corresponding to the callback index in the list */ int SetCallback(ControllerUpdateCallback update_callback); /** * Removes a callback from the list stopping any future events to this object - * @param Key corresponding to the callback index in the list + * @param key Key corresponding to the callback index in the list */ void DeleteCallback(int key); @@ -310,43 +312,43 @@ private: /** * Updates the button status of the controller - * @param callback: A CallbackStatus containing the button status - * @param index: Button ID of the to be updated + * @param callback A CallbackStatus containing the button status + * @param index Button ID of the to be updated */ void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the analog stick status of the controller - * @param callback: A CallbackStatus containing the analog stick status - * @param index: stick ID of the to be updated + * @param callback A CallbackStatus containing the analog stick status + * @param index stick ID of the to be updated */ void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the trigger status of the controller - * @param callback: A CallbackStatus containing the trigger status - * @param index: trigger ID of the to be updated + * @param callback A CallbackStatus containing the trigger status + * @param index trigger ID of the to be updated */ void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the motion status of the controller - * @param callback: A CallbackStatus containing gyro and accelerometer data - * @param index: motion ID of the to be updated + * @param callback A CallbackStatus containing gyro and accelerometer data + * @param index motion ID of the to be updated */ void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the battery status of the controller - * @param callback: A CallbackStatus containing the battery status - * @param index: Button ID of the to be updated + * @param callback A CallbackStatus containing the battery status + * @param index Button ID of the to be updated */ void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the controller status - * @param type: Input type of the event to trigger - * @param is_service_update: indicates if this event should be sended to only services + * @param type Input type of the event to trigger + * @param is_service_update indicates if this event should only be sent to HID services */ void TriggerOnChange(ControllerTriggerType type, bool is_service_update); @@ -357,7 +359,7 @@ private: f32 motion_sensitivity{0.01f}; bool force_update_motion{false}; - // Temporary values to avoid doing changes while the controller is on configuration mode + // Temporary values to avoid doing changes while the controller is in configuring mode NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; bool tmp_is_connected{false}; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 05a945d08..d4f457651 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -75,7 +75,7 @@ class EmulatedDevices { public: /** * Contains all input data related to external devices that aren't necesarily a controller - * like keyboard and mouse + * This includes devices such as the keyboard or mouse */ EmulatedDevices(); ~EmulatedDevices(); @@ -86,14 +86,16 @@ public: /// Removes all callbacks created from input devices void UnloadInput(); - /// Sets the emulated console into configuring mode. Locking all HID service events from being - /// moddified + /** + * Sets the emulated devices into configuring mode + * This prevents the modification of the HID state of the emulated devices by input commands + */ void EnableConfiguration(); - /// Returns the emulated console to the normal behaivour + /// Returns the emulated devices into normal mode, allowing the modification of the HID state void DisableConfiguration(); - /// Returns true if the emulated device is on configuring mode + /// Returns true if the emulated device is in configuring mode bool IsConfiguring() const; /// Reload all input devices @@ -134,14 +136,14 @@ public: /** * Adds a callback to the list of events - * @param InterfaceUpdateCallback that will be triggered + * @param update_callback InterfaceUpdateCallback that will be triggered * @return an unique key corresponding to the callback index in the list */ int SetCallback(InterfaceUpdateCallback update_callback); /** * Removes a callback from the list stopping any future events to this object - * @param Key corresponding to the callback index in the list + * @param key Key corresponding to the callback index in the list */ void DeleteCallback(int key); @@ -151,42 +153,42 @@ private: /** * Updates the touch status of the keyboard device - * @param callback: A CallbackStatus containing the key status - * @param index: key ID to be updated + * @param callback A CallbackStatus containing the key status + * @param index key ID to be updated */ void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the keyboard status of the keyboard device - * @param callback: A CallbackStatus containing the modifier key status - * @param index: modifier key ID to be updated + * @param callback A CallbackStatus containing the modifier key status + * @param index modifier key ID to be updated */ void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the mouse button status of the mouse device - * @param callback: A CallbackStatus containing the button status - * @param index: Button ID to be updated + * @param callback A CallbackStatus containing the button status + * @param index Button ID to be updated */ void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the mouse wheel status of the mouse device - * @param callback: A CallbackStatus containing the wheel status - * @param index: wheel ID to be updated + * @param callback A CallbackStatus containing the wheel status + * @param index wheel ID to be updated */ void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the mouse position status of the mouse device - * @param callback: A CallbackStatus containing the position status - * @param index: stick ID to be updated + * @param callback A CallbackStatus containing the position status + * @param index stick ID to be updated */ void SetMouseStick(Common::Input::CallbackStatus callback); /** * Triggers a callback that something has changed on the device status - * @param Input type of the event to trigger + * @param type Input type of the event to trigger */ void TriggerOnChange(DeviceTriggerType type); diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 1492489d7..d24582226 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -21,7 +21,7 @@ namespace Core::HID { /** * Converts raw input data into a valid battery status. * - * @param Supported callbacks: Analog, Battery, Trigger. + * @param callback Supported callbacks: Analog, Battery, Trigger. * @return A valid BatteryStatus object. */ Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback); @@ -29,7 +29,7 @@ Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackSta /** * Converts raw input data into a valid button status. Applies invert properties to the output. * - * @param Supported callbacks: Analog, Button, Trigger. + * @param callback Supported callbacks: Analog, Button, Trigger. * @return A valid TouchStatus object. */ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback); @@ -37,7 +37,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu /** * Converts raw input data into a valid motion status. * - * @param Supported callbacks: Motion. + * @param callback Supported callbacks: Motion. * @return A valid TouchStatus object. */ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback); @@ -46,7 +46,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert * properties to the output. * - * @param Supported callbacks: Stick. + * @param callback Supported callbacks: Stick. * @return A valid StickStatus object. */ Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback); @@ -54,7 +54,7 @@ Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& /** * Converts raw input data into a valid touch status. * - * @param Supported callbacks: Touch. + * @param callback Supported callbacks: Touch. * @return A valid TouchStatus object. */ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback); @@ -63,7 +63,7 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and * invert properties to the output. Button status uses the threshold property if necessary. * - * @param Supported callbacks: Analog, Button, Trigger. + * @param callback Supported callbacks: Analog, Button, Trigger. * @return A valid TriggerStatus object. */ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); @@ -72,22 +72,23 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta * Converts raw input data into a valid analog status. Applies offset, deadzone, range and * invert properties to the output. * - * @param Supported callbacks: Analog. + * @param callback Supported callbacks: Analog. * @return A valid AnalogStatus object. */ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); /** * Converts raw analog data into a valid analog value - * @param An analog object containing raw data and properties, bool that determines if the value - * needs to be clamped between -1.0f and 1.0f. + * @param analog An analog object containing raw data and properties + * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. */ void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value); /** * Converts raw stick data into a valid stick value - * @param Two analog objects containing raw data and properties, bool that determines if the value - * needs to be clamped into the unit circle. + * @param analog_x raw analog data and properties for the x-axis + * @param analog_y raw analog data and properties for the y-axis + * @param clamp_value bool that determines if the value needs to be clamped into the unit circle. */ void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, bool clamp_value); From 04f48f0120f7f7f3f573ef13aa0feba88aa3172c Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 16:17:55 -0500 Subject: [PATCH 147/291] core: hid: Mark constructors as explicit --- src/core/hid/emulated_console.h | 2 +- src/core/hid/emulated_devices.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 67981b844..bb3d7ab90 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -80,7 +80,7 @@ public: /** * Contains all input data within the emulated switch console tablet such as touch and motion */ - EmulatedConsole(); + explicit EmulatedConsole(); ~EmulatedConsole(); YUZU_NON_COPYABLE(EmulatedConsole); diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index d4f457651..c72327681 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -77,7 +77,7 @@ public: * Contains all input data related to external devices that aren't necesarily a controller * This includes devices such as the keyboard or mouse */ - EmulatedDevices(); + explicit EmulatedDevices(); ~EmulatedDevices(); YUZU_NON_COPYABLE(EmulatedDevices); From 410df5446eb23e75582020790bce2e8241da88ff Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:22:59 -0500 Subject: [PATCH 148/291] general: Fix handheld typo --- src/core/hle/service/hid/controllers/npad.cpp | 2 +- .../configuration/configure_input_player.cpp | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 04b3a68c3..35dbf12df 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -635,7 +635,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing // This buffer only is updated on handheld on HW npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); } else { - // Hanheld doesn't update this buffer on HW + // Handheld doesn't update this buffer on HW npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 16284d5a6..34099bc83 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -246,15 +246,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (player_index == 0) { auto* emulated_controller_p1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = + auto* emulated_controller_handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->SaveCurrentConfig(); emulated_controller_p1->EnableConfiguration(); - emulated_controller_hanheld->SaveCurrentConfig(); - emulated_controller_hanheld->EnableConfiguration(); - if (emulated_controller_hanheld->IsConnected(true)) { + emulated_controller_handheld->SaveCurrentConfig(); + emulated_controller_handheld->EnableConfiguration(); + if (emulated_controller_handheld->IsConnected(true)) { emulated_controller_p1->Disconnect(); - emulated_controller = emulated_controller_hanheld; + emulated_controller = emulated_controller_handheld; } else { emulated_controller = emulated_controller_p1; } @@ -590,19 +590,19 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (player_index == 0) { auto* emulated_controller_p1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = + auto* emulated_controller_handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); bool is_connected = emulated_controller->IsConnected(true); emulated_controller_p1->SetNpadStyleIndex(type); - emulated_controller_hanheld->SetNpadStyleIndex(type); + emulated_controller_handheld->SetNpadStyleIndex(type); if (is_connected) { if (type == Core::HID::NpadStyleIndex::Handheld) { emulated_controller_p1->Disconnect(); - emulated_controller_hanheld->Connect(); - emulated_controller = emulated_controller_hanheld; + emulated_controller_handheld->Connect(); + emulated_controller = emulated_controller_handheld; } else { - emulated_controller_hanheld->Disconnect(); + emulated_controller_handheld->Disconnect(); emulated_controller_p1->Connect(); emulated_controller = emulated_controller_p1; } @@ -650,10 +650,10 @@ ConfigureInputPlayer::~ConfigureInputPlayer() { if (player_index == 0) { auto* emulated_controller_p1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = + auto* emulated_controller_handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->DisableConfiguration(); - emulated_controller_hanheld->DisableConfiguration(); + emulated_controller_handheld->DisableConfiguration(); } else { emulated_controller->DisableConfiguration(); } @@ -663,14 +663,14 @@ void ConfigureInputPlayer::ApplyConfiguration() { if (player_index == 0) { auto* emulated_controller_p1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = + auto* emulated_controller_handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); emulated_controller_p1->DisableConfiguration(); emulated_controller_p1->SaveCurrentConfig(); emulated_controller_p1->EnableConfiguration(); - emulated_controller_hanheld->DisableConfiguration(); - emulated_controller_hanheld->SaveCurrentConfig(); - emulated_controller_hanheld->EnableConfiguration(); + emulated_controller_handheld->DisableConfiguration(); + emulated_controller_handheld->SaveCurrentConfig(); + emulated_controller_handheld->EnableConfiguration(); return; } emulated_controller->DisableConfiguration(); From 940375dfbbbb14480de042c96128aaded894e827 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:59:58 -0500 Subject: [PATCH 149/291] core: hid: hid_core: Add (Enable/DIsable)AllControllerConfiguration --- src/core/hid/hid_core.cpp | 26 ++++++++++++++++++++++++++ src/core/hid/hid_core.h | 6 ++++++ 2 files changed, 32 insertions(+) diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 741a69c3c..946adde00 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -135,6 +135,32 @@ NpadIdType HIDCore::GetFirstNpadId() const { return NpadIdType::Player1; } +void HIDCore::EnableAllControllerConfiguration() { + player_1->EnableConfiguration(); + player_2->EnableConfiguration(); + player_3->EnableConfiguration(); + player_4->EnableConfiguration(); + player_5->EnableConfiguration(); + player_6->EnableConfiguration(); + player_7->EnableConfiguration(); + player_8->EnableConfiguration(); + other->EnableConfiguration(); + handheld->EnableConfiguration(); +} + +void HIDCore::DisableAllControllerConfiguration() { + player_1->DisableConfiguration(); + player_2->DisableConfiguration(); + player_3->DisableConfiguration(); + player_4->DisableConfiguration(); + player_5->DisableConfiguration(); + player_6->DisableConfiguration(); + player_7->DisableConfiguration(); + player_8->DisableConfiguration(); + other->DisableConfiguration(); + handheld->DisableConfiguration(); +} + void HIDCore::ReloadInputDevices() { player_1->ReloadFromSettings(); player_2->ReloadFromSettings(); diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 609f40f3b..140a0e962 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -45,6 +45,12 @@ public: /// Returns the first connected npad id NpadIdType GetFirstNpadId() const; + /// Sets all emulated controllers into configuring mode. + void EnableAllControllerConfiguration(); + + /// Sets all emulated controllers into normal mode. + void DisableAllControllerConfiguration(); + /// Reloads all input devices from settings void ReloadInputDevices(); From b86fcf7c316d8a024f6ed90e46a20fb977b55f5e Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:01:05 -0500 Subject: [PATCH 150/291] qt_controller: Make use of (Enable/Disable)AllControllerConfiguration This also moves the use of DisableConfiguration to the destructor. --- src/yuzu/applets/qt_controller.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 7e80e7836..c5685db2e 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -139,7 +139,6 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( DisableUnsupportedPlayers(); for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { - system.HIDCore().GetEmulatedControllerByIndex(player_index)->EnableConfiguration(); SetEmulatedControllers(player_index); } @@ -205,9 +204,6 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( // If all the parameters are met AND only allows a single player, // stop the constructor here as we do not need to continue. if (CheckIfParametersMet() && parameters.enable_single_mode) { - for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { - system.HIDCore().GetEmulatedControllerByIndex(player_index)->DisableConfiguration(); - } return; } @@ -221,7 +217,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( resize(0, 0); } -QtControllerSelectorDialog::~QtControllerSelectorDialog() = default; +QtControllerSelectorDialog::~QtControllerSelectorDialog() { + system.HIDCore().DisableAllControllerConfiguration(); +} int QtControllerSelectorDialog::exec() { if (parameters_met && parameters.enable_single_mode) { @@ -237,12 +235,11 @@ void QtControllerSelectorDialog::ApplyConfiguration() { Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); - for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { - system.HIDCore().GetEmulatedControllerByIndex(player_index)->DisableConfiguration(); - } } void QtControllerSelectorDialog::LoadConfiguration() { + system.HIDCore().EnableAllControllerConfiguration(); + const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); From bfac21fca10e1bc2f6888ce8592dc58bd9f2ffc3 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:20:34 -0500 Subject: [PATCH 151/291] core: hid: hid_types: Add "All" to NpadButton This represents a bitmask for all pressed buttons --- src/core/hid/hid_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index acf54e233..780659b86 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -63,6 +63,8 @@ enum class NpadButton : u64 { LagonCUp = 1ULL << 32, LagonCRight = 1ULL << 33, LagonCDown = 1ULL << 34, + + All = 0xFFFFFFFFFFFFFFFFULL, }; DECLARE_ENUM_FLAG_OPERATORS(NpadButton); From 322339a5fd4ed78826ecea42e71bc179afb7b5a7 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:23:52 -0500 Subject: [PATCH 152/291] npad: Return NpadButton in GetAndResetPressState We were previously truncating this to a u32 as there were no known buttons that used the full 64 bits of this type. Fix this now that we know they are used. --- src/core/hle/service/hid/controllers/npad.cpp | 6 +++--- src/core/hle/service/hid/controllers/npad.h | 4 ++-- src/core/memory/cheat_engine.cpp | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 35dbf12df..6916930f7 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -510,7 +510,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.r_stick = pad_state.r_stick; npad.system_ext_lifo.WriteNextEntry(pad_state); - press_state |= static_cast(pad_state.npad_buttons.raw); + press_state |= static_cast(pad_state.npad_buttons.raw); std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), &controller.shared_memory_entry, sizeof(NpadInternalState)); @@ -1149,8 +1149,8 @@ void Controller_NPad::ClearAllControllers() { } } -u32 Controller_NPad::GetAndResetPressState() { - return press_state.exchange(0); +Core::HID::NpadButton Controller_NPad::GetAndResetPressState() { + return static_cast(press_state.exchange(0)); } bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 9fa113bb6..de5fa5a64 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -179,7 +179,7 @@ public: // Logical OR for all buttons presses on all controllers // Specifically for cheat engine and other features. - u32 GetAndResetPressState(); + Core::HID::NpadButton GetAndResetPressState(); static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); @@ -503,7 +503,7 @@ private: NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; - std::atomic press_state{}; + std::atomic press_state{}; std::array controller_data{}; KernelHelpers::ServiceContext& service_context; diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 20f0e90f5..12446c9ac 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -19,7 +19,6 @@ namespace Core::Memory { namespace { constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; -constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { auto end_index = start_index; @@ -61,7 +60,7 @@ u64 StandardVmCallbacks::HidKeysDown() { applet_resource ->GetController(Service::HID::HidController::NPad) .GetAndResetPressState(); - return press_state & KEYPAD_BITMASK; + return static_cast(press_state & HID::NpadButton::All); } void StandardVmCallbacks::DebugLog(u8 id, u64 value) { From 5deecd714b78233a4cec207b67d2a32c2defbf0a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:26:52 -0500 Subject: [PATCH 153/291] input_interpreter: Make use of NpadButton instead of a u64 Allows us to be more explicit with the representation of button states and use the provided bit manipulation operators --- src/core/hid/input_interpreter.cpp | 16 ++++++++-------- src/core/hid/input_interpreter.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp index 870422d82..2dbda8814 100644 --- a/src/core/hid/input_interpreter.cpp +++ b/src/core/hid/input_interpreter.cpp @@ -20,7 +20,7 @@ InputInterpreter::InputInterpreter(Core::System& system) InputInterpreter::~InputInterpreter() = default; void InputInterpreter::PollInput() { - const u64 button_state = npad.GetAndResetPressState(); + const auto button_state = npad.GetAndResetPressState(); previous_index = current_index; current_index = (current_index + 1) % button_states.size(); @@ -32,30 +32,30 @@ void InputInterpreter::ResetButtonStates() { previous_index = 0; current_index = 0; - button_states[0] = 0xFFFFFFFFFFFFFFFF; + button_states[0] = Core::HID::NpadButton::All; for (std::size_t i = 1; i < button_states.size(); ++i) { - button_states[i] = 0; + button_states[i] = Core::HID::NpadButton::None; } } bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const { - return (button_states[current_index] & static_cast(button)) != 0; + return True(button_states[current_index] & button); } bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const { - const bool current_press = (button_states[current_index] & static_cast(button)) != 0; - const bool previous_press = (button_states[previous_index] & static_cast(button)) != 0; + const bool current_press = True(button_states[current_index] & button); + const bool previous_press = True(button_states[previous_index] & button); return current_press && !previous_press; } bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const { - u64 held_buttons{button_states[0]}; + Core::HID::NpadButton held_buttons{button_states[0]}; for (std::size_t i = 1; i < button_states.size(); ++i) { held_buttons &= button_states[i]; } - return (held_buttons & static_cast(button)) != 0; + return True(held_buttons & button); } diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h index 1c2e02142..70c34d474 100644 --- a/src/core/hid/input_interpreter.h +++ b/src/core/hid/input_interpreter.h @@ -105,7 +105,7 @@ private: Service::HID::Controller_NPad& npad; /// Stores 9 consecutive button states polled from HID. - std::array button_states{}; + std::array button_states{}; std::size_t previous_index{}; std::size_t current_index{}; From e4492a9a821659cd0c4e874234020cdb630a108b Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Mon, 29 Nov 2021 21:03:47 -0600 Subject: [PATCH 154/291] input_common: Fix error with thread name --- src/input_common/drivers/sdl_driver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 90128b6cf..1052ed394 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -388,8 +388,6 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { - Common::SetCurrentThreadName("yuzu:input:SDL"); - if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); @@ -422,6 +420,7 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin initialized = true; if (start_thread) { poll_thread = std::thread([this] { + Common::SetCurrentThreadName("yuzu:input:SDL"); using namespace std::chrono_literals; while (initialized) { SDL_PumpEvents(); From 505ae5ea1bec7e17dba3d1b4382a839797eff83d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 30 Nov 2021 12:19:21 -0500 Subject: [PATCH 155/291] service: friend: Implement GetCompletionEvent - Used by Super Bomberman R Online --- src/core/hle/service/friend/friend.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 68c9240ae..3c36f4085 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -17,10 +17,11 @@ namespace Service::Friend { class IFriendService final : public ServiceFramework { public: - explicit IFriendService(Core::System& system_) : ServiceFramework{system_, "IFriendService"} { + explicit IFriendService(Core::System& system_) + : ServiceFramework{system_, "IFriendService"}, service_context{system, "IFriendService"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetCompletionEvent"}, + {0, &IFriendService::GetCompletionEvent, "GetCompletionEvent"}, {1, nullptr, "Cancel"}, {10100, nullptr, "GetFriendListIds"}, {10101, &IFriendService::GetFriendList, "GetFriendList"}, @@ -109,6 +110,12 @@ public: // clang-format on RegisterHandlers(functions); + + completion_event = service_context.CreateEvent("IFriendService:CompletionEvent"); + } + + ~IFriendService() override { + service_context.CloseEvent(completion_event); } private: @@ -129,6 +136,14 @@ private: }; static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); + void GetCompletionEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Friend, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(completion_event->GetReadableEvent()); + } + void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { // This is safe to stub, as there should be no adverse consequences from reporting no // blocked users. @@ -179,6 +194,10 @@ private: rb.Push(0); // Friend count // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId" } + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* completion_event; }; class INotificationService final : public ServiceFramework { From 40317eccbaf6735609282bf17f5a09d2dee93ec2 Mon Sep 17 00:00:00 2001 From: The yuzu Community Date: Wed, 1 Dec 2021 02:21:55 +0000 Subject: [PATCH 156/291] Update translations (2021-12-01) --- dist/languages/ca.ts | 1646 ++++++----- dist/languages/cs.ts | 1664 ++++++----- dist/languages/da.ts | 1642 ++++++----- dist/languages/de.ts | 1666 ++++++----- dist/languages/es.ts | 2627 +++++++++-------- dist/languages/fr.ts | 1700 ++++++----- dist/languages/it.ts | 1678 ++++++----- dist/languages/ja_JP.ts | 1676 ++++++----- dist/languages/ko_KR.ts | 1682 ++++++----- dist/languages/nb.ts | 1634 ++++++----- dist/languages/nl.ts | 1654 ++++++----- dist/languages/pl.ts | 1650 ++++++----- dist/languages/pt_BR.ts | 1672 ++++++----- dist/languages/pt_PT.ts | 1648 ++++++----- dist/languages/ru_RU.ts | 1790 +++++++----- dist/languages/sv.ts | 1646 ++++++----- dist/languages/tr_TR.ts | 1797 +++++++----- dist/languages/vi_VN.ts | 6044 +++++++++++++++++++++++++++++++++++++++ dist/languages/zh_CN.ts | 1674 ++++++----- dist/languages/zh_TW.ts | 1852 ++++++------ 20 files changed, 24775 insertions(+), 14267 deletions(-) create mode 100644 dist/languages/vi_VN.ts diff --git a/dist/languages/ca.ts b/dist/languages/ca.ts index 9b58c6661..8ba93205d 100644 --- a/dist/languages/ca.ts +++ b/dist/languages/ca.ts @@ -656,7 +656,12 @@ p, li {white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -936,67 +941,78 @@ p, li {white-space: pre-wrap; } General - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Percentatge de Velocitat Límit - + % % - + Multicore CPU Emulation Emulació CPU Multinucli - + Confirm exit while emulation is running Confirmar la sortida mentre s'està executant l'emulació - + Prompt for user on game boot Sol·licitar l'usuari en l'arrencada del joc - + Pause emulation when in background Pausa l'emulació en segon pla - + Hide mouse on inactivity Ocultar el cursor del ratolí quan no està actiu - + Reset All Settings - + yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? @@ -1114,18 +1130,113 @@ p, li {white-space: pre-wrap; } Estirar a la finestra - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Utilitza un color de fons global - + Set background color: Configura un color de fons: - + Background Color: Color de Fons: @@ -1194,27 +1305,32 @@ p, li {white-space: pre-wrap; } + Automatic + + + + Default Valor Predeterminat - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1542,8 +1658,8 @@ p, li {white-space: pre-wrap; } - Other - Altre + Emulated Devices + @@ -1552,66 +1668,75 @@ p, li {white-space: pre-wrap; } - Emulate Analog with Keyboard Input - - - - - Enable mouse panning - - - - - Mouse sensitivity - - - - - % - - - - - - Advanced - Avançat - - - - Touchscreen - Pantalla Tàctil - - - Mouse Ratolí - - Motion / Touch - Moviment / Tàctil + + Touchscreen + Pantalla Tàctil - - - Configure - Configurar + + Advanced + Avançat - + Debug Controller Controlador de Depuració - + + + Configure + Configurar + + + + Other + Altre + + + + Emulate Analog with Keyboard Input + + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + + + + + % + + + + + Motion / Touch + Moviment / Tàctil + ConfigureInputPlayer @@ -1626,424 +1751,440 @@ p, li {white-space: pre-wrap; } Connectar Controlador - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Joycons Duals - - - - - Left Joycon - Joycon esquerra - - - - - Right Joycon - Joycon Dret - - - - - Handheld - Portàtil - - - + Input Device Dispositiu d'Entrada - - Any - Qualsevol - - - - Keyboard/Mouse - Teclat/Ratolí - - - + Profile Perfil - + Save Guardar - + New Nou - + Delete Esborrar - - + + Left Stick Palanca Esquerra - - - - - - + + + + + + Up Amunt - - - - - - - + + + + + + + Left Esquerra - - - - - - - + + + + + + + Right Dreta - - - - - - + + + + + + Down Abaix - - - - + + + + Pressed Pressionat - - - - + + + + Modifier Modificador - - + + Range Rang - - + + % % - - + + Deadzone: 0% Zona Morta: 0% - - + + Modifier Range: 0% Rang del Modificador: 0% - + D-Pad Creueta - - - + + + L L - - - + + + ZL ZL - - + + Minus Menys - - + + Capture Captura - - - + + + Plus Més - - + + Home Inici - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 - + Motion 2 - + Face Buttons Botons Frontals - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Palanca Dreta - - - - + + + + Clear - - - - + + + + [not set] - - + + Toggle button - - + + Invert button + + + + + + Invert axis + + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. - - Invert axis - - - - - + + Deadzone: %1% Zona Morta: %1% - - + + Modifier Range: %1% Rang del Modificador: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Joycons Duals + + + + Left Joycon + Joycon esquerra + + + + Right Joycon + Joycon Dret + + + + Handheld + Portàtil + + + GameCube Controller - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause - + Z - + Control Stick - + C-Stick - + Shake! - + [waiting] [esperant] - + New Profile - + Enter a profile name: - - + + Create Input Profile - + The given profile name is not valid! - + Failed to create the input profile "%1" - + Delete Input Profile - + Failed to delete the input profile "%1" - + Load Input Profile - + Failed to load the input profile "%1" - + Save Input Profile - + Failed to save the input profile "%1" @@ -2069,85 +2210,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch Configurar Moviment / Tàctil - - Mouse Motion - - - - - Sensitivity: - Sensibilitat: - - - + Touch Tàctil - + UDP Calibration: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configuració - - Use button mapping: - Utilitzar el mapeig de botons: + + Touch from button profile: + - + CemuhookUDP Config Configuració CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Pot utilitzar qualsevol font d'entrada UDP compatible amb Cemuhook per a proporcionar una entrada de moviment i de tacte. - + Server: Servidor: - + Port: Port: - + Learn More Més Informació - - + + Test Provar - + Add Server - + Remove Server @@ -2157,145 +2288,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Més Informació</span></a> - + %1:%2 - - - - - - + + + + + + yuzu - + Port number has invalid characters - + Port has to be in range 0 and 65353 - + IP address is not valid - + This UDP server already exists - + Unable to add more than 8 servers - + Testing Provant - + Configuring Configurant - + Test Successful Prova Exitosa - + Successfully received data from the server. S'han rebut dades des del servidor correctament. - + Test Failed Prova Fallida - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. No s'han pogut rebre dades vàlides des del servidor.<br>Si us plau, verifiqui que el servidor està configurat correctament i que la direcció i el port són correctes.  - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. La prova del UDP o la configuració de la calibració està en curs.<br>Si us plau, esperi a que acabi el procés. - - ConfigureMouseAdvanced - - - Configure Mouse - Configurar Ratolí - - - - Mouse Buttons - Botons del Ratolí - - - - Forward: - Endavant: - - - - Back: - Enrere: - - - - Left: - Esquerra: - - - - Middle: - Mig: - - - - Right: - Dreta: - - - - - Clear - Netejar - - - - Defaults - Valors Predeterminats - - - - [not set] - [no establert] - - - - Restore Default - Restaurar Valor Predeterminat - - - - [press key] - [pressioni una tecla] - - ConfigureNetwork @@ -3079,31 +3146,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3116,7 +3178,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - + Select TAS Load Directory... @@ -3178,37 +3240,37 @@ Arrossegui els punts per a canviar la posició, o faci doble clic a les cel·les Y - + New Profile Nou Perfil - + Enter the name for the new profile. Introdueixi el nom per al nou perfil. - + Delete Profile Esborrar Perfil - + Delete profile %1? Esborrar perfil %1? - + Rename Profile Renombrar Perfil - + New name: Nou nom: - + [press key] [pressioni una tecla] @@ -3628,12 +3690,12 @@ Arrossegui els punts per a canviar la posició, o faci doble clic a les cel·les ControllerDialog - + Controller P1 - + &Controller P1 @@ -3641,89 +3703,94 @@ Arrossegui els punts per a canviar la posició, o faci doble clic a les cel·les GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Es recullen dades anònimes</a> per ajudar a millorar yuzu. <br/><br/>Desitja compartir les seves dades d'ús amb nosaltres? - + Telemetry Telemetria - + Loading Web Applet... Carregant Web Applet... - - + + Disable Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built La quantitat de shaders que s'estan compilant actualment - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocitat d'emulació actual. Valors superiors o inferiors a 100% indiquen que l'emulació s'està executant més ràpidament o més lentament que a la Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quants fotogrames per segon està mostrant el joc actualment. Això variarà d'un joc a un altre i d'una escena a una altra. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Temps que costa emular un fotograma de la Switch, sense tenir en compte la limitació de fotogrames o la sincronització vertical. Per a una emulació òptima, aquest valor hauria de ser com a màxim de 16.67 ms. - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - + DOCK ACOBLAT - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files - - TAS Recording + + &Continue - - Overwrite file of player 1? + + &Pause @@ -3775,656 +3842,723 @@ Arrossegui els punts per a canviar la posició, o faci doble clic a les cel·les Ha ocorregut un error desconegut. Si us plau, consulti el registre per a més detalls. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Iniciar - - - + Save Data Dades de Jocs Guardats - + Mod Data Dades de Mods - + Error Opening %1 Folder Error Obrint la Carpeta %1 - - + + Folder does not exist! La carpeta no existeix! - + Error Opening Transferable Shader Cache Error Obrint el Cache Transferible de Shaders - + Failed to create the shader cache directory for this title. - + Contents Continguts - + Update Actualització - + DLC DLC - + Remove Entry Eliminar Entrada - + Remove Installed Game %1? Eliminar el joc instal·lat %1? - - - - - - + + + + + + Successfully Removed S'ha Eliminat Correctament - + Successfully removed the installed base game. S'ha eliminat correctament el joc base instal·lat. - - - + + + Error Removing %1 Error eliminant %1 - + The base game is not installed in the NAND and cannot be removed. El joc base no està instal·lat a la NAND i no pot ser eliminat. - + Successfully removed the installed update. S'ha eliminat correctament l'actualització instal·lada. - + There is no update installed for this title. No hi ha cap actualització instal·lada per aquest títol. - + There are no DLC installed for this title. No hi ha cap DLC instal·lat per aquest títol. - + Successfully removed %1 installed DLC. S'ha eliminat correctament %1 DLC instal·lat/s. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Eliminar la Configuració Personalitzada del Joc? - + Remove File Eliminar Arxiu - - + + Error Removing Transferable Shader Cache Error eliminant el Cache Transferible de Shaders - - + + A shader cache for this title does not exist. No existeix un cache de shaders per a aquest títol. - + Successfully removed the transferable shader cache. S'ha eliminat correctament el cache transferible de shaders. - + Failed to remove the transferable shader cache. No s'ha pogut eliminar la cache transferible de shaders. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Error Eliminant la Configuració Personalitzada - + A custom configuration for this title does not exist. No existeix una configuració personalitzada per aquest joc. - + Successfully removed the custom game configuration. S'ha eliminat correctament la configuració personalitzada del joc. - + Failed to remove the custom game configuration. No s'ha pogut eliminar la configuració personalitzada del joc. - - + + RomFS Extraction Failed! La extracció de RomFS ha fallat! - + There was an error copying the RomFS files or the user cancelled the operation. S'ha produït un error copiant els arxius RomFS o l'usuari ha cancel·lat la operació. - + Full Completa - + Skeleton Esquelet - + Select RomFS Dump Mode Seleccioni el Mode de Bolcat de RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Si us plau, seleccioni la forma en que desitja bolcar la RomFS.<br>Completa copiarà tots els arxius al nou directori mentre que<br>esquelet només crearà l'estructura de directoris. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Extraient RomFS... - - + + Cancel Cancel·la - + RomFS Extraction Succeeded! Extracció de RomFS Completada Correctament! - + The operation completed successfully. La operació s'ha completat correctament. - + Error Opening %1 Error Obrint %1 - + Select Directory Seleccionar Directori - + Properties Propietats - + The game properties could not be loaded. Les propietats del joc no s'han pogut carregar. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Executable de Switch (%1);;Tots els Arxius (*.*) - + Load File Carregar Arxiu - + Open Extracted ROM Directory Obrir el Directori de la ROM extreta - + Invalid Directory Selected Directori Seleccionat Invàlid - + The directory you have selected does not contain a 'main' file. El directori que ha seleccionat no conté un arxiu 'main'. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Arxiu de Switch Instal·lable (*.nca *.nsp *.xci);;Arxiu de Continguts Nintendo (*.nca);;Paquet d'enviament Nintendo (*.nsp);;Imatge de Cartutx NX (*.xci) - + Install Files Instal·lar Arxius - + %n file(s) remaining - + Installing file "%1"... Instal·lant arxiu "%1"... - - + + Install Results Resultats Instal·lació - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Aplicació de Sistema - + System Archive Arxiu de Sistema - + System Application Update Actualització de l'Aplicació del Sistema - + Firmware Package (Type A) Paquet de Firmware (Tipus A) - + Firmware Package (Type B) Paquet de Firmware (Tipus B) - + Game Joc - + Game Update Actualització Joc - + Game DLC DLC Joc - + Delta Title Títol Delta - + Select NCA Install Type... Seleccioni el Tipus d'Instal·lació NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Seleccioni el tipus de títol que desitja instal·lar aquest NCA com a: (En la majoria dels casos, el valor predeterminat 'Joc' està bé.) - + Failed to Install Ha Fallat la Instal·lació - + The title type you selected for the NCA is invalid. El tipus de títol seleccionat per el NCA és invàlid. - + File not found Arxiu no trobat - + File "%1" not found Arxiu "%1" no trobat - - - &Continue - - - - + OK - + Missing yuzu Account Falta el Compte de yuzu - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Per tal d'enviar un cas de prova de compatibilitat de joc, ha de vincular el seu compte de yuzu.<br><br/>Per a vincular el seu compte de yuzu, vagi a Emulació & gt; Configuració & gt; Web. - + Error opening URL Error obrint URL - + Unable to open the URL "%1". No es pot obrir la URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Arxiu Amiibo (%1);; Tots els Arxius (*.*) - + Load Amiibo Carregar Amiibo - + Error opening Amiibo data file Error obrint l'arxiu de dades d'Amiibo - + Unable to open Amiibo file "%1" for reading. No s'ha pogut obrir l'arxiu de dades d'Amiibo "%1" per a lectura. - + Error reading Amiibo data file Error llegint l'arxiu de dades d'Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. No s'han pogut llegir completament les dades d'Amiibo. S'esperava llegir %1 bytes, però només s'han pogut llegir %2 bytes. - + Error loading Amiibo data Error al carregar les dades d'Amiibo - + Unable to load Amiibo data. No s'han pogut carregar les dades d'Amiibo. - + Capture Screenshot Captura de Pantalla - + PNG Image (*.png) Imatge PNG (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Velocitat: %1% / %2% - + Speed: %1% Velocitat: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Joc: %1 FPS - + Frame: %1 ms Fotograma: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. El joc que està intentant carregar requereix d'arxius addicionals de la seva Switch abans de poder jugar. <br/><br/>Per a obtenir més informació sobre com bolcar aquests arxius, vagi a la següent pàgina de la wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Bolcar arxius del sistema i les fonts compartides des d'una Consola Switch</a>. <br/><br/>Desitja tornar a la llista de jocs? Continuar amb l'emulació pot provocar el tancament inesperat, dades de partides guardades corruptes o altres errors. - + yuzu was unable to locate a Switch system archive. %1 yuzu no ha pogut localitzar l'arxiu de sistema de la Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu no ha pogut localitzar un arxiu de sistema de la Switch: %1. %2 - + System Archive Not Found Arxiu del Sistema no Trobat - + System Archive Missing Falta Arxiu del Sistema - + yuzu was unable to locate the Switch shared fonts. %1 yuzu no ha pogut trobar les fonts compartides de la Switch. %1 - + Shared Fonts Not Found Fonts Compartides no Trobades - + Shared Font Missing Falten les Fonts Compartides - + Fatal Error Error Fatal - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu ha trobat un error fatal, consulti el registre per a obtenir més detalls. Per a més informació sobre com accedir al registre, consulti la següent pàgina: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Com carregar l'arxiu de registre?</a>.<br/><br/> Desitja tornar al llistat de jocs? Continuar amb l'emulació pot provocar el tancament inesperat, dades de partides guardades corruptes o altres errors. - + Fatal Error encountered Trobat Error Fatal - + Confirm Key Rederivation Confirmi la Clau de Rederivació - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4441,37 +4575,37 @@ i opcionalment faci còpies de seguretat. Això eliminarà els arxius de les claus generats automàticament i tornarà a executar el mòdul de derivació de claus. - + Missing fuses Falten fusibles - + - Missing BOOT0 - Falta BOOT0 - + - Missing BCPKG2-1-Normal-Main - Falta BCPKG2-1-Normal-Main - + - Missing PRODINFO - Falta PRODINFO - + Derivation Components Missing Falten Components de Derivació - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Falten components que poden impedir que la derivació de la clau es completi. <br>Si us plau, segueixi <a href='https://yuzu-emu.org/help/quickstart/'>la guia d'inici ràpid de yuzu</a> per a obtenir totes les seves claus i jocs.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4480,39 +4614,39 @@ Això pot prendre fins a un minut depenent del rendiment del seu sistema. - + Deriving Keys Derivant Claus - + Select RomFS Dump Target Seleccioni el Destinatari per a Bolcar el RomFS - + Please select which RomFS you would like to dump. Si us plau, seleccioni quin RomFS desitja bolcar. - + Are you sure you want to close yuzu? Està segur de que vol tancar yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Està segur de que vol aturar l'emulació? Qualsevol progrés no guardat es perdrà. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4524,38 +4658,38 @@ Desitja tancar-lo de totes maneres? GRenderWindow - + OpenGL not available! OpenGL no disponible! - + yuzu has not been compiled with OpenGL support. yuzu no ha estat compilat amb suport per OpenGL. - - + + Error while initializing OpenGL! Error al inicialitzar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4916,190 +5050,205 @@ d'inici. &Emulació - + &View &Veure - + &Reset Window Size - - Reset Window Size to &720p - - - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - - - Reset Window Size to 1080p - - - - + &Debugging - + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + &Tools - + + &TAS + + + + &Help &Ajuda - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit S&ortir - - &Start - &Iniciar - - - + &Pause &Pausar - + &Stop &Aturar - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Mostrar Barra d'Estat - + F&ullscreen - + &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + &Iniciar + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5141,10 +5290,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5175,142 +5329,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [no establert] - - Hat %1 %2 Rotació %1 %2 - - - - - - + + + + Axis %1%2 Eix %1%2 - Button %1 Botó %1 - - - + + + [unknown] [desconegut] - + + Left + + + + + Right + + + - Click 0 - Clic 0 + Down + - - Click 1 - Clic 1 + Up + - - Click 2 - Clic 2 + Z + - - Click 3 - Clic 3 + R + - - Click 4 - Clic 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 - - GC Axis %1%2 - Eix GC %1%2 - - - - GC Button %1 - Botó GC %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 + + + + %1%2Axis %3 - - %1Button %2 + + %1%2Axis %3,%4,%5 - - SDL Motion + + %1%2Motion %3 - - %1Click %2 + + + %1%2Button %3 - + [unused] [sense ús] @@ -5351,7 +5585,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5364,7 +5598,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons @@ -5377,7 +5611,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon @@ -5390,7 +5624,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon @@ -5418,7 +5652,7 @@ p, li { white-space: pre-wrap; } - + Handheld @@ -5539,7 +5773,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5623,13 +5857,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/cs.ts b/dist/languages/cs.ts index a2613e583..044b87ab8 100644 --- a/dist/languages/cs.ts +++ b/dist/languages/cs.ts @@ -658,7 +658,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -938,67 +943,78 @@ p, li { white-space: pre-wrap; } Obecné - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x x - + Limit Speed Percent Omezení rychlosti v procentech - + % % - + Multicore CPU Emulation Vícejádrová emulace CPU - + Confirm exit while emulation is running Potvrzovat exit při spuštěné emulaci - + Prompt for user on game boot Zeptat se na uživatele při spuštění hry - + Pause emulation when in background Pozastavit emulaci, když je aplikace v pozadí - + Hide mouse on inactivity Skrýt myš při neaktivitě - + Reset All Settings Resetovat všechna nastavení - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Toto vyresetuje všechna nastavení a odstraní konfigurace pro jednotlivé hry. Složky s hrami a profily zůstanou zachovány. Přejete si pokračovat? @@ -1116,18 +1132,113 @@ p, li { white-space: pre-wrap; } Roztáhnout podle okna - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Použít globální barvu pozadí - + Set background color: Nastavit barvu pozadí: - + Background Color: Barva Pozadí: @@ -1196,28 +1307,33 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Výchozí - - - 2x (WILL BREAK THINGS) - 2x (ROZBIJE VĚCI) - - 4x (WILL BREAK THINGS) - 4x (ROZBIJE VĚCI) + 2x + - 8x (WILL BREAK THINGS) - 8x (ROZBIJE VĚCI) + 4x + - 16x (WILL BREAK THINGS) - 16x (ROZBIJE VĚCI) + 8x + + + + + 16x + @@ -1544,8 +1660,8 @@ p, li { white-space: pre-wrap; } - Other - Ostatní + Emulated Devices + @@ -1554,66 +1670,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emulovat analog vstupem z klávesnice - - - - Enable mouse panning - Povolit naklánění myší - - - - Mouse sensitivity - Citlivost myši - - - - % - % - - - - - Advanced - Pokročilé - - - - Touchscreen - Dotyková obrazovka - - - Mouse Myš - - Motion / Touch - Pohyb / Dotyk + + Touchscreen + Dotyková obrazovka - - - Configure - Nastavení + + Advanced + Pokročilé - + Debug Controller Ovladač ladění - + + + Configure + Nastavení + + + + Other + Ostatní + + + + Emulate Analog with Keyboard Input + Emulovat analog vstupem z klávesnice + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Povolit naklánění myší + + + + Mouse sensitivity + Citlivost myši + + + + % + % + + + + Motion / Touch + Pohyb / Dotyk + ConfigureInputPlayer @@ -1628,425 +1753,441 @@ p, li { white-space: pre-wrap; } Připojit ovladač - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Dual Joycons - - - - - Left Joycon - Levý Joycon - - - - - Right Joycon - Pravý Joycon - - - - - Handheld - V rukou - - - + Input Device Vstupní zařízení - - Any - Jakýkoliv - - - - Keyboard/Mouse - Klávesnice/Myš - - - + Profile Profil - + Save Uložit - + New Nový - + Delete Smazat - - + + Left Stick Levá Páčka - - - - - - + + + + + + Up Nahoru - - - - - - - + + + + + + + Left Doleva - - - - - - - + + + + + + + Right Doprava - - - - - - + + + + + + Down Dolů - - - - + + + + Pressed Zmáčknuto - - - - + + + + Modifier Modifikátor - - + + Range Rozsah - - + + % % - - + + Deadzone: 0% Deadzone: 0% - - + + Modifier Range: 0% Rozsah modifikátoru: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture Capture - - - + + + Plus Plus - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Pohyb 1 - + Motion 2 Pohyb 2 - + Face Buttons Face Buttons - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Pravá páčka - - - - + + + + Clear Vyčistit - - - - + + + + [not set] [nenastaveno] - - + + Toggle button Přepnout tlačítko - - + + Invert button + + + + + + Invert axis + Převrátit osy + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick Namapovat analogovou páčku - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Po stisknutí OK nejprve posuňte joystick horizontálně, poté vertikálně. Pro převrácení os nejprve posuňte joystick vertikálně, poté horizontálně. - - Invert axis - Převrátit osy - - - - + + Deadzone: %1% Deadzone: %1% - - + + Modifier Range: %1% Rozsah modifikátoru: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Dual Joycons + + + + Left Joycon + Levý Joycon + + + + Right Joycon + Pravý Joycon + + + + Handheld + V rukou + + + GameCube Controller Ovladač GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pause - + Z Z - + Control Stick Control Stick - + C-Stick C-Stick - + Shake! Shake! - + [waiting] [čekání] - + New Profile Nový profil - + Enter a profile name: Zadejte název profilu: - - + + Create Input Profile Vytvořit profil vstupu - + The given profile name is not valid! Zadaný název profilu není platný! - + Failed to create the input profile "%1" Nepodařilo se vytvořit profil vstupu "%1" - + Delete Input Profile Odstranit profil vstupu - + Failed to delete the input profile "%1" Nepodařilo se odstranit profil vstupu "%1" - + Load Input Profile Načíst profil vstupu - + Failed to load the input profile "%1" Nepodařilo se načíst profil vstupu "%1" - + Save Input Profile Uložit profil vstupu - + Failed to save the input profile "%1" Nepodařilo se uložit profil vstupu "%1" @@ -2072,85 +2213,75 @@ Pro převrácení os nejprve posuňte joystick vertikálně, poté horizontáln ConfigureMotionTouch - + Configure Motion / Touch Nastavení pohybu / dotyku - - Mouse Motion - Pohyb myší - - - - Sensitivity: - Citlivost: - - - + Touch Dotyk - + UDP Calibration: Kalibrace UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Konfigurovat - - Use button mapping: - Použít mapování tlačítek: + + Touch from button profile: + - + CemuhookUDP Config Nastavení CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Můžete použít jakýkoliv Cemuhook kompatibilní UDP vstupní zdroj pro poskytnutí pohybového a dotykového vstupu. - + Server: Server: - + Port: Port: - + Learn More Dozvědět se více - - + + Test Test - + Add Server Přidat server - + Remove Server Odstranit server @@ -2160,145 +2291,81 @@ Pro převrácení os nejprve posuňte joystick vertikálně, poté horizontáln <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Dozvědět se více</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Číslo portu obsahuje neplatné znaky - + Port has to be in range 0 and 65353 Port musí být v rozsahu 0 až 65353 - + IP address is not valid IP adresa není platná - + This UDP server already exists UDP server již existuje - + Unable to add more than 8 servers Není možné přidat více než 8 serverů - + Testing Testování - + Configuring Nastavování - + Test Successful Test byl úspěšný - + Successfully received data from the server. Úspěšně jsme získali data ze serveru. - + Test Failed Test byl neúspěšný - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Nedostali jsme platná data ze serveru.<br>Prosím zkontrolujte, že váš server je nastaven správně a že adresa a port jsou zadány správně. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Probíhá test UDP nebo konfigurace kalibrace.<br>Prosím vyčkejte na dokončení. - - ConfigureMouseAdvanced - - - Configure Mouse - Nastavení Myši - - - - Mouse Buttons - Tlačítka Myši - - - - Forward: - Vpřed: - - - - Back: - Zpátky: - - - - Left: - Vlevo: - - - - Middle: - Prostřed: - - - - Right: - Vpravo: - - - - - Clear - Vyčistit - - - - Defaults - Defaultní - - - - [not set] - [nenastaveno] - - - - Restore Default - Navrátit Základní Nastavení - - - - [press key] - [zmačkni tlačítko] - - ConfigureNetwork @@ -3082,31 +3149,26 @@ Pro převrácení os nejprve posuňte joystick vertikálně, poté horizontáln - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3119,7 +3181,7 @@ Pro převrácení os nejprve posuňte joystick vertikálně, poté horizontáln - + Select TAS Load Directory... @@ -3181,37 +3243,37 @@ Táhněte body pro změnu pozice nebo dvojitě klikněte na buňky tabulky pro z Y - + New Profile Nový profil - + Enter the name for the new profile. Zadejte název nového profilu. - + Delete Profile Smazat profil - + Delete profile %1? Odstranit profil %1? - + Rename Profile Přejmenovat profil - + New name: Nový název: - + [press key] [stiskněte klávesu] @@ -3631,12 +3693,12 @@ Táhněte body pro změnu pozice nebo dvojitě klikněte na buňky tabulky pro z ControllerDialog - + Controller P1 Ovladač P1 - + &Controller P1 &Ovladač P1 @@ -3644,89 +3706,94 @@ Táhněte body pro změnu pozice nebo dvojitě klikněte na buňky tabulky pro z GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymní data jsou sbírána</a> pro vylepšení yuzu. <br/><br/>Chcete s námi sdílet anonymní data? - + Telemetry Telemetry - + Loading Web Applet... Načítání Web Appletu... - - + + Disable Web Applet Zakázat Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Zakázání Web Appletu způsobí, že se po zbytek emulované relace již nebude zobrazovat. To může vést k nedefinovanému chování a mělo by být použito pouze u hry Super Mario 3D All-Stars. Opravdu si přejete Web Applet zakázat? - + The amount of shaders currently being built Počet aktuálně sestavovaných shaderů - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Aktuální emulační rychlost. Hodnoty vyšší než 100% indikují, že emulace běží rychleji nebo pomaleji než na Switchi. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Kolik snímků za sekundu aktuálně hra zobrazuje. Tohle závisí na hře od hry a scény od scény. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Čas potřebný na emulaci framu scény, nepočítá se limit nebo v-sync. Pro plnou rychlost by se tohle mělo pohybovat okolo 16.67 ms. - + Invalid config detected Zjištěno neplatné nastavení - + Handheld controller can't be used on docked mode. Pro controller will be selected. Ruční ovladač nelze používat v dokovacím režimu. Bude vybrán ovladač Pro Controller. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Vymazat poslední soubory - - TAS Recording - + + &Continue + &Pokračovat - - Overwrite file of player 1? + + &Pause @@ -3778,657 +3845,724 @@ Táhněte body pro změnu pozice nebo dvojitě klikněte na buňky tabulky pro z Nastala chyba. Koukni do logu. - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Start - - - + Save Data Uložit data - + Mod Data Módovat Data - + Error Opening %1 Folder Chyba otevírání složky %1 - - + + Folder does not exist! Složka neexistuje! - + Error Opening Transferable Shader Cache Chyba při otevírání přenositelné mezipaměti shaderů - + Failed to create the shader cache directory for this title. - + Contents Obsah - + Update Aktualizace - + DLC DLC - + Remove Entry Odebrat položku - + Remove Installed Game %1? Odebrat Nainstalovanou Hru %1? - - - - - - + + + + + + Successfully Removed Úspěšně odebráno - + Successfully removed the installed base game. Úspěšně odebrán nainstalovaný základ hry. - - - + + + Error Removing %1 Chyba při odstraňování %1 - + The base game is not installed in the NAND and cannot be removed. Základ hry není nainstalovaný na NAND a nemůže být odstraněn. - + Successfully removed the installed update. Úspěšně odebrána nainstalovaná aktualizace. - + There is no update installed for this title. Není nainstalovaná žádná aktualizace pro tento titul. - + There are no DLC installed for this title. Není nainstalované žádné DLC pro tento titul. - + Successfully removed %1 installed DLC. Úspěšně odstraněno %1 nainstalovaných DLC. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Odstranit vlastní konfiguraci hry? - + Remove File Odstranit soubor - - + + Error Removing Transferable Shader Cache Chyba při odstraňování přenositelné mezipaměti shaderů - - + + A shader cache for this title does not exist. Mezipaměť shaderů pro tento titul neexistuje. - + Successfully removed the transferable shader cache. Přenositelná mezipaměť shaderů úspěšně odstraněna - + Failed to remove the transferable shader cache. Nepodařilo se odstranit přenositelnou mezipaměť shaderů - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Chyba při odstraňování vlastní konfigurace hry - + A custom configuration for this title does not exist. Vlastní konfigurace hry pro tento titul neexistuje. - + Successfully removed the custom game configuration. Úspěšně odstraněna vlastní konfigurace hry. - + Failed to remove the custom game configuration. Nepodařilo se odstranit vlastní konfiguraci hry. - - + + RomFS Extraction Failed! Extrakce RomFS se nepovedla! - + There was an error copying the RomFS files or the user cancelled the operation. Nastala chyba při kopírování RomFS souborů, nebo uživatel operaci zrušil. - + Full Plný - + Skeleton Kostra - + Select RomFS Dump Mode Vyber RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Vyber jak by si chtěl RomFS vypsat.<br>Plné zkopíruje úplně všechno, ale<br>kostra zkopíruje jen strukturu složky. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Extrahuji RomFS... - - + + Cancel Zrušit - + RomFS Extraction Succeeded! Extrakce RomFS se povedla! - + The operation completed successfully. Operace byla dokončena úspěšně. - + Error Opening %1 Chyba při otevírání %1 - + Select Directory Vybraná Složka - + Properties Vlastnosti - + The game properties could not be loaded. Herní vlastnosti nemohly být načteny. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch Executable (%1);;Všechny soubory (*.*) - + Load File Načíst soubor - + Open Extracted ROM Directory Otevřít složku s extrahovanou ROM - + Invalid Directory Selected Vybraná složka je neplatná - + The directory you have selected does not contain a 'main' file. Složka kterou jste vybrali neobsahuje soubor "main" - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Instalovatelný soubor pro Switch (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Instalovat Soubory - + %n file(s) remaining - + Installing file "%1"... Instalování souboru "%1"... - - + + Install Results Výsledek instalace - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Abychom předešli možným konfliktům, nedoporučujeme uživatelům instalovat základní hry na paměť NAND. Tuto funkci prosím používejte pouze k instalaci aktualizací a DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systémová Aplikace - + System Archive Systémový archív - + System Application Update Systémový Update Aplikace - + Firmware Package (Type A) Firmware-ový baliček (Typu A) - + Firmware Package (Type B) Firmware-ový baliček (Typu B) - + Game Hra - + Game Update Update Hry - + Game DLC Herní DLC - + Delta Title Delta Title - + Select NCA Install Type... Vyberte typ instalace NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Vyberte typ title-u, který chcete nainstalovat tenhle NCA jako: (Většinou základní "game" stačí.) - + Failed to Install Chyba v instalaci - + The title type you selected for the NCA is invalid. Tento typ pro tento NCA není platný. - + File not found Soubor nenalezen - + File "%1" not found Soubor "%1" nenalezen - - - &Continue - &Pokračovat - - - + OK OK - + Missing yuzu Account Chybí účet yuzu - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Pro přidání recenze kompatibility je třeba mít účet yuzu<br><br/>Pro nalinkování yuzu účtu jdi do Emulace &gt; Konfigurace &gt; Web. - + Error opening URL Chyba při otevírání URL - + Unable to open the URL "%1". Nelze otevřít URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Soubor Amiibo (%1);; Všechny Soubory (*.*) - + Load Amiibo Načíst Amiibo - + Error opening Amiibo data file Chyba při načítání souboru Amiibo - + Unable to open Amiibo file "%1" for reading. Amiibo "%1" nešlo otevřít v řežimu pro čtení. - + Error reading Amiibo data file Chyba načítání Amiiba - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Načtení celého Amiiba nebylo možné. Očekáváno bylo %1 bytů, ale pouze %2 bytů se načetlo. - + Error loading Amiibo data Chyba načítání Amiiba - + Unable to load Amiibo data. Načtení Amiiba nebylo možné - + Capture Screenshot Pořídit Snímek Obrazovky - + PNG Image (*.png) PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Rychlost: %1% / %2% - + Speed: %1% Rychlost: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Hra: %1 FPS - + Frame: %1 ms Frame: %1 ms - + GPU NORMAL GPU NORMÁLNÍ - + GPU HIGH GPU VYSOKÝ - + GPU EXTREME GPU EXTRÉMNÍ - + GPU ERROR GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Hra, kterou se snažíte načíst potřebuje další data z vašeho Switche, než bude moci být načtena.<br/><br/>Pro více informací o získání těchto souboru se koukněte na wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Získávání Systémových Archivů a Sdílených Fontu z konzole Switch</a>.<br/><br/>Přejete si odejít do listu her? Pokračování v emulaci by mohlo mít negativní účinky jako crashe, rozbité savy , nebo další bugy. - + yuzu was unable to locate a Switch system archive. %1 Aplikace yuzu nenašla systémový archiv Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 Aplikace yuzu nenašla systémový archiv Switch: %1. %2 - + System Archive Not Found Systémový Archív Nenalezen - + System Archive Missing Chybí systémový archiv - + yuzu was unable to locate the Switch shared fonts. %1 Aplikace yuzu nenašla sdílená písma Switch. %1 - + Shared Fonts Not Found Sdílené Fonty Nenalezeny - + Shared Font Missing Chybí sdílené písmo - + Fatal Error Fatální Chyba - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu narazilo na fatální chybu, prosím kouknšte do logu pro více informací. Pro více informací jak se dostat do logu se koukněte na následující stránku: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'> Jak Uploadnout Log</a>.<br/><br/>Přejete si odejít do listu her? Pokračování v emulaci může mít za následek crashe, rozbité savy, nebo další bugy. - + Fatal Error encountered Vyskytla se kritická chyba - + Confirm Key Rederivation Potvďte Rederivaci Klíčů - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4445,37 +4579,37 @@ a udělejte si zálohu. Toto vymaže věechny vaše automaticky generované klíče a znova spustí modul derivace klíčů. - + Missing fuses Chybí Fuses - + - Missing BOOT0 - Chybí BOOT0 - + - Missing BCPKG2-1-Normal-Main - Chybí BCPKG2-1-Normal-Main - + - Missing PRODINFO - Chybí PRODINFO - + Derivation Components Missing Chybé odvozené komponenty - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4484,39 +4618,39 @@ Tohle může zabrat až minutu podle výkonu systému. - + Deriving Keys Derivuji Klíče - + Select RomFS Dump Target Vyberte Cíl vypsaní RomFS - + Please select which RomFS you would like to dump. Vyberte, kterou RomFS chcete vypsat. - + Are you sure you want to close yuzu? Jste si jist, že chcete zavřít yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Jste si jist, že chcete ukončit emulaci? Jakýkolic neuložený postup bude ztracen. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4528,38 +4662,38 @@ Opravdu si přejete ukončit tuto aplikaci? GRenderWindow - + OpenGL not available! OpenGL není k dispozici! - + yuzu has not been compiled with OpenGL support. yuzu nebylo sestaveno s OpenGL podporou. - - + + Error while initializing OpenGL! Chyba při inicializaci OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Vaše grafická karta pravděpodobně nepodporuje OpenGL nebo nejsou nainstalovány nejnovější ovladače. - + Error while initializing OpenGL 4.6! Chyba při inicializaci OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Vaše grafická karta pravděpodobně nepodporuje OpenGL 4.6 nebo nejsou nainstalovány nejnovější ovladače.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Vaše grafická karta pravděpodobně nepodporuje jedno nebo více rozšíření OpenGL. Ujistěte se prosím, že jsou nainstalovány nejnovější ovladače.<br><br>GL Renderer:<br>%1<br><br>Nepodporované rozšíření:<br>%2 @@ -4916,190 +5050,205 @@ Screen. &Emulace - + &View &Pohled - + &Reset Window Size &Resetovat Velikost Okna - - Reset Window Size to &720p - Nastavit velikost okna na &720p - - - - Reset Window Size to 720p - Nastavit velikost okna na 720p - - - - Reset Window Size to &900p - Resetovat Velikost Okna na &900p - - - - Reset Window Size to 900p - Resetovat Velikost Okna na 900p - - - - Reset Window Size to &1080p - Nastavit velikost okna na &1080p - - - - Reset Window Size to 1080p - Nastavit velikost okna na 1080p - - - + &Debugging &Ladění - + + Reset Window Size to &720p + Nastavit velikost okna na &720p + + + + Reset Window Size to 720p + Nastavit velikost okna na 720p + + + + Reset Window Size to &900p + Resetovat Velikost Okna na &900p + + + + Reset Window Size to 900p + Resetovat Velikost Okna na 900p + + + + Reset Window Size to &1080p + Nastavit velikost okna na &1080p + + + + Reset Window Size to 1080p + Nastavit velikost okna na 1080p + + + &Tools &Nástroje - + + &TAS + + + + &Help &Pomoc - + &Install Files to NAND... &Instalovat soubory na NAND... - + L&oad File... Načís&t soubor... - + Load &Folder... Načíst sl&ožku... - + E&xit E&xit - - &Start - &Start - - - + &Pause &Pauza - + &Stop &Stop - + &Reinitialize keys... &Znovu inicializovat klíče... - + &About yuzu O &aplikaci yuzu - + Single &Window Mode &Režim jednoho okna - + Con&figure... &Nastavení - + Display D&ock Widget Headers Zobrazit záhlaví widgetů d&oku - + Show &Filter Bar Zobrazit &filtrovací panel - + Show &Status Bar Zobrazit &stavový řádek - + Show Status Bar Zobrazit Staus Bar - + F&ullscreen &Celá obrazovka - + &Restart &Restartovat - + Load &Amiibo... Načíst &Amiibo... - + &Report Compatibility &Nahlásit kompatibilitu - + Open &Mods Page Otevřít stránku s &modifikacemi - + Open &Quickstart Guide Otevřít &rychlého průvodce - + &FAQ Často &kladené otázky - + Open &yuzu Folder Otevřít složku s &yuzu - + &Capture Screenshot Za&chytit snímek obrazovky - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... Nastavení současné hry + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5145,10 +5294,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE START/PAUSE + + + Charging + + QObject @@ -5179,142 +5333,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [Nenastaveno] - - Hat %1 %2 Poziční klobouček %1 %2 - - - - - - + + + + Axis %1%2 Osa %1%2 - Button %1 Tlačítko %1 - - - + + + [unknown] [Neznámá] - + + Left + + + + + Right + + + - Click 0 - Klik 0 + Down + - - Click 1 - Klik 1 + Up + - - Click 2 - Klik 2 + Z + - - Click 3 - Klik 3 + R + - - Click 4 - Klik 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC osa %1%2 - - - - GC Button %1 - GC tlačítko %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Pohyb %1 - - - - %1Button %2 + + + + %1%2Axis %3 - - SDL Motion - SDL pohyb + + %1%2Axis %3,%4,%5 + - - %1Click %2 - %1Klik %2 + + %1%2Motion %3 + - + + + %1%2Button %3 + + + + [unused] [nepoužito] @@ -5355,7 +5589,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5368,7 +5602,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Oba Joycony @@ -5381,7 +5615,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Levý Joycon @@ -5394,7 +5628,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Pravý Joycon @@ -5422,7 +5656,7 @@ p, li { white-space: pre-wrap; } - + Handheld Handheld @@ -5543,7 +5777,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Ovladač GameCube @@ -5637,13 +5871,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Storno diff --git a/dist/languages/da.ts b/dist/languages/da.ts index c125586dd..c62fd142d 100644 --- a/dist/languages/da.ts +++ b/dist/languages/da.ts @@ -666,7 +666,12 @@ p, li { white-space: pre-wrap; } Aktivér Automatisk Stub** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. **Dette vil automatisk blive nulstillet, når yuzu lukkes. @@ -946,67 +951,78 @@ p, li { white-space: pre-wrap; } Generelt - - Framerate Cap - Billedfrekvensloft + + + Use global framerate cap + - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. Kræver brug af FPS-Begrænsnings-Skift genvejstast, for at træde i kraft. - + + Framerate Cap + Billedfrekvensloft + + + x x - + Limit Speed Percent Begræns Hastighedsprocent - + % % - + Multicore CPU Emulation Flerkerne-CPU-Emulering - + Confirm exit while emulation is running Bekræft afslutning, mens emulering kører - + Prompt for user on game boot Spørg efter bruger, ved opstart af spil - + Pause emulation when in background Sæt emulering på pause, når i baggrund - + Hide mouse on inactivity Skjul mus ved inaktivitet - + Reset All Settings Nulstil Alle Indstillinger - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? dette nulstiller alle indstillinger og fjerner alle pr-spil-konfigurationer. Dette vil ikke slette spilmapper, -profiler, eller input-profiler. Fortsæt? @@ -1124,18 +1140,113 @@ p, li { white-space: pre-wrap; } Stræk til Vindue - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Brug global baggrundsfarve - + Set background color: Angiv baggrundsfarve: - + Background Color: Baggrundsfarve: @@ -1204,28 +1315,33 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Standard - - - 2x (WILL BREAK THINGS) - 2x (VIL ØDELÆGGE NOGET) - - 4x (WILL BREAK THINGS) - 4x (VIL ØDELÆGGE NOGET) + 2x + - 8x (WILL BREAK THINGS) - 8x (VIL ØDELÆGGE NOGET) + 4x + - 16x (WILL BREAK THINGS) - 16x (VIL ØDELÆGGE NOGET) + 8x + + + + + 16x + @@ -1552,8 +1668,8 @@ p, li { white-space: pre-wrap; } - Other - Andet + Emulated Devices + @@ -1562,66 +1678,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emulér Analog med Tastaturinput - - - - Enable mouse panning - Aktivér kig med mus - - - - Mouse sensitivity - Mus-følsomhed - - - - % - % - - - - - Advanced - Avanceret - - - - Touchscreen - Berøringsfølsom Skærm - - - Mouse Mus - - Motion / Touch - Bevægelse / Berøring + + Touchscreen + Berøringsfølsom Skærm - - - Configure - Konfigurér + + Advanced + Avanceret - + Debug Controller Fejlfindings-Styringsenhed - + + + Configure + Konfigurér + + + + Other + Andet + + + + Emulate Analog with Keyboard Input + Emulér Analog med Tastaturinput + + + Requires restarting yuzu Kræver genstart af yuzu - + Enable XInput 8 player support (disables web applet) Aktivér XInput 8-spiller-understøttelse (deaktiverer net-applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Aktivér kig med mus + + + + Mouse sensitivity + Mus-følsomhed + + + + % + % + + + + Motion / Touch + Bevægelse / Berøring + ConfigureInputPlayer @@ -1636,425 +1761,441 @@ p, li { white-space: pre-wrap; } Tilslut Styringsenhed - - - - Pro Controller - Pro-Styringsenhed - - - - - Dual Joycons - Dobbelt-Joycon - - - - - Left Joycon - Venstre Joycon - - - - - Right Joycon - Højre Joycon - - - - - Handheld - Håndholdt - - - + Input Device Inputenhed - - Any - Enhver - - - - Keyboard/Mouse - Tastatur/Mus - - - + Profile Profil - + Save Gem - + New Ny - + Delete Slet - - + + Left Stick Venstre Styrepind - - - - - - + + + + + + Up Op - - - - - - - + + + + + + + Left Venstre - - - - - - - + + + + + + + Right Højre - - - - - - + + + + + + Down ed - - - - + + + + Pressed Nedtrykt - - - - + + + + Modifier Forandrer - - + + Range Rækkevidde - - + + % % - - + + Deadzone: 0% Dødzone: 0% - - + + Modifier Range: 0% Forandr Rækkevidde: 0% - + D-Pad Retningskryds - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture Optag - - - + + + Plus Plus - - + + Home Hjem - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Bevægelse 1 - + Motion 2 Bevægelse 2 - + Face Buttons Frontknapper: - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Højre Styrepind - - - - + + + + Clear Ryd - - - - + + + + [not set] [ikke indstillet] - - + + Toggle button Funktionsskifteknap - - + + Invert button + + + + + + Invert axis + Omvend akser + + + + Set threshold Angiv tærskel - + Choose a value between 0% and 100% Vælg en værdi imellem 0% og 100% - + Map Analog Stick Tilsted Analog Pind - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Bevæg, efter tryk på OK, først din styrepind vandret og så lodret. Bevæg, for at omvende akserne, først din styrepind lodret og så vandret. - - Invert axis - Omvend akser - - - - + + Deadzone: %1% Dødzone: 1% - - + + Modifier Range: %1% Forandringsrækkevidde: %1% - + + + Pro Controller + Pro-Styringsenhed + + + + Dual Joycons + Dobbelt-Joycon + + + + Left Joycon + Venstre Joycon + + + + Right Joycon + Højre Joycon + + + + Handheld + Håndholdt + + + GameCube Controller GameCube-Styringsenhed - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pause - + Z Z - + Control Stick Styrepind - + C-Stick C-Pind - + Shake! Ryst! - + [waiting] [venter] - + New Profile Ny Profil - + Enter a profile name: Indtast et profilnavn: - - + + Create Input Profile Opret Input-Profil - + The given profile name is not valid! Det angivne profilnavn er ikke gyldigt! - + Failed to create the input profile "%1" Oprettelse af input-profil "%1" mislykkedes - + Delete Input Profile Slet Input-Profil - + Failed to delete the input profile "%1" Sletning af input-profil "%1" mislykkedes - + Load Input Profile Indlæs Input-Profil - + Failed to load the input profile "%1" Indlæsning af input-profil "%1" mislykkedes - + Save Input Profile Gem Input-Profil - + Failed to save the input profile "%1" Lagring af input-profil "%1" mislykkedes @@ -2080,85 +2221,75 @@ Bevæg, for at omvende akserne, først din styrepind lodret og så vandret. ConfigureMotionTouch - + Configure Motion / Touch Konfigurér Bevægelse / Berøring - - Mouse Motion - Musebevægelse - - - - Sensitivity: - Følsomhed: - - - + Touch Berøring - + UDP Calibration: UDP-Kalibrering: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Konfigurér - - Use button mapping: - Brug knaptildeling + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP-Konfiguration - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Du må bruge enhver Cemuhook-kompatibel input-kilde, til at give bevægelses- og berøringsinput. - + Server: Server: - + Port: Port: - + Learn More Find Ud Af Mere - - + + Test Afprøv - + Add Server Tilføj Server - + Remove Server Fjernserver @@ -2168,145 +2299,81 @@ Bevæg, for at omvende akserne, først din styrepind lodret og så vandret.<a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Find Ud Af Mere</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Portnummer indeholder ugyldige tegn - + Port has to be in range 0 and 65353 Port skal være imellem 0 and 65353 - + IP address is not valid IP-adresse er ikke gyldig - + This UDP server already exists Denne UDP-server eksisterer allerede - + Unable to add more than 8 servers Ude af stand til, at tilføje mere end 8 servere - + Testing Afprøvning - + Configuring Konfigurér - + Test Successful Afprøvning Lykkedes - + Successfully received data from the server. Modtagelse af data fra serveren lykkedes. - + Test Failed Afprøvning Mislykkedes - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Kunne ikke modtage gyldig data fra serveren.<br>Bekræft venligst, at serveren er opsat korrekt, og at adressen og porten er korrekte. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP-Afprøvnings- eller -kalibreringskonfiguration er i gang.<br>vent venligst på, at de bliver færdige. - - ConfigureMouseAdvanced - - - Configure Mouse - Konfigurér Mus - - - - Mouse Buttons - Museknapper - - - - Forward: - Frem: - - - - Back: - Tilbage: - - - - Left: - Venstre: - - - - Middle: - Midte: - - - - Right: - Højre: - - - - - Clear - Ryd - - - - Defaults - Standarder - - - - [not set] - [ikke indstillet] - - - - Restore Default - Gendan Standard - - - - [press key] - [tryk på tast] - - ConfigureNetwork @@ -3090,31 +3157,26 @@ Bevæg, for at omvende akserne, først din styrepind lodret og så vandret. - Automatic controller profile swapping - Automatisk styringsenhedsprofil-ombytning - - - Loop script Loop skrift - + Pause execution during loads Sæt eksekvering på pause under indlæsninger - + Script Directory Skriftmappe - + Path Sti - + ... ... @@ -3127,7 +3189,7 @@ Bevæg, for at omvende akserne, først din styrepind lodret og så vandret.TAS-Konfiguration - + Select TAS Load Directory... Vælg TAS-Indlæsningsmappe... @@ -3189,37 +3251,37 @@ Træk punkter, for at skifte position, eller dobbeltklik i tabelceller, for at r Y - + New Profile Ny Profil - + Enter the name for the new profile. Indtast navnet på den nye profil. - + Delete Profile Slet Profil - + Delete profile %1? Slet profil %1? - + Rename Profile Omdøb Profil - + New name: Nyt navn: - + [press key] [tryk på tast] @@ -3639,12 +3701,12 @@ Træk punkter, for at skifte position, eller dobbeltklik i tabelceller, for at r ControllerDialog - + Controller P1 Styringsenhed P1 - + &Controller P1 &Styringsenhed P1 @@ -3652,89 +3714,94 @@ Træk punkter, for at skifte position, eller dobbeltklik i tabelceller, for at r GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonym data indsamles</a>, for at hjælp med, at forbedre yuzu. <br/><br/>Kunne du tænke dig, at dele dine brugsdata med os? - + Telemetry Telemetri - + Loading Web Applet... Indlæser Net-Applet... - - + + Disable Web Applet Deaktivér Net-Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Aktuel emuleringshastighed. Værdier højere eller lavere end 100% indikerer, at emulering kører hurtigere eller langsommere end en Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - + DOCK - + VULKAN - + OPENGL - + &Clear Recent Files - - TAS Recording + + &Continue - - Overwrite file of player 1? + + &Pause @@ -3786,655 +3853,722 @@ Træk punkter, for at skifte position, eller dobbeltklik i tabelceller, for at r - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Start - - - + Save Data - + Mod Data - + Error Opening %1 Folder Fejl ved Åbning af %1 Mappe - - + + Folder does not exist! Mappe eksisterer ikke! - + Error Opening Transferable Shader Cache - + Failed to create the shader cache directory for this title. - + Contents - + Update - + DLC - + Remove Entry - + Remove Installed Game %1? - - - - - - + + + + + + Successfully Removed - + Successfully removed the installed base game. - - - + + + Error Removing %1 - + The base game is not installed in the NAND and cannot be removed. - + Successfully removed the installed update. - + There is no update installed for this title. - + There are no DLC installed for this title. - + Successfully removed %1 installed DLC. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove File - - + + Error Removing Transferable Shader Cache - - + + A shader cache for this title does not exist. - + Successfully removed the transferable shader cache. - + Failed to remove the transferable shader cache. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration - + A custom configuration for this title does not exist. - + Successfully removed the custom game configuration. - + Failed to remove the custom game configuration. - - + + RomFS Extraction Failed! RomFS-Udpakning Mislykkedes! - + There was an error copying the RomFS files or the user cancelled the operation. Der skete en fejl ved kopiering af RomFS-filerne, eller brugeren afbrød opgaven. - + Full Fuld - + Skeleton Skelet - + Select RomFS Dump Mode Vælg RomFS-Nedfældelsestilstand - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Udpakker RomFS... - - + + Cancel Afbryd - + RomFS Extraction Succeeded! RomFS-Udpakning Lykkedes! - + The operation completed successfully. Fuldførelse af opgaven lykkedes. - + Error Opening %1 Fejl ved Åbning af %1 - + Select Directory Vælg Mappe - + Properties Egenskaber - + The game properties could not be loaded. Spil-egenskaberne kunne ikke indlæses. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch-Eksekverbar (%1);;Alle filer (*.*) - + Load File Indlæs Fil - + Open Extracted ROM Directory Åbn Udpakket ROM-Mappe - + Invalid Directory Selected Ugyldig Mappe Valgt - + The directory you have selected does not contain a 'main' file. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files - + %n file(s) remaining - + Installing file "%1"... Installér fil "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systemapplikation - + System Archive Systemarkiv - + System Application Update Systemapplikationsopdatering - + Firmware Package (Type A) Firmwarepakke (Type A) - + Firmware Package (Type B) Firmwarepakke (Type B) - + Game Spil - + Game Update Spilopdatering - + Game DLC Spiludvidelse - + Delta Title Delta-Titel - + Select NCA Install Type... Vælg NCA-Installationstype... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install Installation mislykkedes - + The title type you selected for the NCA is invalid. - + File not found Fil ikke fundet - + File "%1" not found Fil "%1" ikke fundet - - - &Continue - - - - + OK - + Missing yuzu Account Manglende yuzu-Konto - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. - + Error opening URL - + Unable to open the URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Amiibo-Fil (%1);; Alle Filer (*.*) - + Load Amiibo Indlæs Amiibo - + Error opening Amiibo data file Fejl ved åbning af Amiibo-datafil - + Unable to open Amiibo file "%1" for reading. Ude af stand til, at åbne Amiibo-fil "%1" til indlæsning. - + Error reading Amiibo data file Fejl ved indlæsning af Amiibo-datafil - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. - + Error loading Amiibo data Fejl ved indlæsning af Amiibo-data - + Unable to load Amiibo data. Ude af stand til, at indlæse Amiibo-data. - + Capture Screenshot Optag Skærmbillede - + PNG Image (*.png) PNG-Billede (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Hastighed: %1% / %2% - + Speed: %1% Hastighed: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Spil: %1 FPS - + Frame: %1 ms Billede: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - + yuzu was unable to locate a Switch system archive. %1 yuzu var ude af stand til, at lokalisere et Switch-systemarkiv. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu var ude af stand til, at lokalisere et Switch-systemarkiv. %1. %2 - + System Archive Not Found Systemarkiv Ikke Fundet - + System Archive Missing Systemarkiv Mangler - + yuzu was unable to locate the Switch shared fonts. %1 yuzu var ude af stand til, at finde delte Switch-skrifttyper. %1 - + Shared Fonts Not Found Delte Skrifttyper Ikke Fundet - + Shared Font Missing Delte Skrifttyper Mangler - + Fatal Error Fatal Fejl - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - + Fatal Error encountered Stødte på Fatal Fejl - + Confirm Key Rederivation - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4445,76 +4579,76 @@ This will delete your autogenerated key files and re-run the key derivation modu - + Missing fuses - + - Missing BOOT0 - + - Missing BCPKG2-1-Normal-Main - + - Missing PRODINFO - + Derivation Components Missing - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. - + Deriving Keys - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close yuzu? Er du sikker på, at du vil lukke yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Er du sikker på, at du vil stoppe emulereingen? Enhver ulagret data, vil gå tabt. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4524,38 +4658,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! - + yuzu has not been compiled with OpenGL support. - - + + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4911,190 +5045,205 @@ Screen. &Emulering - + &View - + &Reset Window Size - - Reset Window Size to &720p - - - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - - - Reset Window Size to 1080p - - - - + &Debugging - + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + &Tools - + + &TAS + + + + &Help &Hjælp - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit - - &Start - - - - + &Pause - + &Stop - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Vis Statuslinje - + F&ullscreen - + &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5136,10 +5285,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5170,142 +5324,222 @@ p, li { white-space: pre-wrap; } - - + Shift Skift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [ikke indstillet] - - Hat %1 %2 - - - - - - + + + + Axis %1%2 Akse %1%2 - Button %1 Knap %1 - - - + + + [unknown] [ukendt] - + + Left + + + + + Right + + + - Click 0 + Down - - Click 1 + Up - - Click 2 + Z - - Click 3 + R - - Click 4 + L - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 - - GC Axis %1%2 + + [invalid] - - GC Button %1 + + + %1%2Hat %3 - - TAS Axis %1 + + + + %1%2Axis %3 - - TAS Btn %1 + + %1%2Axis %3,%4,%5 - - Motion %1 + + %1%2Motion %3 - - %1Button %2 + + + %1%2Button %3 - - SDL Motion - - - - - %1Click %2 - - - - + [unused] [ubrugt] @@ -5346,7 +5580,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5359,7 +5593,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons @@ -5372,7 +5606,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon @@ -5385,7 +5619,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon @@ -5413,7 +5647,7 @@ p, li { white-space: pre-wrap; } - + Handheld @@ -5534,7 +5768,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5618,13 +5852,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/de.ts b/dist/languages/de.ts index ac17c0e22..2cb4c534f 100644 --- a/dist/languages/de.ts +++ b/dist/languages/de.ts @@ -657,7 +657,12 @@ p, li { white-space: pre-wrap; } Auto-Stub** aktivieren - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -937,67 +942,78 @@ p, li { white-space: pre-wrap; } Allgemein - - Framerate Cap - Bildratenbeschränkung + + + Use global framerate cap + - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + Bildratenbeschränkung + + + x x - + Limit Speed Percent Geschwindigkeit auf % festlegen - + % % - + Multicore CPU Emulation Multicore-CPU-Emulation - + Confirm exit while emulation is running Schließen des Emulators bestätigen, falls ein Spiel läuft - + Prompt for user on game boot Beim Spielstart nach Nutzer fragen - + Pause emulation when in background Emulation im Hintergrund pausieren - + Hide mouse on inactivity Mauszeiger verstecken - + Reset All Settings Setze alle Einstellungen zurück - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Hierdurch werden alle Einstellungen zurückgesetzt und alle spielspezifischen Konfigurationen gelöscht. Spiel-Ordner, Profile oder Eingabeprofile werden nicht gelöscht. Fortfahren? @@ -1115,18 +1131,113 @@ p, li { white-space: pre-wrap; } Auf Fenster anpassen - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Globale Hintergrundfarbe verwenden - + Set background color: Hintergrundfarbe: - + Background Color: Hintergrundfarbe: @@ -1195,27 +1306,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Standard - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1543,8 +1659,8 @@ p, li { white-space: pre-wrap; } - Other - Weiteres + Emulated Devices + @@ -1553,66 +1669,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Analog bei Tastatureingabe emulieren - - - - Enable mouse panning - Maus-Panning aktivieren - - - - Mouse sensitivity - Maus-Empfindlichkeit - - - - % - % - - - - - Advanced - Erweitert - - - - Touchscreen - Touchscreen - - - Mouse Maus - - Motion / Touch - Bewegung / Touch + + Touchscreen + Touchscreen - - - Configure - Konfigurieren + + Advanced + Erweitert - + Debug Controller Debug Controller - + + + Configure + Konfigurieren + + + + Other + Weiteres + + + + Emulate Analog with Keyboard Input + Analog bei Tastatureingabe emulieren + + + Requires restarting yuzu Erfordet Neustart von yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Maus-Panning aktivieren + + + + Mouse sensitivity + Maus-Empfindlichkeit + + + + % + % + + + + Motion / Touch + Bewegung / Touch + ConfigureInputPlayer @@ -1627,425 +1752,441 @@ p, li { white-space: pre-wrap; } Controller verbinden - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Zwei Joycons - - - - - Left Joycon - Linker Joycon - - - - - Right Joycon - Rechter Joycon - - - - - Handheld - Handheld - - - + Input Device Eingabegerät - - Any - Alle - - - - Keyboard/Mouse - Tastatur/Maus - - - + Profile Profil - + Save Speichern - + New Neu - + Delete Löschen - - + + Left Stick Linker Analogstick - - - - - - + + + + + + Up Hoch - - - - - - - + + + + + + + Left Links - - - - - - - + + + + + + + Right Rechts - - - - - - + + + + + + Down Runter - - - - + + + + Pressed Gedrückt - - - - + + + + Modifier Modifikator - - + + Range Radius - - + + % % - - + + Deadzone: 0% Deadzone: 0% - - + + Modifier Range: 0% Modifikator-Radius: 0% - + D-Pad Steuerkreuz - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture Screenshot - - - + + + Plus Plus - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Bewegung 1 - + Motion 2 Bewegung 2 - + Face Buttons Tasten - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Rechter Analogstick - - - - + + + + Clear Löschen - - - - + + + + [not set] [nicht belegt] - - + + Toggle button Taste umschalten - - + + Invert button + + + + + + Invert axis + Achsen umkehren + + + + Set threshold - + Choose a value between 0% and 100% Wert zwischen 0% und 100% wählen - + Map Analog Stick Analog-Stick festlegen - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Nach dem Drücken von OK den Joystick zuerst horizontal, dann vertikal bewegen. Um die Achsen umzukehren, bewege den Joystick zuerst vertikal und dann horizontal. - - Invert axis - Achsen umkehren - - - - + + Deadzone: %1% Deadzone: %1% - - + + Modifier Range: %1% Modifikator-Radius: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Zwei Joycons + + + + Left Joycon + Linker Joycon + + + + Right Joycon + Rechter Joycon + + + + Handheld + Handheld + + + GameCube Controller GameCube-Controller - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pause - + Z Z - + Control Stick Analog Stick - + C-Stick C-Stick - + Shake! Schütteln! - + [waiting] [wartet] - + New Profile Neues Profil - + Enter a profile name: Profilnamen eingeben: - - + + Create Input Profile Eingabeprofil erstellen - + The given profile name is not valid! Angegebener Profilname ist nicht gültig! - + Failed to create the input profile "%1" Erstellen des Eingabeprofils "%1" ist fehlgeschlagen - + Delete Input Profile Eingabeprofil löschen - + Failed to delete the input profile "%1" Löschen des Eingabeprofils "%1" ist fehlgeschlagen - + Load Input Profile Eingabeprofil laden - + Failed to load the input profile "%1" Laden des Eingabeprofils "%1" ist fehlgeschlagen - + Save Input Profile Eingabeprofil speichern - + Failed to save the input profile "%1" Speichern des Eingabeprofils "%1" ist fehlgeschlagen @@ -2071,85 +2212,75 @@ Um die Achsen umzukehren, bewege den Joystick zuerst vertikal und dann horizonta ConfigureMotionTouch - + Configure Motion / Touch Bewegung / Touch einrichten - - Mouse Motion - Mausbewegung - - - - Sensitivity: - Empfindlichkeit: - - - + Touch Touch - + UDP Calibration: UDP Kalibrierung: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Einrichtung - - Use button mapping: - Tastenbelegung nutzen: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP Konfiguration - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Du kannst alle Cemuhook-kompatiblen UDP-Eingabequellen für Bewegung und Touch verwenden. - + Server: Server: - + Port: Port: - + Learn More Mehr erfahren - - + + Test Testen - + Add Server Server hinzufügen - + Remove Server Server löschen @@ -2159,145 +2290,81 @@ Um die Achsen umzukehren, bewege den Joystick zuerst vertikal und dann horizonta <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Mehr erfahren</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Port-Nummer hat ungültige Zeichen - + Port has to be in range 0 and 65353 Port muss zwischen 0 und 65353 liegen - + IP address is not valid IP Adresse ist ungültig - + This UDP server already exists Dieser UDP-Server existiert bereits - + Unable to add more than 8 servers Es können nicht mehr als 8 Server hinzugefügt werden - + Testing Testen - + Configuring Einrichten - + Test Successful Test erfolgreich - + Successfully received data from the server. Daten wurden erfolgreich vom Server empfangen. - + Test Failed Test fehlgeschlagen - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Konnte keine Daten vom Server empfangen.<br>Prüfe bitte, dass der Server korrekt eingerichtet wurde und dass Adresse und Port korrekt sind. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP-Test oder Kalibration wird gerade durchgeführt.<br>Bitte warte einen Moment. - - ConfigureMouseAdvanced - - - Configure Mouse - Maus einrichten - - - - Mouse Buttons - Maustasten - - - - Forward: - Vorwärts: - - - - Back: - Rückwärts: - - - - Left: - Links: - - - - Middle: - Mitte: - - - - Right: - Rechts: - - - - - Clear - Löschen - - - - Defaults - Standardwerte - - - - [not set] - [nicht belegt] - - - - Restore Default - Standardwert wiederherstellen - - - - [press key] - [Taste drücken] - - ConfigureNetwork @@ -3081,31 +3148,26 @@ Um die Achsen umzukehren, bewege den Joystick zuerst vertikal und dann horizonta - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory Skript-Verzeichnis - + Path Pfad - + ... ... @@ -3118,7 +3180,7 @@ Um die Achsen umzukehren, bewege den Joystick zuerst vertikal und dann horizonta TAS-Konfiguration - + Select TAS Load Directory... @@ -3180,37 +3242,37 @@ Ziehe die Punkte mit deiner Maus, um ihre Position zu ändern. Doppelklicke auf Y - + New Profile Neues Profil - + Enter the name for the new profile. Neuen Namen für das Profil eingeben. - + Delete Profile Profil löschen - + Delete profile %1? Profil "%1" löschen? - + Rename Profile Profil umbenennen - + New name: Neuer Name: - + [press key] [Knopf drücken] @@ -3630,12 +3692,12 @@ Ziehe die Punkte mit deiner Maus, um ihre Position zu ändern. Doppelklicke auf ControllerDialog - + Controller P1 Controller P1 - + &Controller P1 &Controller P1 @@ -3643,90 +3705,95 @@ Ziehe die Punkte mit deiner Maus, um ihre Position zu ändern. Doppelklicke auf GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonyme Daten werden gesammelt,</a> um yuzu zu verbessern.<br/><br/>Möchstest du deine Nutzungsdaten mit uns teilen? - + Telemetry Telemetrie - + Loading Web Applet... Lade Web-Applet... - - + + Disable Web Applet Deaktiviere die Web Applikation - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Durch deaktivieren des Web-Applets wird es für den Rest der emulierten Sitzung nicht mehr angezeigt. Dies kann zu undefiniertem Verhalten führen und sollte nur mit Super Mario 3D All-Stars verwendet werden. Das Web-Applet wirklich deaktivieren? - + The amount of shaders currently being built Wie viele Shader im Moment kompiliert werden - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Derzeitige Emulations-Geschwindigkeit. Werte höher oder niedriger als 100% zeigen, dass die Emulation scheller oder langsamer läuft als auf einer Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Wie viele Bilder pro Sekunde angezeigt werden variiert von Spiel zu Spiel und von Szene zu Szene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Zeit, die gebraucht wurde, um einen Switch-Frame zu emulieren, ohne Framelimit oder V-Sync. Für eine Emulation bei voller Geschwindigkeit sollte dieser Wert bei höchstens 16.67ms liegen. - + Invalid config detected Ungültige Konfiguration erkannt - + Handheld controller can't be used on docked mode. Pro controller will be selected. Handheld-Controller können nicht im Dock verwendet werden. Der Pro-Controller wird verwendet. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Zuletzt geladene Dateien leeren - - TAS Recording - TAS Aufnahme + + &Continue + &Fortsetzen - - Overwrite file of player 1? - Datei von Spieler 1 überschreiben? + + &Pause + @@ -3777,657 +3844,724 @@ Ziehe die Punkte mit deiner Maus, um ihre Position zu ändern. Doppelklicke auf Ein unbekannter Fehler ist aufgetreten. Bitte prüfe die Log-Dateien auf mögliche Fehlermeldungen. - + (64-bit) (64-Bit) - + (32-bit) (32-Bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Start - - - + Save Data Speicherdaten - + Mod Data Mod-Daten - + Error Opening %1 Folder Konnte Verzeichnis %1 nicht öffnen - - + + Folder does not exist! Verzeichnis existiert nicht! - + Error Opening Transferable Shader Cache Fehler beim Öffnen des transferierbaren Shader-Caches - + Failed to create the shader cache directory for this title. - + Contents Inhalte - + Update Update - + DLC DLC - + Remove Entry Eintrag entfernen - + Remove Installed Game %1? Installiertes Spiel %1 entfernen? - - - - - - + + + + + + Successfully Removed Erfolgreich entfernt - + Successfully removed the installed base game. Das Spiel wurde entfernt. - - - + + + Error Removing %1 Fehler beim Entfernen von %1 - + The base game is not installed in the NAND and cannot be removed. Das Spiel ist nicht im NAND installiert und kann somit nicht entfernt werden. - + Successfully removed the installed update. Das Update wurde entfernt. - + There is no update installed for this title. Es ist kein Update für diesen Titel installiert. - + There are no DLC installed for this title. Es sind keine DLC für diesen Titel installiert. - + Successfully removed %1 installed DLC. %1 DLC entfernt. - + Delete OpenGL Transferable Shader Cache? Transferierbaren OpenGL Shader Cache löschen? - + Delete Vulkan Transferable Shader Cache? Transferierbaren Vulkan Shader Cache löschen? - + Delete All Transferable Shader Caches? Alle transferierbaren Shader Caches löschen? - + Remove Custom Game Configuration? Spiel-Einstellungen entfernen? - + Remove File Datei entfernen - - + + Error Removing Transferable Shader Cache Fehler beim Entfernen - - + + A shader cache for this title does not exist. Es existiert kein Shader-Cache für diesen Titel. - + Successfully removed the transferable shader cache. Der transferierbare Shader-Cache wurde entfernt. - + Failed to remove the transferable shader cache. Konnte den transferierbaren Shader-Cache nicht entfernen. - - + + Error Removing Transferable Shader Caches Fehler beim Entfernen der transferierbaren Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Fehler beim Entfernen - + A custom configuration for this title does not exist. Es existieren keine Spiel-Einstellungen für dieses Spiel. - + Successfully removed the custom game configuration. Die Spiel-Einstellungen wurden entfernt. - + Failed to remove the custom game configuration. Die Spiel-Einstellungen konnten nicht entfernt werden. - - + + RomFS Extraction Failed! RomFS-Extraktion fehlgeschlagen! - + There was an error copying the RomFS files or the user cancelled the operation. Das RomFS konnte wegen eines Fehlers oder Abbruchs nicht kopiert werden. - + Full Komplett - + Skeleton Nur Ordnerstruktur - + Select RomFS Dump Mode RomFS Extraktions-Modus auswählen - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Bitte wähle, wie das RomFS gespeichert werden soll.<br>"Full" wird alle Dateien des Spiels extrahieren, während <br>"Skeleton" nur die Ordnerstruktur erstellt. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... RomFS wird extrahiert... - - + + Cancel Abbrechen - + RomFS Extraction Succeeded! RomFS wurde extrahiert! - + The operation completed successfully. Der Vorgang wurde erfolgreich abgeschlossen. - + Error Opening %1 Fehler beim Öffnen von %1 - + Select Directory Verzeichnis auswählen - + Properties Einstellungen - + The game properties could not be loaded. Spiel-Einstellungen konnten nicht geladen werden. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch-Programme (%1);;Alle Dateien (*.*) - + Load File Datei laden - + Open Extracted ROM Directory Öffne das extrahierte ROM-Verzeichnis - + Invalid Directory Selected Ungültiges Verzeichnis ausgewählt - + The directory you have selected does not contain a 'main' file. Das Verzeichnis, das du ausgewählt hast, enthält keine 'main'-Datei. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Installierbares Switch-Programm (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Dateien installieren - + %n file(s) remaining - + Installing file "%1"... Datei "%1" wird installiert... - - + + Install Results NAND-Installation - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Um Konflikte zu vermeiden, raten wir Nutzern davon ab, Spiele im NAND zu installieren. Bitte nutze diese Funktion nur zum Installieren von Updates und DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systemanwendung - + System Archive Systemarchiv - + System Application Update Systemanwendungsupdate - + Firmware Package (Type A) Firmware-Paket (Typ A) - + Firmware Package (Type B) Firmware-Paket (Typ B) - + Game Spiel - + Game Update Spiel-Update - + Game DLC Spiel-DLC - + Delta Title Delta-Titel - + Select NCA Install Type... Wähle den NCA-Installationstyp aus... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Bitte wähle, als was diese NCA installiert werden soll: (In den meisten Fällen sollte die Standardeinstellung 'Spiel' ausreichen.) - + Failed to Install Installation fehlgeschlagen - + The title type you selected for the NCA is invalid. Der Titel-Typ, den du für diese NCA ausgewählt hast, ist ungültig. - + File not found Datei nicht gefunden - + File "%1" not found Datei "%1" nicht gefunden - - - &Continue - &Fortsetzen - - - + OK OK - + Missing yuzu Account Fehlender yuzu-Account - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Um einen Kompatibilitätsbericht abzuschicken, musst du einen yuzu-Account mit yuzu verbinden.<br><br/>Um einen yuzu-Account zu verbinden, prüfe die Einstellungen unter Emulation &gt; Konfiguration &gt; Web. - + Error opening URL Fehler beim Öffnen der URL - + Unable to open the URL "%1". URL "%1" kann nicht geöffnet werden. - + + TAS Recording + TAS Aufnahme + + + + Overwrite file of player 1? + Datei von Spieler 1 überschreiben? + + + Amiibo File (%1);; All Files (*.*) Amiibo-Datei (%1);; Alle Dateien (*.*) - + Load Amiibo Amiibo laden - + Error opening Amiibo data file Fehler beim Öffnen der Amiibo Datei - + Unable to open Amiibo file "%1" for reading. Die Amiibo Datei "%1" konnte nicht zum Lesen geöffnet werden. - + Error reading Amiibo data file Fehler beim Lesen der Amiibo-Daten - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Amiibo-Daten können nicht vollständig gelesen werden. Es wurde erwartet, dass %1 Bytes gelesen werden, es konnten aber nur %2 Bytes gelesen werden. - + Error loading Amiibo data Fehler beim Laden der Amiibo-Daten - + Unable to load Amiibo data. Amiibo-Daten konnten nicht geladen werden. - + Capture Screenshot Screenshot aufnehmen - + PNG Image (*.png) PNG Bild (*.png) - + TAS state: Running %1/%2 TAS Zustand: Läuft %1/%2 - + TAS state: Recording %1 TAS Zustand: Aufnahme %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid TAS Zustand: Ungültig + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Geschwindigkeit: %1% / %2% - + Speed: %1% Geschwindigkeit: %1% - + Game: %1 FPS (Unlocked) Spiel: %1 FPS (Unbegrenzt) - + Game: %1 FPS Spiel: %1 FPS - + Frame: %1 ms Frame: %1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU HOCH - + GPU EXTREME GPU EXTREM - + GPU ERROR GPU FEHLER - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Das Spiel, dass du versuchst zu spielen, benötigt bestimmte Dateien von deiner Switch-Konsole.<br/><br/>Um Informationen darüber zu erhalten, wie du diese Dateien von deiner Switch extrahieren kannst, prüfe bitte die folgenden Wiki-Seiten: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>System-Archive und Shared Fonts von einer Switch-Konsole extrahieren</a>.<br/><br/>Willst du zur Spiele-Liste zurückkehren und die Emulation beenden? Das Fortsetzen der Emulation könnte zu Spielfehlern, Abstürzen, beschädigten Speicherdaten und anderen Fehlern führen. - + yuzu was unable to locate a Switch system archive. %1 yuzu konnte ein Switch Systemarchiv nicht finden. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu konnte ein Switch Systemarchiv nicht finden: %1. %2 - + System Archive Not Found Systemarchiv nicht gefunden - + System Archive Missing Systemarchiv fehlt - + yuzu was unable to locate the Switch shared fonts. %1 yuzu konnte die Switch Shared Fonts nicht finden. %1 - + Shared Fonts Not Found Shared Fonts nicht gefunden - + Shared Font Missing Shared Font fehlt - + Fatal Error Schwerwiegender Fehler - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Ein schwerwiegender Fehler ist aufgetreten, bitte prüfe die Log-Dateien auf mögliche Fehlermeldungen. Weitere Informationen: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Wie kann ich eine Log-Datei hochladen</a>.<br/><br/>Willst du zur Spiele-Liste zurückkehren und die Emulation beenden? Das Fortsetzen der Emulation könnte zu Spielfehlern, Abstürzen, beschädigten Speicherdaten und anderen Fehlern führen. - + Fatal Error encountered Fataler Fehler aufgetreten - + Confirm Key Rederivation Schlüsselableitung bestätigen - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4440,37 +4574,37 @@ This will delete your autogenerated key files and re-run the key derivation modu Dieser Prozess wird die generierten Schlüsseldateien löschen und die Schlüsselableitung neu starten. - + Missing fuses Fuses fehlen - + - Missing BOOT0 - BOOT0 fehlt - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Main fehlt - + - Missing PRODINFO - PRODINFO fehlt - + Derivation Components Missing Derivationskomponenten fehlen - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Einige Komponenten, die yuzu benötigt, um Schlüssel zu generieren, wurden nicht gefunden. <br>Bitte folge <a href='https://yuzu-emu.org/help/quickstart/'>dem yuzu Schnellstart-Guide</a> um alle deine Schlüssel und Spiele zu übertragen.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4478,39 +4612,39 @@ on your system's performance. Dies könnte, je nach Leistung deines Systems, bis zu einer Minute dauern. - + Deriving Keys Schlüsselableitung - + Select RomFS Dump Target RomFS wählen - + Please select which RomFS you would like to dump. Wähle, welches RomFS du speichern möchtest. - + Are you sure you want to close yuzu? Bist du sicher, dass du yuzu beenden willst? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Bist du sicher, dass du die Emulation stoppen willst? Jeder nicht gespeicherte Fortschritt geht verloren. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4522,38 +4656,38 @@ Möchtest du dies umgehen und sie trotzdem beenden? GRenderWindow - + OpenGL not available! OpenGL nicht verfügbar! - + yuzu has not been compiled with OpenGL support. yuzu wurde nicht mit OpenGL-Unterstützung kompiliert. - - + + Error while initializing OpenGL! Fehler beim Initialisieren von OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Deine Grafikkarte unterstützt kein OpenGL oder du hast nicht den neusten Treiber installiert. - + Error while initializing OpenGL 4.6! Fehler beim Initialisieren von OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Deine Grafikkarte unterstützt OpenGL 4.6 nicht, oder du benutzt nicht die neuste Treiberversion.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Deine Grafikkarte unterstützt anscheinend nicht eine oder mehrere von yuzu benötigten OpenGL-Erweiterungen. Bitte stelle sicher, dass du den neusten Grafiktreiber installiert hast.<br><br>GL Renderer:<br>%1<br><br>Nicht unterstützte Erweiterungen:<br>%2 @@ -4911,190 +5045,205 @@ Screen. &Emulation - + &View &Anzeige - + &Reset Window Size &Fenstergöße zurücksetzen - - Reset Window Size to &720p - Fenstergröße auf &720p zurücksetzen - - - - Reset Window Size to 720p - Fenstergröße auf 720p zurücksetzen - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - Fenstergröße auf &1080p zurücksetzen - - - - Reset Window Size to 1080p - Fenstergröße auf 1080p zurücksetzen - - - + &Debugging &Debugging - + + Reset Window Size to &720p + Fenstergröße auf &720p zurücksetzen + + + + Reset Window Size to 720p + Fenstergröße auf 720p zurücksetzen + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + Fenstergröße auf &1080p zurücksetzen + + + + Reset Window Size to 1080p + Fenstergröße auf 1080p zurücksetzen + + + &Tools &Werkzeuge - + + &TAS + + + + &Help &Hilfe - + &Install Files to NAND... &Dateien im NAND installieren... - + L&oad File... Datei &laden... - + Load &Folder... &Verzeichnis laden... - + E&xit S&chließen - - &Start - &Start - - - + &Pause &Pause - + &Stop &Stop - + &Reinitialize keys... &Schlüssel neu initialisieren... - + &About yuzu &Über yuzu - + Single &Window Mode &Einzelfenster-Modus - + Con&figure... Kon&figurieren - + Display D&ock Widget Headers D&ock-Widget-Header anzeigen - + Show &Filter Bar &Filterleiste anzeigen - + Show &Status Bar &Statusleiste anzeigen - + Show Status Bar Statusleiste anzeigen - + F&ullscreen Vollbild (&u) - + &Restart Neusta&rt - + Load &Amiibo... &Amiibo laden... - + &Report Compatibility &Kompatibilität melden - + Open &Mods Page &Mods-Seite öffnen - + Open &Quickstart Guide &Schnellstart-Anleitung öffnen - + &FAQ &FAQ - + Open &yuzu Folder &yuzu-Verzeichnis öffnen - + &Capture Screenshot &Bildschirmfoto aufnehmen - - Configure &TAS... - TAS &konfigurieren... + + &Configure TAS... + - + Configure C&urrent Game... &Spiel-Einstellungen ändern... + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5140,10 +5289,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE START/PAUSE + + + Charging + + QObject @@ -5174,142 +5328,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Strg - - + Alt Alt - - - + + [not set] [nicht gesetzt] - - Hat %1 %2 Hat %1 %2 - - - - - - + + + + Axis %1%2 Achse %1%2 - Button %1 Taste %1 - - - + + + [unknown] [unbekannt] - + + Left + + + + + Right + + + - Click 0 - Klick 0 + Down + - - Click 1 - Klick 1 + Up + - - Click 2 - Klick 2 + Z + - - Click 3 - Klick 3 + R + - - Click 4 - Klick 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC Achse %1%2 + + [invalid] + - - GC Button %1 - GC Knopf %1 + + + %1%2Hat %3 + - - TAS Axis %1 - TAS Achse %1 + + + + %1%2Axis %3 + - - TAS Btn %1 - TAS Knopf %1 + + %1%2Axis %3,%4,%5 + - - Motion %1 - Bewegung %1 + + %1%2Motion %3 + - - %1Button %2 - %1Knopf %2 + + + %1%2Button %3 + - - SDL Motion - SDL-Bewegung - - - - %1Click %2 - %1Klick %2 - - - + [unused] [unbenutzt] @@ -5350,7 +5584,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro-Controller @@ -5363,7 +5597,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Zwei Joycons @@ -5376,7 +5610,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Linker Joycon @@ -5389,7 +5623,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Rechter Joycon @@ -5417,7 +5651,7 @@ p, li { white-space: pre-wrap; } - + Handheld Handheld @@ -5538,7 +5772,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller GameCube-Controller @@ -5632,13 +5866,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Abbrechen diff --git a/dist/languages/es.ts b/dist/languages/es.ts index 2732a5923..a7583ba9f 100644 --- a/dist/languages/es.ts +++ b/dist/languages/es.ts @@ -36,17 +36,17 @@ p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu es un emulador experimental de código abierto de Nintendo Switch licenciado bajo GPLv2.0.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Este software no debe ser utilizado para jugar juegos que no hayas obtenido legalmente.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Este software no debe utilizarse para jugar juegos que no se hayan obtenido legalmente.</span></p></body></html> <html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Sitio web</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Código fuente</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidor</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Licencia</span></a></p></body></html> + <html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Sitio web</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Código fuente</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Licencia</span></a></p></body></html> <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.</span></p></body></html> - <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; es una marca registrada de Nintendo. yuzu no esta afiliado con Nintendo de ninguna manera.</span></p></body></html> + <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; es una marca registrada de Nintendo. yuzu no esta afiliado con Nintendo de ninguna forma.</span></p></body></html> @@ -74,7 +74,7 @@ p, li { white-space: pre-wrap; } Configuration completed! - ¡Configuración completa! + ¡Configuración completada! @@ -98,7 +98,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html> - <html><head/><body><p><span style=" font-size:10pt;">SI decides presentar una prueba a la </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Lista de Compatibilidad de yuzu</span></a><span style=" font-size:10pt;">, La siguiente información será obtenida y mostrada en el sitio web:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informacion de Hardware (CPU / GPU / Sistema Operativo)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qué versión de yuzu estas utilizando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">La cuenta de yuzu conectada</li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;">Si deseas presentar una prueba a la </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Lista de Compatibilidad de yuzu</span></a><span style=" font-size:10pt;">, La siguiente información será obtenida y mostrada en el sitio web:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informacion de Hardware (CPU / GPU / Sistema operativo)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Versión de yuzu que estés utilizando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">La cuenta de yuzu conectada</li></ul></body></html> @@ -118,7 +118,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> - <html><head/><body><p>El juego funciona con fallos gráficos o de audio menores y es jugable desde el principio hasta el final. Puede requerir de soluciones temporales.</p></body></html> + <html><head/><body><p>El juego funciona con fallos gráficos o de audio menores y es jugable de principio a fin. Puede que sea necesario recurrir a arreglos temporales.</p></body></html> @@ -128,7 +128,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - <html><head/><body><p>El juego funciona con importantes fallos gráficos o de audio, pero es jugable desde el principio hasta el final con soluciones temporales.</p></body></html> + <html><head/><body><p>El juego funciona con fallos gráficos o de audio sustanciales, pero es jugable de principio a fin con arreglos temporales.</p></body></html> @@ -138,17 +138,17 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - <html><head/><body><p>El juego funciona, pero tiene errores gráficos o de audio. Imposible progresar en ciertas áreas debido a errores incluso con soluciones temporales.</p></body></html> + <html><head/><body><p>El juego funciona, pero tiene errores gráficos o de audio. Imposible progresar en ciertas zonas debido a fallos incluso con arreglos temporales.</p></body></html> Intro/Menu - Intro/Menú + Intro/Menu <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - <html><head/><body><p>No es posible jugar a este juego debido a importantes errores gráficos o de audio. Es imposible avanzar mas allá de la pantalla de inicio.</p></body></html> + <html><head/><body><p>No es posible jugar a este juego debido a errores gráficos o de audio importantes. Es imposible avanzar mas allá de la pantalla de inicio.</p></body></html> @@ -163,7 +163,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html> - <html><head/><body><p>Independientemente de la velocidad o del rendimiento, ¿cómo definiría su experiencia con el juego de principio a fin en esta versión de yuzu?</p></body></html> + <html><head/><body><p>Independientemente de la velocidad o del rendimiento, ¿cómo definiría su experiencia de juego de principio a fin en esta versión de yuzu?</p></body></html> @@ -183,7 +183,7 @@ p, li { white-space: pre-wrap; } An error occurred while sending the Testcase - Un error a ocurrido mientras se enviaba el caso de prueba. + Ha ocurrido un fallo mientras se enviaba el caso de prueba. @@ -202,17 +202,17 @@ p, li { white-space: pre-wrap; } Output Engine: - Motor de Salida: + Motor de salida: Audio Device: - Dispositivo de Audio: + Dispositivo de audio: Use global volume - Usar el volumen global + Usar volumen global @@ -276,12 +276,12 @@ p, li { white-space: pre-wrap; } We recommend setting accuracy to "Auto". - Recomendamos ajustar la precisión a "Auto". + Recomendamos establecer la precisión en "Auto". Unsafe CPU Optimization Settings - Ajustes del Modo Impreciso de Optimización de la CPU + Ajustes del Modo Impreciso de optimización de la CPU @@ -294,13 +294,13 @@ p, li { white-space: pre-wrap; } <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> - <div>Esta opción mejora el rendimiento al reducir la precisión de las instrucciones fused-multiply-add en las CPU sin soporte nativo de FMA.</div> + <div>Esta opción mejora el rendimiento al reducir la precisión de las instrucciones fused-multiply-add en las CPU sin soporte nativo FMA.</div> Unfuse FMA (improve performance on CPUs without FMA) - Unfuse FMA (mejora el rendimiento en las CPU sin FMA) + Desactivar FMA (mejora el rendimiento en las CPU sin FMA) @@ -314,7 +314,7 @@ p, li { white-space: pre-wrap; } Faster FRSQRTE and FRECPE - FRSQRTE y FRECPE más rápido + FRSQRTE y FRECPE rápido @@ -322,7 +322,7 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - <div>Esta opción mejora la velocidad de las funciones de punto flotante ASIMD de 32 bits al ejecutarlas con modos aproximados e incorrectos.</div> + <div>Esta opción mejora la velocidad de las funciones de punto flotante ASIMD de 32 bits al ejecutarlas con métodos aproximados e incorrectos.</div> @@ -336,13 +336,13 @@ p, li { white-space: pre-wrap; } <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> - <div>Esta opción mejora la velocidad eliminando el revisor NaN. Tenga en cuenta que esto también reduce la precisión de algunas instrucciones de coma flotante</div> + <div>Esta opción mejora la velocidad eliminando las comprobaciones NaN. Ten en cuenta que esto también reduce la precisión de algunas instrucciones de punto flotante.</div> Inaccurate NaN handling - Manejo inexacto de NaN + Gestión imprecisa NaN @@ -350,18 +350,18 @@ p, li { white-space: pre-wrap; } <div>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.</div> - <div>Esta opción mejora la velocidad al eliminar un control de seguridad antes de cada lectura/escritura de memoria en el invitado. Desactivarlo podría permitir que los juegos que lean/escriban en la memoria del emulador.</div> + <div>Esta opción mejora la velocidad al eliminar un control de seguridad antes de cada lectura/escritura de memoria del anfitrión. Desactivarlo podría permitir que los juegos lean/escriban en la memoria del emulador.</div> Disable address space checks - Desactivar controles del espacio de direcciones + Desactivar comprobación del espacio de destino CPU settings are available only when game is not running. - Los ajustes de la CPU sólo se encuentran disponibles cuando no se está ejecutando ningún juego. + Los ajustes de la CPU sólo están disponibles cuando no se esté ejecutando ningún juego. @@ -384,7 +384,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Sólo para depurar.</span><br/>Si no tienes la certeza de lo que hacen, déjalas activadas. <br/>Esas opciones, cuando están desactivadas, sólo funcionarán cuando Depuración de CPU está activada. </p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sólo para depurar.</span><br/>Si no estás seguro de su función, déjalas activadas. <br/>Estas opciones, cuando estén desactivadas, sólo funcionarán cuando la Depuración de CPU esté activada. </p></body></html> @@ -394,15 +394,15 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> - <div style="white-space: nowrap">Esta optimización acelera los accesos a la memoria del programa del invitado.</div> - <div style="white-space: nowrap">Activando las inlines accede a PageTable::pointers en código emitido.</div> - <div style="white-space: nowrap">Desactivando esto obliga a que todos los accesos a la memoria pasen por las funciones Memory::Read/Memory::Write.</div> + <div style="white-space: nowrap">Esta optimización acelera los accesos a la memoria del programa anfitrión.</div> + <div style="white-space: nowrap">Al activarlo, integra los accesos a PageTable::pointers en el código emitido.</div> + <div style="white-space: nowrap">Al desactivar esto, obliga a que todos los accesos a la memoria pasen por las funciones Memory::Read/Memory::Write.</div> Enable inline page tables - Activar las tablas de páginas inline. + Activar las tablas de páginas integradas. @@ -410,13 +410,13 @@ p, li { white-space: pre-wrap; } <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> - <div>Esta optimización evita las búsquedas del despachador permitiendo que los bloques básicos emitidos salten directamente a otros bloques básicos si el PC de destino es estático.</div> + <div>Esta optimización evita las búsquedas del emisor permitiendo que los bloques básicos emitidos salten directamente a otros bloques básicos si el PC de destino es estático.</div> Enable block linking - Activar el enlace de bloques + Activar enlace de bloques @@ -424,13 +424,13 @@ p, li { white-space: pre-wrap; } <div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div> - <div>Esta optimización evita las búsquedas de los despachadores al rastrear las direcciones potenciales de retorno de las instrucciones de BL. Esto se aproxima a lo que sucede con un buffer de la pila de retorno en una CPU real.</div> + <div>Esta optimización evita las búsquedas del emisor al rastrear las direcciones potenciales de retorno de las instrucciones BL. Esto se aproxima a lo que sucede con un buffer acumulado de retorno en una CPU real.</div> Enable return stack buffer - Activar el buffer de la pila de retorno + Activar buffer acumulado de retorno @@ -438,13 +438,13 @@ p, li { white-space: pre-wrap; } <div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div> - <div>Habilitar un sistema de despacho de dos niveles. Un despachador más rápido escrito en ensamblado tiene un pequeño caché MRU de destinos de salto se utiliza primero. Si eso falla, el despacho vuelve al despacho más lento de C++.</div> + <div>Habilitar un sistema de emisión de dos niveles. Un emisor más rápido escrito en ensamblado que tiene un pequeño caché MRU de destinos de salto se utiliza primero. Si esto falla, el emisor vuelve al emisor más lento de C++.</div> Enable fast dispatcher - Activar el despachador rápido + Activar emisor rápido @@ -452,13 +452,13 @@ p, li { white-space: pre-wrap; } <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> - <div>Esto habilita una optimización de IR que reduce los accesos innecesarios a la estructura del contexto de la CPU.</div> + <div>Activa una optimización de IR que reduce los accesos innecesarios a la estructura del contexto de la CPU.</div> Enable context elimination - Activar la eliminación del contexto + Activar eliminación de contexto @@ -466,13 +466,13 @@ p, li { white-space: pre-wrap; } <div>Enables IR optimizations that involve constant propagation.</div> - <div>Esto habilita optimizaciones de IR que implican una propagación constante.</div> + <div>Activa optimizaciones de IR que implican una propagación constante.</div> Enable constant propagation - Activar la propagación constante + Activar propagación constante @@ -480,7 +480,7 @@ p, li { white-space: pre-wrap; } <div>Enables miscellaneous IR optimizations.</div> - <div>Esto habilita optimizaciónes misceláneas IR.</div> + <div>Activa optimizaciones misceláneas IR.</div> @@ -495,14 +495,14 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> - <div style="white-space: nowrap">Cuando está activada, una desalineación sólo se activa cuando un acceso cruza el límite de una página.</div> - <div style="white-space: nowrap">Cuando está desactivado, se desencadena una desalineación en todos los accesos desalineados.</div> + <div style="white-space: nowrap">Cuando esté activada, una desalineación sólo se activa cuando un acceso cruza el límite de una página.</div> + <div style="white-space: nowrap">Cuando esté desactivado, se produce una desalineación en todos los accesos desalineados.</div> Enable misalignment check reduction - Activar la reducción del control de desalineación + Activar reducción del control de desalineación @@ -512,20 +512,20 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> - <div style="white-space: nowrap">Esta optimización acelera los accesos de memoria por el programa invitado.</div> - <div style="white-space: nowrap">Activarlo causa que la lectura/escritura de la memoria invitada se haga directamente en memoria y usen el MMU del Host.</div> + <div style="white-space: nowrap">Esta optimización acelera los accesos de memoria por el programa anfitrión.</div> + <div style="white-space: nowrap">Activarlo causa que la lectura/escritura de la memoria del anfitrión se haga directamente en la memoria y utilicen el MMU del Host.</div> <div style="white-space: nowrap">Desactivar esto fuerza a todos los accesos de memoria a usar la Emulación del Software de MMU.</div> Enable Host MMU Emulation - Activar emulación de MMU del Host + Activar emulación MMU del Host CPU settings are available only when game is not running. - Los ajustes de la CPU sólo se encuentran disponibles cuando no se está ejecutando ningún juego. + Los ajustes de la CPU sólo están disponibles cuando no se esté ejecutando ningún juego. @@ -538,7 +538,7 @@ p, li { white-space: pre-wrap; } Global Log Filter - Filtro de Registro Global + Filtro del registro global @@ -548,7 +548,7 @@ p, li { white-space: pre-wrap; } Open Log Location - Abrir Ubicación del Registro + Abrir ubicación del archivo de registro @@ -568,7 +568,7 @@ p, li { white-space: pre-wrap; } Arguments String - Cadena de Argumentos + Cadena de argumentos @@ -578,17 +578,17 @@ p, li { white-space: pre-wrap; } When checked, the graphics API enters a slower debugging mode - Cuando se marque, la API gráfica entrará en un modo de depuración más lento. + Cuando esté marcado, la API gráfica entrará en un modo de depuración más lento. Enable Graphics Debugging - Activar la Depuración de Gráficos + Activar depuración de gráficos When checked, it enables Nsight Aftermath crash dumps - Cuando se marque, activará los volcados de bloqueos de Nsight Aftermath + Cuando esté marcado, activará los volcados de los fallos Nsight Aftermath @@ -598,27 +598,27 @@ p, li { white-space: pre-wrap; } When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower - Cuando está marcado, se desactiva el compilador de macro Just In Time. Activando esto hace que los juegos se ejecuten más lento + Cuando esté marcado, se desactiva el compilador de macro Just In Time. Activar esto hace que los juegos se ejecuten más lento. Disable Macro JIT - Desactivar Macro JIT + Desactivar macro JIT When checked, yuzu will log statistics about the compiled pipeline cache - Cuando se marque, yuzu hará un registro de las estadísticas de la tubería de caché compilada + Cuando esté marcado, yuzu hará un registro de las estadísticas del caché de tubería compilado Enable Shader Feedback - Activar feedback de cache + Activar información de shaders When checked, it executes shaders without loop logic changes - Cuando se marque, se ejecutarán los shaders sin cambios de bucles lógicos. + Cuando esté marcado, se ejecutarán los shaders sin cambios de bucles lógicos. @@ -633,12 +633,12 @@ p, li { white-space: pre-wrap; } Enable FS Access Log - Activar Registro de FS Access + Activar registro de acceso FS Enable Verbose Reporting Services** - Habilitar Servicios de Reporte Detallados** + Activar servicios de reporte detallados** @@ -648,17 +648,17 @@ p, li { white-space: pre-wrap; } Kiosk (Quest) Mode - Modo Quiosco (Quest) + Modo quiosco (Quest) Enable CPU Debugging - Activar la Depuración de CPU + Activar depuración de la CPU Enable Debug Asserts - Habilitar declaraciones de depuración + Activar alertas de depuración @@ -666,9 +666,14 @@ p, li { white-space: pre-wrap; } Activar Auto-Stub** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. - **Se reiniciará automáticamente cuando yuzu se cierre. + **Esto se reiniciará automáticamente cuando yuzu se cierre. @@ -676,7 +681,7 @@ p, li { white-space: pre-wrap; } Configure Debug Controller - Configurar el Control de Depuración + Configurar el controlador de depuración @@ -686,7 +691,7 @@ p, li { white-space: pre-wrap; } Defaults - Valores Predeterminados + Valores predeterminados @@ -713,7 +718,7 @@ p, li { white-space: pre-wrap; } yuzu Configuration - Configuración de yuzu. + Configuración de yuzu @@ -735,7 +740,7 @@ p, li { white-space: pre-wrap; } Filesystem - Sistema de Archivos + Sistema de archivos @@ -752,12 +757,12 @@ p, li { white-space: pre-wrap; } GraphicsAdvanced - GráficosAvanzados + Gráficosavanzados Hotkeys - Teclas de Acceso Rápido + Teclas de acceso rápido @@ -784,7 +789,7 @@ p, li { white-space: pre-wrap; } Game List - Lista de Juegos + Lista de juegos @@ -802,12 +807,12 @@ p, li { white-space: pre-wrap; } Filesystem - Sistema de Archivos + Sistema de archivos Storage Directories - Directorios de Almacenamiento + Directorios de almacenamiento @@ -831,7 +836,7 @@ p, li { white-space: pre-wrap; } Gamecard - Cartucho de Juegos + Cartucho de juego @@ -846,42 +851,42 @@ p, li { white-space: pre-wrap; } Current Game - Juego Actual + Juego actual Patch Manager - Administrador de Parches + Administrador de parches Dump Decompressed NSOs - Volcar NSOs Descomprimidos + Volcar NSOs descomprimidos Dump ExeFS - Volcar Partición ExeFS + Volcar ExeFS Mod Load Root - Carpeta raíz de carga de Mods + Carpeta raíz de carga de mods Dump Root - Carpeta raíz de Volcado + Carpeta raíz de volcado Caching - Cargando Caché + Cargando caché Cache Game List Metadata - Metadatos de Lista de Juegos en Caché + Metadatos de lista de juegos en caché @@ -889,32 +894,32 @@ p, li { white-space: pre-wrap; } Reset Metadata Cache - Reiniciar Caché de Metadatos + Reiniciar caché de metadatos Select Emulated NAND Directory... - Seleccione el directorio de NAND Emulado... + Selecciona el directorio de NAND emulado... Select Emulated SD Directory... - Seleccione el directorio de SD Emulado... + Seleccione el directorio de SD emulado... Select Gamecard Path... - Seleccione la ruta del Cartucho... + Seleccione la ruta del cartucho... Select Dump Directory... - Seleccione Directorio para Volcar... + Seleccione directorio de volcado... Select Mod Load Directory... - Seleccione el directorio de carga de Mod... + Seleccione el directorio de carga de mod... @@ -946,69 +951,80 @@ p, li { white-space: pre-wrap; } General - - Framerate Cap - Límite de cuadros por segundo + + + Use global framerate cap + Utilizar límite global de fotogramas - + + Set framerate cap: + Establece el límite de fotogramas: + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - Se necesita el uso de la tecla de acceso rápido Cambiar Límite de FPS para que tenga efecto. + Es necesario el uso de la tecla de acceso rápido Cambiar límite de FPS para que tenga efecto. - + + Framerate Cap + Límite de fotogramas + + + x x - + Limit Speed Percent - Limitar el Porcentaje de Velocidad + Limitar porcentaje de velocidad - + % % - + Multicore CPU Emulation Emulación de CPU multinúcleo - + Confirm exit while emulation is running Confirmar salida mientras se ejecuta la emulación - + Prompt for user on game boot Mostrar usuario actual al abrir el juego - + Pause emulation when in background Pausar emulación cuando la ventana esté en segundo plano - + Hide mouse on inactivity - Ocultar el cursor del ratón cuando no está activo. + Ocultar el cursor en caso de inactividad. - + Reset All Settings - Reiniciar todos los Ajustes + Reiniciar todos los ajustes - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? - Ésto reinicia todas las configuraciones y eliminará todas las configuraciones de cada juego. No eliminará ni los directorios de juego, ni perfiles, ni perfiles de control. ¿Continuar? + Esto reiniciará y eliminará todas las configuraciones de los juegos. No eliminará ni los directorios de juego, ni los perfiles, ni los perfiles de los mandos. ¿Continuar? @@ -1031,7 +1047,7 @@ p, li { white-space: pre-wrap; } Shader Backend: - Backend de Shaders: + Soporte de shaders: @@ -1046,12 +1062,12 @@ p, li { white-space: pre-wrap; } Graphics Settings - Ajustes de los Gráficos + Ajustes de gráficos Use disk pipeline cache - Usar caché de shaders en tubería + Usar caché de shaders de tubería @@ -1076,17 +1092,17 @@ p, li { white-space: pre-wrap; } CPU Video Decoding - Decodificación de vídeo de CPU + Decodificación de vídeo en la CPU GPU Video Decoding (Default) - Decodificación de vídeo de GPU (Por defecto) + Decodificación de vídeo en GPU (Por defecto) Fullscreen Mode: - Modo Pantalla Completa: + Modo pantalla completa: @@ -1096,17 +1112,17 @@ p, li { white-space: pre-wrap; } Exclusive Fullscreen - Pantalla completa exclusiva + Pantalla completa Aspect Ratio: - Relación de Aspecto: + Relación de aspecto: Default (16:9) - Valor Predeterminado (16:9) + Valor predeterminado (16:9) @@ -1121,28 +1137,123 @@ p, li { white-space: pre-wrap; } Stretch to Window - Estirar a la Ventana + Ajustar a la ventana - - + + Resolution: + Resolución: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + x0.5 (360p/540p) [EXPERIMENTAL] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + x0.75 (540p/810p) [EXPERIMENTAL] + + + + 1X (720p/1080p) + x1 (720p/1080p) + + + + 2X (1440p/2160p) + x2 (1440p/2160p) + + + + 3X (2160p/3240p) + x3 (2160p/3240p) + + + + 4X (2880p/4320p) + x4 (2880p/4320p) + + + + 5X (3600p/5400p) + x5 (3600p/5400p) + + + + 6X (4320p/6480p) + x6 (4320p/6480p) + + + + Window Adapting Filter: + Filtro adaptable de ventana: + + + + Nearest Neighbor + Proveedor más cercano + + + + Bilinear + Bilineal + + + + Bicubic + Bicúbico + + + + Gaussian + Gaussiano + + + + ScaleForce + ScaleForce + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + AMD FidelityFX™️ Super Resolution [Sólo Vulkan] + + + + Anti-Aliasing Method: + Método de Anti-Aliasing: + + + + None + Ninguno + + + + FXAA + FXAA + + + + Use global background color Usar el color de fondo global - + Set background color: Establecer el color de fondo: - + Background Color: - Color de Fondo: + Color de fondo: GLASM (Assembly Shaders, NVIDIA Only) - GLASM (Assembly Shaders, Sólo NVIDIA) + GLASM (Assembly shaders, sólo NVIDIA) @@ -1160,27 +1271,27 @@ p, li { white-space: pre-wrap; } Advanced Graphics Settings - Ajustes de los Gráficos Avanzados + Ajustes avanzados de gráficos Accuracy Level: - Nivel de Precisión: + Nivel de precisión: VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync evita que la pantalla se distorsione, pero algunas tarjetas gráficas tienen un rendimiento menor con VSync activado. Mantenlo activado si no notas una diferencia de rendimiento. + El VSync evita que la pantalla se distorsione, pero algunas tarjetas gráficas tienen un menor rendimiento con el VSync activado. Mantenlo activado si no notas diferencias en el rendimiento. Use VSync (OpenGL only) - Usar VSync (sólo en OpenGL) + Usar VSync (sólo OpenGL) Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental. - Activa la compilación de shaders en modo asíncrono, cuál podría reducir el tartamudeo de los shaders. Esta función es experimental. + Activa la compilación de shaders en modo asíncrono, lo que puede reducir la sobrecarga de shaders. Esta función es experimental. @@ -1195,37 +1306,42 @@ p, li { white-space: pre-wrap; } Use Fast GPU Time (Hack) - Usar Tiempo Rápido en la GPU (Hack) + Usar tiempo rápido en la GPU (Hack) Anisotropic Filtering: - Filtrado Anisotrópico: + Filtrado anisotrópico: - Default - Valor Predeterminado + Automatic + Automático - 2x (WILL BREAK THINGS) - 2x (ROMPERÁ COSAS) + Default + Valor predeterminado - 4x (WILL BREAK THINGS) - 4x (ROMPERÁ COSAS) + 2x + x2 - 8x (WILL BREAK THINGS) - 8x (ROMPERÁ COSAS) + 4x + x4 - 16x (WILL BREAK THINGS) - 16x (ROMPERÁ COSAS) + 8x + x8 + + + + 16x + x16 @@ -1233,12 +1349,12 @@ p, li { white-space: pre-wrap; } Hotkey Settings - Configuración de Teclas de Acceso Rápido + Configuración de teclas de acceso rápido Hotkeys - Teclas de Acceso Rápido + Teclas de acceso rápido @@ -1248,12 +1364,12 @@ p, li { white-space: pre-wrap; } Clear All - Limpiar Todo + Borrar todo Restore Defaults - Restaurar Valores Predeterminados + Restaurar valores predeterminados @@ -1263,7 +1379,7 @@ p, li { white-space: pre-wrap; } Hotkey - Tecla de Acceso Rápido + Tecla de acceso rápido @@ -1274,17 +1390,17 @@ p, li { white-space: pre-wrap; } Conflicting Key Sequence - Secuencia de Teclas en Conflicto + Combinación de teclas en conflicto The entered key sequence is already assigned to: %1 - La secuencia de teclas introducida ya ha sido asignada a: %1 + La combinación de teclas introducida ya ha sido asignada a: %1 Restore Default - Restaurar Valor Predeterminado + Restaurar valor predeterminado @@ -1294,7 +1410,7 @@ p, li { white-space: pre-wrap; } The default key sequence is already assigned to: %1 - La secuencia de teclas predeterminada ya ha sido asignada a: %1 + La combinación de teclas predeterminada ya ha sido asignada a: %1 @@ -1302,7 +1418,7 @@ p, li { white-space: pre-wrap; } ConfigureInput - ConfigurarEntrada + Configurarentrada @@ -1361,12 +1477,12 @@ p, li { white-space: pre-wrap; } Console Mode - Modo de la Consola + Modo de la consola Docked - Acoplado + Sobremesa @@ -1392,7 +1508,7 @@ p, li { white-space: pre-wrap; } Controllers - Controladores + Mandos @@ -1442,7 +1558,7 @@ p, li { white-space: pre-wrap; } Defaults - Valores Predeterminados + Predeterminados @@ -1455,12 +1571,12 @@ p, li { white-space: pre-wrap; } Configure Input - Configurar Controles + Configurar controles Joycon Colors - Colores de Joycon + Colores de los Joycon @@ -1477,7 +1593,7 @@ p, li { white-space: pre-wrap; } L Body - Lado L + Parte L @@ -1501,7 +1617,7 @@ p, li { white-space: pre-wrap; } R Body - Lado R + Parte R @@ -1552,8 +1668,8 @@ p, li { white-space: pre-wrap; } - Other - Otro + Emulated Devices + Dispositivos Emulados @@ -1562,65 +1678,74 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emular entrada analógica con teclado - - - - Enable mouse panning - Activar barrido del ratón - - - - Mouse sensitivity - Sensibilidad del Mouse - - - - % - % - - - - - Advanced - Avanzado - - - - Touchscreen - Pantalla Táctil - - - Mouse Ratón - - Motion / Touch - Movimiento / Táctil + + Touchscreen + Pantalla táctil - - + + Advanced + Avanzado + + + + Debug Controller + Depurar controlador + + + + Configure Configurar - - Debug Controller - Controlador de Depuración + + Other + Otros - + + Emulate Analog with Keyboard Input + Emular entradas analógicas con teclado + + + Requires restarting yuzu - Requiere un reinicio de yuzu + Requiere reiniciar yuzu - + Enable XInput 8 player support (disables web applet) - Activar soporte de 8 jugadores de XInput (desactiva la web applet) + Activar soporte de 8 jugadores XInput (desactiva la web applet) + + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Activar desplazamiento del ratón + + + + Mouse sensitivity + Sensibilidad del ratón + + + + % + % + + + + Motion / Touch + Movimiento / táctil @@ -1628,435 +1753,451 @@ p, li { white-space: pre-wrap; } Configure Input - Configurar Controles + Configurar controles Connect Controller - Conectar el Controlador + Conectar controlador - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Doble Joycons - - - - - Left Joycon - Joycon Izquierdo - - - - - Right Joycon - Joycon Derecho - - - - - Handheld - Portátil - - - + Input Device - Dispositivo de Entrada + Dispositivo de entrada - - Any - Cualquier - - - - Keyboard/Mouse - Teclado/Ratón - - - + Profile Perfil - + Save Guardar - + New Crear - + Delete Borrar - - + + Left Stick - Palanca Izquierda + Palanca izquierda - - - - - - + + + + + + Up Arriba - - - - - - - + + + + + + + Left Izquierda - - - - - - - + + + + + + + Right Derecha - - - - - - + + + + + + Down Abajo - - - - + + + + Pressed Presionado - - - - + + + + Modifier Modificador - - + + Range Rango - - + + % % - - + + Deadzone: 0% - Zona Muerta: 0% + Punto muerto: 0% - - + + Modifier Range: 0% - Rango del Modificador: 0% + Rango del modificador: 0% - + D-Pad Cruceta - - - + + + L L - - - + + + ZL ZL - - + + Minus Menos - - + + Capture Captura - - - + + + Plus Más - - + + Home Inicio - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Movimiento 1 - + Motion 2 Movimiento 2 - + Face Buttons - Botones Frontales + Botones frontales - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick - Palanca Derecha + Palanca derecha - - - - + + + + Clear Borrar - - - - + + + + [not set] [no definido] - - + + Toggle button Alternar botón - - + + Invert button + + + + + + Invert axis + Invertir ejes + + + + Set threshold Configurar umbral - + Choose a value between 0% and 100% Seleccione un valor entre 0% y 100%. - + Map Analog Stick - Configurar Mando Analógico + Configuración de palanca analógico - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. - Después de pulsar OK, primero mueve tu joystick de manera horizontal, y luego verticalmente. -Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego horizontalmente. + Después de pulsar OK, mueve primero el joystick de manera horizontal, y luego verticalmente. +Para invertir los ejes, mueve primero el joystick de manera vertical, y luego horizontalmente. - - Invert axis - Invertir axis - - - - + + Deadzone: %1% - Zona Muerta: %1% + Punto muerto: %1% - - + + Modifier Range: %1% - Rango del Modificador: %1% + Rango del modificador: %1% - + + + Pro Controller + Controlador Pro + + + + Dual Joycons + Joycons duales + + + + Left Joycon + Joycon izquierdo + + + + Right Joycon + Joycon derecho + + + + Handheld + Portátil + + + GameCube Controller - Controlador GameCube + Controlador de GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause - Empezar / Parar + Inicio / Pausa - + Z Z - + Control Stick Palanca de control - + C-Stick C-Stick - + Shake! ¡Agita! - + [waiting] [esperando] - + New Profile - Nuevo Perfil + Nuevo perfil + + + + Enter a profile name: + Introduce un nombre de perfil: + + + + + Create Input Profile + Crear perfil de entrada + + + + The given profile name is not valid! + ¡El nombre de perfil introducido no es válido! + + + + Failed to create the input profile "%1" + Error al crear el perfil de entrada "%1" + + + + Delete Input Profile + Eliminar perfil de entrada + + + + Failed to delete the input profile "%1" + Error al eliminar el perfil de entrada "%1" + + + + Load Input Profile + Cargar perfil de entrada + + + + Failed to load the input profile "%1" + Error al cargar el perfil de entrada "%1" + + + + Save Input Profile + Guardar perfil de entrada - Enter a profile name: - Introduzca un nombre de perfil: - - - - - Create Input Profile - Crear Perfil de Entrada - - - - The given profile name is not valid! - El nombre de perfil dado no es valido! - - - - Failed to create the input profile "%1" - Fallo al crear el perfil de entrada "%1" - - - - Delete Input Profile - Eliminar Perfil de Entrada - - - - Failed to delete the input profile "%1" - Fallo al eliminar el perfil de entrada "%1" - - - - Load Input Profile - Cargar Perfil de Entrada - - - - Failed to load the input profile "%1" - Fallo al cargar el perfil de entrada "%1" - - - - Save Input Profile - Guardar Perfil de Entrada - - - Failed to save the input profile "%1" - Fallo al guardar el perfil de entrada "%1" + Error al guardar el perfil de entrada "%1" @@ -2064,7 +2205,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Create Input Profile - Crear Perfil de Entrada + Crear perfil de entrada @@ -2074,237 +2215,163 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Defaults - Valores Predeterminados + Predeterminados ConfigureMotionTouch - + Configure Motion / Touch - Configurar: Movimiento / Táctil + Configurar: movimiento / táctil - - Mouse Motion - Movimiento del Ratón - - - - Sensitivity: - Sensibilidad: - - - + Touch Táctil - + UDP Calibration: Calibración UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configurar - - Use button mapping: - Usar el mapeo de botones: + + Touch from button profile: + - + CemuhookUDP Config Configuración CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. - Puede utilizar cualquier fuente de entrada UDP compatible con Cemuhook para proporcionar una entrada de movimiento y de tacto. + Puedes utilizar cualquier fuente de entrada UDP compatible con Cemuhook para proporcionar una entrada de movimiento y táctil. - + Server: Servidor: - + Port: Puerto: - + Learn More - Más Información + Más información - - + + Test Probar - + Add Server - Añadir Servidor + Añadir servidor - + Remove Server - Eliminar Servidor + Eliminar servidor <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Más Información</span></a> + <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Más información</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters - El numero del puerto tiene caracteres invalidos + El número del puerto tiene caracteres que no son válidos - + Port has to be in range 0 and 65353 - El puerto tiene que estar en el rango de 0 y 65353 + El puerto debe estar en un rango entre 0 y 65353 - + IP address is not valid - Dirección IP no valida + Dirección IP no válida - + This UDP server already exists Este servidor UDP ya existe - + Unable to add more than 8 servers - Incapaz de añadir mas de 8 servidores + No es posible añadir más de 8 servidores - + Testing Probando - + Configuring Configurando - + Test Successful - Prueba Existosa + Prueba existosa - + Successfully received data from the server. - Se recibió con éxito los datos del servidor. + Se han recibido con éxito los datos del servidor. - + Test Failed Prueba fallida - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - No pudo recibir datos válidos del servidor.<br>Por favor, verifique que el servidor esté configurado correctamente y que la dirección y el puerto sean correctos. + No se han podido recibir datos válidos del servidor.<br>Por favor, verifica que el servidor esté configurado correctamente y que la dirección y el puerto sean correctos. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - La prueba de UDP o la configuración de la calibración está en curso.<br>Por favor, espere a que termine el proceso. - - - - ConfigureMouseAdvanced - - - Configure Mouse - Configurar el Ratón - - - - Mouse Buttons - Botones del Ratón - - - - Forward: - Adelante: - - - - Back: - Atrás: - - - - Left: - Izquierda: - - - - Middle: - Medio: - - - - Right: - Derecha: - - - - - Clear - Borrar - - - - Defaults - Valores Predeterminados - - - - [not set] - [no establecido] - - - - Restore Default - Restaurar Valor Predeterminado - - - - [press key] - [pulsa un botón] + La prueba de UDP o la configuración de la calibración está en curso.<br>Por favor, espera a que termine el proceso. @@ -2355,12 +2422,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Title ID - ID del Título + ID del título Filename - Nombre del Archivo + Nombre del archivo @@ -2385,7 +2452,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Add-Ons - Complementos + Extras / Add-Ons @@ -2410,7 +2477,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Adv. Graphics - + Gráficos avanz. @@ -2425,7 +2492,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Use global configuration (%1) - Usar la configuración global (%1) + Usar configuración global (%1) @@ -2438,12 +2505,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Add-Ons - Complementos + Extras / Add-Ons Patch Name - Nombre del Parche + Nombre del parche @@ -2466,22 +2533,22 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Profile Manager - Administrador de Perfiles + Administrador de perfiles Current User - Usuario Actual + Usuario actual Username - Nombre de Usuario + Nombre de usuario Set Image - Seleccionar Imagen + Seleccionar imagen @@ -2501,7 +2568,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Profile management is available only when game is not running. - El sistema de perfiles solo se encuentra disponible cuando no se está ejecutando ningún juego. + El sistema de perfiles sólo se encuentra disponible cuando no se esté ejecutando ningún juego. @@ -2514,7 +2581,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Enter Username - Introduzca el Nombre de Usuario + Introduzca el nombre @@ -2524,17 +2591,17 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Enter a username for the new user: - Introduzca un nombre para el nuevo usuario: + Introduce un nombre para el nuevo usuario: Enter a new username: - Introduzca un nuevo nombre de usuario: + Introduce un nuevo nombre de usuario: Confirm Delete - Confirmar Eliminanación + Confirmar eliminación @@ -2544,7 +2611,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Select User Image - Seleccione una Imagen de Usuario + Selecciona una imagen de usuario @@ -2559,17 +2626,17 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Error occurred attempting to overwrite previous image at: %1. - Ocurrió un error al intentar sobrescribir la imagen anterior en: %1. + Ha ocurrido un error al intentar sobrescribir la imagen anterior en: %1. Error deleting file - Error eliminando archivo + Error al eliminar el archivo Unable to delete existing file: %1. - No se pudo eliminar el archivo existente: %1. + No se puede eliminar el archivo existente: %1. @@ -2579,12 +2646,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Unable to create directory %1 for storing user images. - No se puede crear el directorio % 1 para almacenar imágenes de usuario. + No se puede crear el directorio %1 para almacenar imágenes de usuario. Error copying user image - Error al copiar la imagen del usuario. + Error al copiar la imagen de usuario. @@ -2594,12 +2661,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Error resizing user image - + Error al redimensionar la imagen de usuario Unable to resize image - + No se puede cambiar el tamaño de la imagen @@ -2632,7 +2699,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Default - Valor Predeterminado + Predeterminado @@ -2727,7 +2794,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Iran - Iran + Irán @@ -2853,7 +2920,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Zulu - Zulu + Zulú @@ -2883,17 +2950,17 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Taiwan - Taiwan + Taiwán Time Zone: - Zona Horaria + Zona horaria: Note: this can be overridden when region setting is auto-select - Nota: esto puede ser ignorado cuando la opción de región está en "autoseleccionar" + Nota: esto puede ser reemplazado si la opción de región está en "autoseleccionar" @@ -2913,7 +2980,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho German (Deutsch) - Alemán (Deutsch) + Alemán (deutsch) @@ -2938,7 +3005,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Dutch (Nederlands) - Holandés (Nederlands) + Holandés (nederlands) @@ -2958,12 +3025,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho British English - Inglés Británico + Inglés británico Canadian French - Francés Canadiense + Francés canadiense @@ -2973,22 +3040,22 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Simplified Chinese - Chino Simplificado + Chino simplificado Traditional Chinese (正體中文) - Chino Tradicional (正體中文) + Chino tradicional (正體中文) Brazilian Portuguese (português do Brasil) - Portugués Brasileño (português do Brasil) + Portugués brasileño (português do Brasil) Custom RTC - RTC Personalizado + RTC personalizado @@ -3008,7 +3075,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Stereo - Estereo + Estéreo @@ -3018,12 +3085,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Console ID: - ID de la Consola: + ID de la consola: Sound output mode - Modo de salida del sonido: + Método de salida de sonido: @@ -3038,12 +3105,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho System settings are available only when game is not running. - Los ajustes del sistema solo se encuentran disponibles cuando no se está ejecutando ningún juego. + Los ajustes del sistema sólo se encuentran disponibles cuando no se esté ejecutando ningún juego. This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? - Esto reemplazará tu Switch virtual con una nueva. Tu Switch virtual actual no será recuperable. Esto podría causar efectos inesperados en determinados juegos. Si usas un archivo de configuración obsoleto, esto podría fallar. ¿Continuar? + Esto reemplazará tu Switch virtual con una nueva. Tu Switch virtual actual no será recuperable. Esto podría causar efectos inesperados en determinados juegos. Si usas un archivo de guardado de configuración obsoleto, esto podría fallar. ¿Continuar? @@ -3053,7 +3120,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Console ID: 0x%1 - ID de Consola: 0x%1 + ID de consola: 0x%1 @@ -3066,17 +3133,17 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - <html><head/><body><p>Lee la entrada de los controles de los scripts en el mismo formato que los scripts TAS-nx.<br/>Para una mejor explicación, consulta la<a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">página de ayuda</span></a> en la web de yuzu.</p></body></html> + <html><head/><body><p>Lee la entrada de los controles de los scripts en el mismo formato que los scripts TAS-nx.<br/>Para una mejor explicación, consulta la<a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">página de ayuda</span></a> en la página web de yuzu.</p></body></html> To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). - Para comprobar qué teclas de acceso rápido controlan la reproducción/grabación, por favor, comprueba la configuración de las Teclas de Acceso Rápido (Configuración -> General -> Teclas de Acceso Rápido) + Para comprobar qué teclas de acceso rápido controlan la reproducción/grabación, por favor, revisa la configuración de las Teclas de acceso rápido (Configuración -> General -> Teclas de acceso rápido) WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method. - AVISO: Ésto es una característica experimental.<br/>No va a reproducir scripts perfectamente con el métido actual e imperfecto de sincronización. + AVISO: Esto es una característica experimental.<br/>No se reproducirán los scripts perfectamente con el método actual e imperfecto de sincronización. @@ -3086,35 +3153,30 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Enable TAS features - Activar características de TAS + Activar características TAS - Automatic controller profile swapping - Cambio automático de perfil de controlador - - - Loop script Repetir script en bucle - + Pause execution during loads - Pausar ejecución durante cargas + Pausar ejecución durante las cargas - + Script Directory Directorio de scripts - + Path Ruta - + ... ... @@ -3124,12 +3186,12 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho TAS Configuration - Configuración de TAS + Configuración TAS - + Select TAS Load Directory... - Seleccione el directorio de carga de TAS... + Selecciona el directorio de carga TAS... @@ -3137,7 +3199,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Configure Touchscreen Mappings - Configurar las Asignaciones de la Pantalla Táctil + Configurar las asignaciones de la pantalla táctil @@ -3147,7 +3209,7 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho New - Crear + Nuevo @@ -3163,13 +3225,13 @@ Para invertir los ejes, primero mueve tu joystick de manera vertical, y luego ho Click the bottom area to add a point, then press a button to bind. Drag points to change position, or double-click table cells to edit values. - Haz clic en el área inferior para añadir un punto, y luego presiona un botón para unir. -Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas de la tabla para editar los valores. + Haz clic en el área inferior para añadir un punto, y luego presiona un botón para vincularlo. +Arrastra los puntos para cambiar de posición, o haz doble clic en las celdas de la tabla para editar los valores. Delete Point - Borrar Punto + Borrar punto @@ -3189,37 +3251,37 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Y - + New Profile - Crear Perfíl + Crear perfil - + Enter the name for the new profile. - Introduzca un nombre para el nuevo perfíl: + Introduce un nombre para el nuevo perfil: - + Delete Profile - Borrar Perfíl + Borrar perfil - + Delete profile %1? - ¿Borrar Perfíl %1? + ¿Borrar el perfil %1? - + Rename Profile - Renombrar Perfíl + Renombrar perfil - + New name: Nuevo nombre: - + [press key] [presionar tecla] @@ -3234,27 +3296,27 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing. - Advertencia: Los ajustes en esta página afectarán al funcionamiento de la pantalla táctil emulada de yuzu. Cambiarlas podría resultar en un comportamiento inapropiado, como que la pantalla táctil deje de funcionar parcialmente. Se recomienda usar esta pestaña sólo si sabes lo que estás haciendo. + Advertencia: Los ajustes en esta página afectarán al funcionamiento interno de la pantalla táctil emulada de yuzu. Cambiarlos puede dar lugar a un comportamiento imprevisto, como que la pantalla táctil deje de funcionar o funcione parcialmente. Sólo debes utilizar esta página si sabes lo que estás haciendo. Touch Parameters - Parámetros Táctil + Parámetros táctil Touch Diameter Y - Diámetro Táctil Y + Diámetro táctil Y Touch Diameter X - Diámetro Táctil X + Diámetro táctil X Rotational Angle - Ángulo Rotacional + Ángulo rotacional @@ -3309,22 +3371,22 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Filename - Nombre del Archivo + Nombre del archivo Filetype - Tipo de Archivo + Tipo de archivo Title ID - ID del Título + ID del título Title Name - Nombre del Título + Nombre del título @@ -3337,7 +3399,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d UI - IU + Interfaz @@ -3347,12 +3409,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Note: Changing language will apply your configuration. - Nota: Cambiar el idioma guardará tu configuración actual. + Nota: cambiar el idioma afectará a tu configuración actual. Interface language: - Lenguage de la Interfaz: + Idioma de la interfaz: @@ -3362,12 +3424,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Game List - Lista de Juegos + Lista de juegos Show Add-Ons Column - Mostrar Columna de Accesorios + Mostrar columna de extras/Add-Ons @@ -3382,27 +3444,27 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Row 1 Text: - Texto de la Fila 1: + Texto de fila 1: Row 2 Text: - Texto de la Fila 2: + Texto de fila 2: Screenshots - Capturas de Pantalla + Capturas de pantalla Ask Where To Save Screenshots (Windows Only) - Pregunte Dónde Guardar las Capturas de Pantalla (sólo para Windows) + Preguntar dónde guardar las capturas de pantalla (sólo en Windows) Screenshots Path: - Trayectoria de las Capturas de Pantalla: + Ruta de las capturas de pantalla: @@ -3412,7 +3474,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Select Screenshots Path... - Selecciona la Trayectoria de las Capturas de Pantalla: + Selecciona la ruta de las capturas de pantalla: @@ -3430,7 +3492,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Configure Vibration - Configurar Vibración + Configurar vibración @@ -3497,7 +3559,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Enable Accurate Vibration - Habilitar Vibración Precisa + Activar vibración precisa @@ -3515,12 +3577,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d yuzu Web Service - Servicio Web de yuzu + Servicio web de yuzu By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information. - Al proporcionar su nombre de usuario y token, das tu consentimiento a que yuzu recopile datos de uso adicionales, que pueden incluir información de identificación del usuario. + Al proporcionar el nombre de usuario y el token, aceptas que yuzu recopile datos de uso adicionales, que pueden incluir información de identificación del usuario. @@ -3566,7 +3628,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Telemetry ID: - ID de Telemetría: + ID de telemetría: @@ -3581,7 +3643,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Show Current Game in your Discord Status - Mostrar el juego actual en tu estado de Discord + Mostrar el juego actual en el estado de Discord @@ -3602,7 +3664,7 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Telemetry ID: 0x%1 - ID de Telemetría: 0x%1 + ID de telemetría: 0x%1 @@ -3613,12 +3675,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Token not verified - No se pudo verificar el token + Token no verificado Token was not verified. The change to your token has not been saved. - El token pudo ser verificado. El cambio realizado a su token no se ha guardado. + El token no se puede verificar. Los cambios realizados en tu token no se ha guardado. @@ -3628,124 +3690,129 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d Verification failed - Verificación fallida + Error de verificación Verification failed. Check that you have entered your token correctly, and that your internet connection is working. - Verificación fallida. Compruebe que ha ingresado el token correctamente, y que esté funcionando su conexión a internet. + Error de verificación. Comprueba que has introducido el token correctamente, y que esté funcionando correctamente tu conexión a internet. ControllerDialog - + Controller P1 Controlador J1 - + &Controller P1 - Controlador J1 + &Controlador J1 GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? - <a href='https://yuzu-emu.org/help/feature/telemetry/'>Se recogen datos anónimos</a> para ayudar a mejorar yuzu. <br/><br/>¿Quieres compartir tus datos de uso con nosotros? + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Los datos de uso anónimos se recogen</a> para ayudar a mejorar yuzu. <br/><br/>¿Deseas compartir tus datos de uso con nosotros? - + Telemetry Telemetría - + Loading Web Applet... - Cargando Web Applet... + Cargando Web applet... - - + + Disable Web Applet - Desactivar Web Applet + Desactivar Web applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - Desactivar la web applet causará que ésta no se muestre nunca más durante el resto de la sesión. Puede causar comportamientos indefinidos y sólo debe ser usado con Super Mario 3D All-Stars. ¿De verdad quieres desactivar la web applet? + Desactivar la web applet causará que ésta no se muestre más durante el resto de la sesión. Puede causar comportamientos imprevistos y sólo debe ser usado con Super Mario 3D All-Stars. ¿De verdad quieres desactivar la web applet? - + The amount of shaders currently being built La cantidad de shaders que se están construyendo actualmente - + + The current selected resolution scaling multiplier. + El multiplicador de escala de resolución seleccionado actualmente. + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. La velocidad de emulación actual. Los valores superiores o inferiores al 100% indican que la emulación se está ejecutando más rápido o más lento que en una Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - Cuántos fotogramas por segundo está mostrando el juego actualmente. Esto variará de un juego a otro y de una escena a otra. + La cantidad de fotogramas por segundo que se está mostrando el juego actualmente. Esto variará de un juego a otro y de una escena a otra. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tiempo que lleva emular un fotograma de la Switch, sin tener en cuenta la limitación de fotogramas o sincronización vertical. Para una emulación óptima, este valor debería ser como máximo de 16.67 ms. - + Invalid config detected - Configuración invalida detectada + Configuración no válida detectada - + Handheld controller can't be used on docked mode. Pro controller will be selected. - El controlador del modo portátil no puede ser usado en modo dock. Se elegirá Pro controller en su lugar. + El controlador del modo portátil no puede ser usado en el modo sobremesa. Se seleccionará el controlador Pro en su lugar. - + DOCK - ESTACIONADO + DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files - &Limpiar Archivos Recientes + &Eliminar archivos recientes - - TAS Recording - Grabación TAS + + &Continue + &Continuar - - Overwrite file of player 1? - ¿Sobreescribir archivo del Jugador 1? + + &Pause + &Pausar Warning Outdated Game Format - Advertencia Formato de Juego Obsoleto + Advertencia: formato del juego obsoleto You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br><br>For an explanation of the various Switch formats yuzu supports, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our wiki</a>. This message will not be shown again. - Está utilizando el formato de directorio de ROM deconstruido para este juego, que es un formato desactualizado que ha sido reemplazado por otros, como NCA, NAX, XCI o NSP. Los directorios de ROM deconstruidos carecen de íconos, metadatos y soporte de actualización.<br><br>Para obtener una explicación de los diversos formatos de Switch que soporta yuzu,<a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>echa un vistazo a nuestra wiki</a>. Este mensaje no se volverá a mostrar. + Está utilizando el formato de directorio de ROM deconstruido para este juego, que es un formato desactualizado que ha sido reemplazado por otros, como los NCA, NAX, XCI o NSP. Los directorios de ROM deconstruidos carecen de íconos, metadatos y soporte de actualizaciones.<br><br>Para ver una explicación de los diversos formatos de Switch que soporta yuzu,<a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>echa un vistazo a nuestra wiki</a>. Este mensaje no se volverá a mostrar. @@ -3761,12 +3828,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d An error occurred initializing the video core. - Se produjo un error al inicializar el núcleo de video. + Se ha producido un error al inicializar el núcleo de video. yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.Ensure that you have the latest graphics drivers for your GPU. - yuzu ha encontrado un error al ejecutar el núcleo de video, consulte el registro para obtener más detalles. Para obtener más información sobre cómo acceder al registro, consulte la siguiente página: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Cómo cargar el archivo de registro.</a> Asegúrese de tener los últimos controladores de gráficos para su GPU. + yuzu ha encontrado un error al ejecutar el núcleo de video, consulta el registro para obtener más detalles. Para obtener más información sobre cómo acceder al archivo de registro, consulte la siguiente página: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Cómo cargar el archivo de registro.</a> Asegúrate de tener los últimos controladores de gráficos para la GPU. @@ -3778,374 +3845,370 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d %1<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to redump your files.<br>You can refer to the yuzu wiki</a> or the yuzu Discord</a> for help. %1 signifies an error string. - %1<br>Por favor, sique <a href='https://yuzu-emu.org/help/quickstart/'>la guía de inicio rápido de yuzu</a> para revolcar tus archivos.<br>Puedes consultar la wiki de yuzu</a> o el Discord de yuzu</a> para obtener ayuda. + %1<br>Por favor, sigue <a href='https://yuzu-emu.org/help/quickstart/'>la guía de inicio rápido de yuzu</a> para revolcar los archivos.<br>Puedes consultar la wiki de yuzu</a> o el Discord de yuzu</a> para obtener ayuda. An unknown error occurred. Please see the log for more details. - Error desconocido. Por favor, consulte el registro para ver más detalles. + Error desconocido. Por favor, consulte el archivo de registro para ver más detalles. - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Iniciar - - - + Save Data - Datos de Juegos Guardados + Datos de guardado - + Mod Data - Datos de Mods + Datos de mods - + Error Opening %1 Folder Error al abrir la carpeta %1 - - + + Folder does not exist! ¡La carpeta no existe! - + Error Opening Transferable Shader Cache - Error al Abrir el Caché Transferible de Shaders + Error al abrir el caché transferible de shaders - + Failed to create the shader cache directory for this title. No se pudo crear el directorio de la caché de los shaders para este título. - + Contents Contenidos - + Update Actualización - + DLC DLC - + Remove Entry - Eliminar el Título + Eliminar entrada - + Remove Installed Game %1? - Eliminar el Juego Instalado %1? + ¿Eliminar el juego instalado %1? - - - - - - + + + + + + Successfully Removed - Se Eliminó con Éxito + Se ha eliminado con éxito - + Successfully removed the installed base game. - Se eliminó con éxito el juego de base instalado. + Se ha eliminado con éxito el juego base instalado. - - - + + + Error Removing %1 - Error en la eliminación de %1 + Error al eliminar %1 - + The base game is not installed in the NAND and cannot be removed. El juego base no está instalado en el NAND y no se puede eliminar. - + Successfully removed the installed update. - Se eliminó con éxito la actualización instalada. + Se ha eliminado con éxito la actualización instalada. - + There is no update installed for this title. No hay ninguna actualización instalada para este título. - + There are no DLC installed for this title. No hay ningún DLC instalado para este título. - + Successfully removed %1 installed DLC. - Se eliminó con éxito %1 DLC instalado(s). + Se ha eliminado con éxito %1 DLC instalado(s). - + Delete OpenGL Transferable Shader Cache? - ¿Desea eliminar el Caché Transferible de Shaders de OpenGL? + ¿Deseas eliminar el caché transferible de shaders de OpenGL? - + Delete Vulkan Transferable Shader Cache? - ¿Desea eliminar el Caché Transferible de Shaders de Vulkan? + ¿Deseas eliminar el caché transferible de shaders de Vulkan? - + Delete All Transferable Shader Caches? - ¿Desea eliminar todas las Cachés Transferibles de Shaders? + ¿Deseas eliminar todo el caché transferible de shaders? - + Remove Custom Game Configuration? - ¿Desea Eliminar la Configuración Personalizada del Juego? + ¿Deseas eliminar la configuración personalizada del juego? - + Remove File - Eliminar Archivo - - - - - Error Removing Transferable Shader Cache - Error al Eliminar el Caché Transferible de Shaders + Eliminar archivo + - + Error Removing Transferable Shader Cache + Error al eliminar la caché de shaders transferibles + + + + A shader cache for this title does not exist. - No existe un Caché de shaders para este título. + No existe caché de shaders para este título. - + Successfully removed the transferable shader cache. - El Caché Transferible de Shaders fue eliminado con éxito. + El caché de shaders transferibles se ha eliminado con éxito. - + Failed to remove the transferable shader cache. - No se ha podido eliminar el caché de shaders transferibles. + No se ha podido eliminar la caché de shaders transferibles. - - + + Error Removing Transferable Shader Caches - Error al Eliminar las Cachés Transferibles de Shaders + Error al eliminar las cachés de shaders transferibles - + Successfully removed the transferable shader caches. - Cachés transferibles de shaders eliminadas con éxito. + Cachés de shaders transferibles eliminadas con éxito. - + Failed to remove the transferable shader cache directory. - No se ha podido eliminar el directorio de cachés transferibles de shaders. + No se ha podido eliminar el directorio de cachés de shaders transferibles. - - + + Error Removing Custom Configuration - Error al Eliminar la Configuración Personalizada del Juego + Error al eliminar la configuración personalizada del juego - + A custom configuration for this title does not exist. No existe una configuración personalizada para este título. - + Successfully removed the custom game configuration. Se eliminó con éxito la configuración personalizada del juego. - + Failed to remove the custom game configuration. No se ha podido eliminar la configuración personalizada del juego. - - + + RomFS Extraction Failed! - ¡La extracción de RomFS falló! + ¡La extracción de RomFS ha fallado! - + There was an error copying the RomFS files or the user cancelled the operation. - Se produjo un error al copiar los archivos RomFS o el usuario canceló la operación. + Se ha producido un error al copiar los archivos RomFS o el usuario ha cancelado la operación. - + Full Completo - + Skeleton - Base + Esquema - + Select RomFS Dump Mode - Elegir modo para volcar el RomFS + Elegir método de volcado de RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - Seleccione la forma en que desea volcar el RomFS. <br>Copiará todos los archivos en el nuevo directorio <br> mientras que el esqueleto solo creará la estructura del directorio. + Seleccione la forma en que quieras volcar el RomFS. <br>Copiará todos los archivos en el nuevo directorio <br> mientras que el esqueleto solo creará la estructura del directorio. + + + + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root + No hay suficiente espacio en %1 para extraer el RomFS. Por favor, libera espacio o elige otro directorio de volcado en Emulación > Configuración > Sistema > Sistema de archivos > Raíz de volcado - There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - No hay suficiente espacio en %1 para extraer el RomFS. Por favor, libere espacio o elige otro directorio de volcado en Emulación > Configuración > Sistema > Sistema de archivos > Raíz de volcado - - - Extracting RomFS... Extrayendo RomFS... - - + + Cancel Cancelar - + RomFS Extraction Succeeded! - ¡La extracción RomFS tuvo éxito! + ¡La extracción RomFS ha tenido éxito! - + The operation completed successfully. La operación se completó con éxito. - + Error Opening %1 Error al intentar abrir %1 - + Select Directory - Seleccionar Directorio + Seleccionar directorio - + Properties Propiedades - + The game properties could not be loaded. - No se pudieron cargar las propiedades del juego. + No se pueden cargar las propiedades del juego. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Ejecutable de Switch (%1);;Todos los archivos (*.*) - + Load File Cargar archivo - + Open Extracted ROM Directory Abrir el directorio de la ROM extraída - + Invalid Directory Selected - Directorio no válido seleccionado + Directorio seleccionado no válido - + The directory you have selected does not contain a 'main' file. El directorio que ha seleccionado no contiene ningún archivo 'main'. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Archivo de Switch Instalable (*.nca *.nsp *.xci);;Archivo de Contenidos Nintendo (*.nca);;Paquete de Envío Nintendo (*.nsp);;Imagen de Cartucho NX (*.xci) + Archivo de Switch Instalable (*.nca *.nsp *.xci);;Archivo de contenidos de Nintendo (*.nca);;Paquete de envío de Nintendo (*.nsp);;Imagen de cartucho NX (*.xci) - + Install Files - Instalar Archivos + Instalar archivos - + %n file(s) remaining %n archivo(s) restantes%n archivo(s) restantes - + Installing file "%1"... Instalando el archivo "%1"... - - + + Install Results - Instalar Resultados + Instalar resultados - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - Para evitar posibles conflictos, no recomendamos instalar juegos base en la NAND. Por favor, usa sólo esta característica para instalar actualizaciones y DLC. + Para evitar posibles conflictos, no recomendamos a los usuarios que instalen juegos base en el NAND. +Por favor, utiliza esta función sólo para instalar actualizaciones y DLCs. - + %n file(s) were newly installed %n archivo(s) recién instalado/s -%n archivo(s) recién instalado/s +%n archivo(s) instalado/s recientemente - + %n file(s) were overwritten %n archivo(s) recién sobreescrito/s -%n archivo(s) recién sobreescrito/s +%n archivo(s) sobrescrito/s recientemente - + %n file(s) failed to install %n archivo(s) no se instaló/instalaron @@ -4153,295 +4216,367 @@ Please, only use this feature to install updates and DLC. - + System Application Aplicación del sistema - + System Archive - Archivo del Sistema + Archivo del sistema - + System Application Update Actualización de la aplicación del sistema - + Firmware Package (Type A) - Paquete de Firmware (Tipo A) + Paquete de firmware (Tipo A) - + Firmware Package (Type B) - Paquete de Firmware (Tipo B) + Paquete de firmware (Tipo B) - + Game Juego - + Game Update - Actualización del juego + Actualización de juego - + Game DLC - DLC del Juego + DLC del juego - + Delta Title - Titulo Delta + Titulo delta - + Select NCA Install Type... Seleccione el tipo de instalación NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - Seleccione el tipo de título en el que desea instalar este NCA como: -(En la mayoría de los casos, el 'Juego' predeterminado está bien). + Seleccione el tipo de título en el que deseas instalar este NCA como: +(En la mayoría de los casos, el 'Juego' predeterminado está bien). - + Failed to Install Fallo en la instalación - + The title type you selected for the NCA is invalid. El tipo de título que seleccionó para el NCA no es válido. - + File not found Archivo no encontrado - + File "%1" not found Archivo "%1" no encontrado - - - &Continue - &Continuar - - - + OK Aceptar - + Missing yuzu Account Falta la cuenta de Yuzu - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. - Para enviar un caso de prueba de compatibilidad de juegos, debe vincular su cuenta de yuzu.<br><br/> Para vincular su cuenta yuzu, vaya a Emulación & gt; Configuración & gt; Web. + Para enviar un caso de prueba de compatibilidad de juegos, debes vincular tu cuenta de yuzu.<br><br/> Para vincular tu cuenta de yuzu, ve a Emulación &gt; Configuración &gt; Web. - + Error opening URL Error al abrir la URL - + Unable to open the URL "%1". No se puede abrir la URL "%1". - - Amiibo File (%1);; All Files (*.*) - Archivo Amiibo (%1);; Todos los archivos (*.*) + + TAS Recording + Grabación TAS - + + Overwrite file of player 1? + ¿Sobrescribir archivo del jugador 1? + + + + Amiibo File (%1);; All Files (*.*) + Archivo amiibo (%1);; Todos los archivos (*.*) + + + Load Amiibo Cargar amiibo - + Error opening Amiibo data file - Error al abrir el archivo de datos de Amiibo + Error al abrir el archivo de datos amiibo - + Unable to open Amiibo file "%1" for reading. - No se puede abrir el archivo de Amiibo "%1" para leer. + No se puede abrir el archivo amiibo "%1" para leer. - + Error reading Amiibo data file - Error al leer el archivo de datos de Amiibo + Error al leer el archivo de datos amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. - No se pueden leer completamente los datos de Amiibo. Se esperaban leer %1 bytes, pero solo se pudo leer %2 bytes. + No se puede leer completamente los datos Amiibo. Se esperaban leer %1 bytes, pero solo se puede leer %2 bytes. - + Error loading Amiibo data - Error al cargar los datos de Amiibo + Error al cargar los datos Amiibo - + Unable to load Amiibo data. - No se pueden cargar los datos de Amiibo. + No se pueden cargar los datos Amiibo. - + Capture Screenshot - Captura de Pantalla + Captura de pantalla - + PNG Image (*.png) Imagen PNG (*.png) - + TAS state: Running %1/%2 - Estado TAS: Ejecutando %1/%2 + Estado TAS: ejecutando %1/%2 - + TAS state: Recording %1 - Estado TAS: Grabando %1 + Estado TAS: grabando %1 - + TAS state: Idle %1/%2 - Estado TAS: Idle %1/%2 + Estado TAS: inactivo %1/%2 - + TAS State: Invalid - Estado TAS: Nulo + Estado TAS: nulo + + + + &Stop Running + &Parar de ejecutar + + + + &Start + &Iniciar + + + + Stop R&ecording + Pausar g&rabación + + + + R&ecord + G&rabar - + Building: %n shader(s) - Creando: %n shader(s)Creando: %n shader(s) + Creando: %n shader(s)Construyendo: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + Escalado: %1x + + + Speed: %1% / %2% Velocidad: %1% / %2% - + Speed: %1% Velocidad: %1% - + Game: %1 FPS (Unlocked) - Juego: %1 FPS (Desbloqueado) + Juego: %1 FPS (desbloqueado) - + Game: %1 FPS Juego: %1 FPS - + Frame: %1 ms Fotogramas: %1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU ALTA - + GPU EXTREME GPU EXTREMA - + GPU ERROR GPU ERROR - - The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - El juego que estás intentando cargar requiere de archivos adicionales de su Switch antes de poder jugar. <br/><br/>Para obtener más información sobre cómo obtener estos archivos, ve a la siguiente página de la wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Volcar archivos del sistema y las fuentes compartidas desde una Consola Switch. </a>.<br/><br/>¿Quieres volver a la lista de juegos? Continuar con la emulación puede provocar fallos, datos de guardado dañados u otros errores. + + NEAREST + PROVEEDOR - + + + BILINEAR + BILINEAL + + + + BICUBIC + BICÚBICO + + + + GAUSSIAN + GAUSSIANO + + + + SCALEFORCE + SCALEFORCE + + + + FSR + FSR + + + + + NO AA + NO AA + + + + FXAA + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. + El juego que estás intentando cargar requiere archivos adicionales de tu Switch antes de poder jugar. <br/><br/>Para obtener más información sobre cómo obtener estos archivos, ve a la siguiente página de la wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Volcar archivos del sistema y las fuentes compartidas desde una Consola Switch. </a>.<br/><br/>¿Quieres volver a la lista de juegos? Continuar con la emulación puede provocar fallos, datos de guardado corrompidos u otros errores. + + + yuzu was unable to locate a Switch system archive. %1 yuzu no pudo localizar el archivo de sistema de la Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu no pudo localizar un archivo de sistema de la Switch: %1. %2 - + System Archive Not Found - Archivo del Sistema No Encontrado + Archivo del sistema no encontrado - + System Archive Missing - Falta Archivo del Sistema + Faltan archivos del sistema - + yuzu was unable to locate the Switch shared fonts. %1 - yuzu no pudo encontrar las Fuentes Compartidas de la Switch. %1 + yuzu no pudo encontrar las fuentes compartidas de la Switch. %1 - + Shared Fonts Not Found Fuentes compartidas no encontradas - + Shared Font Missing - Faltan las Fuentes Compartidas + Faltan fuentes compartidas - + Fatal Error - Error Fatal + Error fatal - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - yuzu ha encontrado un error fatal, consulte el registro para obtener más detalles. Para obtener más información sobre cómo acceder al registro, consulte la siguiente página: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>¿Cómo cargar el archivo de registro?</a>.<br/><br/> La emulación continua puede provocar fallos, datos de guardado dañados u otros errores. + yuzu ha encontrado un error fatal, consulta el registro para obtener más detalles. Para obtener más información sobre cómo acceder al registro, consulta la siguiente página: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>¿Cómo cargar el archivo de registro?</a>.<br/><br/> Continuar con la emulación puede provocar fallos, datos de guardado corruptos u otros errores. - + Fatal Error encountered - Error Fatal Encontrado + Error fatal encontrado - + Confirm Key Rederivation - Confirma la Clave de Rederivación + Confirmar la clave de rederivación - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4449,46 +4584,46 @@ Please make sure this is what you want and optionally make backups. This will delete your autogenerated key files and re-run the key derivation module. - Estás a punto de forzar todas tus claves. + Estás a punto de forzar la rederivación de todas tus claves. Si no sabes qué es esto, es una acción potencialmente destructiva. -Por favor, asegúrese de que esto -es lo que desea hacer si es necesario. +Por favor, asegúrate de que esto +es lo que quieres hacer si es necesario. - Esto eliminará los archivos de las claves generados automáticamente y volverá a ejecutar el módulo de derivación de claves. + Esto eliminará los archivos de las claves generadas automáticamente y volverá a ejecutar el módulo de derivación de claves. - + Missing fuses - Falta fuses + Faltan fuses - + - Missing BOOT0 - Falta BOOT0 - + - Missing BCPKG2-1-Normal-Main - Falta BCPKG2-1-Normal-Main - + - Missing PRODINFO - Falta PRODINFO - + Derivation Components Missing - Faltan Componentes de Derivación + Faltan componentes de derivación - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Faltan componentes que pueden impedir que la derivación de la clave se complete. <br>Por favor siga <a href='https://yuzu-emu.org/help/quickstart/'>la guía de inicio rápido de yuzu</a> para conseguir todas tus llaves y juegos.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + Faltan las claves de encriptación. <br>Por favor, sigue <a href='https://yuzu-emu.org/help/quickstart/'>la guía rápida de yuzu</a> para obtener todas tus claves, firmware y juegos.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4497,84 +4632,84 @@ Esto puede llevar unos minutos dependiendo del rendimiento de su sistema. - + Deriving Keys Obtención de claves - + Select RomFS Dump Target Selecciona el destinatario para volcar el RomFS - + Please select which RomFS you would like to dump. - Por favor, seleccione los RomFS que desea volcar. + Por favor, seleccione los RomFS que deseas volcar. - + Are you sure you want to close yuzu? ¿Estás seguro de que quieres cerrar yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. ¿Estás seguro de que quieres detener la emulación? Cualquier progreso no guardado se perderá. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? - La aplicación que se está ejecutando actualmente ha solicitado que yuzu no sea cerrado. + La aplicación que se está ejecutando actualmente ha solicitado que yuzu no se cierre. -¿Desea cerrarlo de todas formas? +¿Quieres salir de todas formas? GRenderWindow - + OpenGL not available! ¡OpenGL no está disponible! - + yuzu has not been compiled with OpenGL support. yuzu no ha sido compilado con soporte de OpenGL. - - + + Error while initializing OpenGL! ¡Error al inicializar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - Tu GPU no soporta OpenGL o no tienes instalados los últimos controladores gráficos. + Tu GPU no soporta OpenGL, o no tienes instalados los últimos controladores gráficos. - + Error while initializing OpenGL 4.6! ¡Error al iniciar OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Tu GPU no soporta OpenGL 4.6, o no tienes instalado el último controlador de la tarjeta gráfica.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 - Es posible que su GPU no soporte una o más extensiones OpenGL requeridas. Por favor, asegúrese de tener el último controlador de la tarjeta gráfica.<br><br>GL Renderer:<br>%1<br><br>Extensiones no soportadas:<br>%2 + Es posible que la GPU no soporte una o más extensiones necesarias de OpenGL . Por favor, asegúrate de tener los últimos controladores de la tarjeta gráfica.<br><br>GL Renderer:<br>%1<br><br>Extensiones no soportadas:<br>%2 @@ -4592,12 +4727,12 @@ Would you like to bypass this and exit anyway? Add-ons - Complementos + Extras/Add-ons File type - Tipo de Archivo + Tipo de archivo @@ -4612,12 +4747,12 @@ Would you like to bypass this and exit anyway? Start Game - Empezar Juego + Iniciar juego Start Game without Custom Configuration - Empezar Juego sin Configuración Personalizada + Iniciar juego sin la configuración personalizada @@ -4627,12 +4762,12 @@ Would you like to bypass this and exit anyway? Open Mod Data Location - Abrir ubicación de Mods + Abrir ubicación de los mods Open Transferable Pipeline Cache - Abrir Caché Transferible de Shaders de Tubería + Abrir caché transferible de shaders en tubería @@ -4642,7 +4777,7 @@ Would you like to bypass this and exit anyway? Remove Installed Update - Eliminar la Actualización Instalada + Eliminar la actualización instalada @@ -4652,27 +4787,27 @@ Would you like to bypass this and exit anyway? Remove Custom Configuration - Eliminar Configuración Personalizada + Eliminar la configuración personalizada Remove OpenGL Pipeline Cache - Eliminar Caché de Tubería de OpenGL + Eliminar caché en tubería de OpenGL Remove Vulkan Pipeline Cache - Eliminar Caché de Tubería de Vulkan + Eliminar caché en tubería de Vulkan Remove All Pipeline Caches - Eliminar todas las cachés de tubería + Eliminar todas las cachés en tubería Remove All Installed Contents - Eliminar Todos los Contenidos Instalados + Eliminar todo el contenido instalado @@ -4688,12 +4823,12 @@ Would you like to bypass this and exit anyway? Copy Title ID to Clipboard - Copiar ID de título al portapapeles + Copiar la ID del título al portapapeles Navigate to GameDB entry - Navegar a la entrada de BD del juego + Ir a la sección de bases de datos del juego @@ -4708,22 +4843,22 @@ Would you like to bypass this and exit anyway? Remove Game Directory - Eliminar Directorio de Juegos + Eliminar directorio de juegos ▲ Move Up - ▲ Mover Hacia Arriba + ▲ Mover hacia arriba ▼ Move Down - ▼ Mover Hacia Abajo + ▼ Mover hacia abajo Open Directory Location - Abrir Ubicación del Directorio + Abrir ubicación del directorio @@ -4754,8 +4889,8 @@ sin ninguna solución necesaria. Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - El juego funciona con fallos gráficos o de audio menores y se puede jugar de principio a fin. Puede requerir de -soluciones temporales. + El juego funciona con fallos gráficos o de audio menores y es jugable de principio a fin. Puede que sea necesario +recurrir a arreglos temporales. @@ -4766,8 +4901,8 @@ soluciones temporales. Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - El juego funciona con importantes fallos gráficos o de audio, pero el juego se puede jugar de principio a fin con -soluciones temporales. + El juego funciona con fallos gráficos o de audio sustanciales, pero el juego es jugable de principio a fin con +arreglos temporales. @@ -4778,19 +4913,19 @@ soluciones temporales. Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - El juego funciona, pero con importantes fallos gráficos o de audio. Es imposible avanzar en zonas específicas -incluso con soluciones temporales. + El juego funciona, pero tiene errores gráficos o de audio. Es imposible avanzar en ciertas zonas debido a fallos +incluso con arreglos temporales. Intro/Menu - Intro/Menú + Intro/Menu Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - No es posible jugar a este juego debido a importantes errores gráficos o de audio. Es imposible avanzar mas allá de la pantalla + No es posible jugar a este juego debido a errores gráficos o de audio importantes. Es imposible avanzar mas allá de la pantalla de inicio. @@ -4819,7 +4954,7 @@ de inicio. Double-click to add a new folder to the game list - Haga doble clic para agregar un nuevo directorio a la lista de juegos. + Haz doble clic para agregar un nuevo directorio a la lista de juegos. @@ -4832,12 +4967,12 @@ de inicio. Filter: - Filtrar: + Búsqueda: Enter pattern to filter - Introduce patrón para filtrar + Introduce un patrón para buscar @@ -4845,12 +4980,12 @@ de inicio. Please confirm these are the files you wish to install. - Por favor, confirme que estos son los archivos que desea instalar. + Por favor, confirma que estos son los archivos que desea instalar. Installing an Update or DLC will overwrite the previously installed one. - Instalando una Actualización o DLC reemplazará la que está instalada anteriormente. + Instalar una actualización o DLC reemplazará la que se instaló previamente. @@ -4878,17 +5013,17 @@ de inicio. Loading Shaders 387 / 1628 - Cargando Shaders 387 / 1628 + Cargando shaders 387 / 1628 Loading Shaders %v out of %m - Cargando Shaders %v de %m + Cargando shaders %v de %m Estimated Time 5m 4s - Tiempo Estimado 5m 4s + Tiempo estimado 5m 4s @@ -4898,7 +5033,7 @@ de inicio. Loading Shaders %1 / %2 - Cargando Shaders %1 / %2 + Cargando shaders %1 / %2 @@ -4926,7 +5061,7 @@ de inicio. &Recent Files - &Archivos Recientes + &Archivos recientes @@ -4934,189 +5069,204 @@ de inicio. &Emulación - + &View &Ver - + &Reset Window Size - &Reiniciar Tamaño de Ventana + &Reiniciar tamaño de ventana - - Reset Window Size to &720p - Reiniciar Tamaño de Ventana a &720p - - - - Reset Window Size to 720p - Reiniciar Tamaño de Ventana a 720p - - - - Reset Window Size to &900p - Reiniciar Tamaño de Ventana a &900p - - - - Reset Window Size to 900p - Reiniciar Tamaño de Ventana a 900p - - - - Reset Window Size to &1080p - Reiniciar Tamaño de Ventana a &1080p - - - - Reset Window Size to 1080p - Reiniciar Tamaño de Ventana a 1080p - - - + &Debugging &Depuración - + + Reset Window Size to &720p + Reiniciar el tamaño de la ventana a &720p + + + + Reset Window Size to 720p + Reiniciar el tamaño de la ventana a 720p + + + + Reset Window Size to &900p + Reiniciar el tamaño de la ventana a &900p + + + + Reset Window Size to 900p + Reiniciar el tamaño de la ventana a 900p + + + + Reset Window Size to &1080p + Reiniciar el tamaño de la ventana a &1080p + + + + Reset Window Size to 1080p + Reiniciar el tamaño de la ventana a 1080p + + + &Tools &Herramientas - + + &TAS + &TAS + + + &Help &Ayuda - + &Install Files to NAND... - &Instalar Archivos al NAND... + &Instalar archivos en NAND... - + L&oad File... - C&argar Archivo... + C&argar archivo... - + Load &Folder... - Cargar &Carpera + Cargar &carpeta - + E&xit S&alir - - &Start - &Iniciar - - - + &Pause &Pausar - + &Stop &Detener - + &Reinitialize keys... &Reiniciando claves... - + &About yuzu &Acerca de yuzu - + Single &Window Mode - Modo &Ventana + Modo &ventana - + Con&figure... - Con&figure... + Con&figurar... - + Display D&ock Widget Headers Mostrar complementos de cabecera del D&ock - + Show &Filter Bar - Mostrar Barra de &Filtro + Mostrar barra de &búsqueda - + Show &Status Bar - Mostrar Barra de &Estado + Mostrar barra de &estado - + Show Status Bar - Mostrar Barra de Estado + Mostrar barra de estado - + F&ullscreen P&antalla completa - + &Restart &Reiniciar - + Load &Amiibo... - Cargar &Amibo + Cargar &Amiibo - + &Report Compatibility - &Reporte de Compatibilidad + &Reporte de compatibilidad - + Open &Mods Page - Abrir Página de &Mods + Abrir página de &mods - + Open &Quickstart Guide - Abrir Guía de &Inicio Rápido + Abrir guía de &inicio rápido - + &FAQ &Preguntas frecuentes - + Open &yuzu Folder Abrir la carpeta de &yuzu - + &Capture Screenshot - &Captura de Pantalla + &Captura de pantalla - - Configure &TAS... - Configurar &TAS... + + &Configure TAS... + &Configurar TAS... - + Configure C&urrent Game... - Configurar J&uego actual... + Configurar j&uego actual... + + + + &Start + &Iniciar + + + + &Reset + &Reiniciar + + + + R&ecord + G&rabar @@ -5163,9 +5313,14 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE - INICIAR/PARAR + INICIO/PAUSAR + + + + Charging + @@ -5178,17 +5333,17 @@ p, li { white-space: pre-wrap; } Installed NAND Titles - Títulos instalados en la NAND + Títulos instalados en NAND System Titles - Títulos del Sistema + Títulos del sistema Add New Game Directory - Agregar un Nuevo Directorio de Juegos + Añadir un nuevo directorio de juegos @@ -5197,142 +5352,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] - [no establecido] + [no definido] - - Hat %1 %2 Rotación %1 %2 - - - - - - + + + + Axis %1%2 Eje %1%2 - Button %1 Botón %1 - - - + + + [unknown] [desconocido] - + + Left + Izquierda + + + + Right + Derecha + + - Click 0 - Clic 0 + Down + Abajo - - Click 1 - Clic 1 + Up + Arriba - - Click 2 - Clic 2 + Z + Z - - Click 3 - Clic 3 + R + R - - Click 4 - Clic 4 + L + L - + + A + A + + + + B + B + + + + X + X + + + + Y + Y + + + + Start + + + + + L1 + L1 + + + + L2 + L2 + + + + L3 + L3 + + + + R1 + R1 + + + + R2 + R2 + + + + R3 + R3 + + + + Circle + Círculo + + + + Cross + + + + + Square + Cuadrado + + + + Triangle + Triángulo + + + + Share + + + + + Options + Opciones + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - Eje GC %1%2 + + [invalid] + - - GC Button %1 - Botón GC %1 + + + %1%2Hat %3 + - - TAS Axis %1 - TAS Axis %1 + + + + %1%2Axis %3 + - - TAS Btn %1 - TAS Btn %1 + + %1%2Axis %3,%4,%5 + - - Motion %1 - Movimiento %1 + + %1%2Motion %3 + - - %1Button %2 - %1Button %2 + + + %1%2Button %3 + %1%2Botón %3 - - SDL Motion - Movimiento SDL - - - - %1Click %2 - %1Click %2 - - - + [unused] [no usado] @@ -5342,12 +5577,12 @@ p, li { white-space: pre-wrap; } Controller Applet - Controller Applet + Controlador Applet Supported Controller Types: - Tipos de Controladores Soportados: + Tipos de controladores soportados: @@ -5373,7 +5608,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Controlador Pro @@ -5386,9 +5621,9 @@ p, li { white-space: pre-wrap; } - + Dual Joycons - Joycons Dobles + Joycons duales @@ -5399,9 +5634,9 @@ p, li { white-space: pre-wrap; } - + Left Joycon - Joycon Izquierdo + Joycon izquierdo @@ -5412,9 +5647,9 @@ p, li { white-space: pre-wrap; } - + Right Joycon - Joycon Derecho + Joycon derecho @@ -5426,7 +5661,7 @@ p, li { white-space: pre-wrap; } Use Current Config - Usar Configuracion Actual + Usar configuración actual @@ -5440,7 +5675,7 @@ p, li { white-space: pre-wrap; } - + Handheld Portátil @@ -5472,7 +5707,7 @@ p, li { white-space: pre-wrap; } Console Mode - Modo Consola + Modo consola @@ -5561,9 +5796,9 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller - Controlador GameCube + Controlador de GameCube @@ -5573,21 +5808,21 @@ p, li { white-space: pre-wrap; } Error Code: %1-%2 (0x%3) - Código de Error: %1-%2 (0x%3) + Código de error: %1-%2 (0x%3) An error has occurred. Please try again or contact the developer of the software. Ha ocurrido un error. -Por favor, intentelo de nuevo o contacta con el desarrollador del software. +Por favor, inténtalo de nuevo o contacta con el desarrollador del software. An error occurred on %1 at %2. Please try again or contact the developer of the software. Ha ocurrido un error en %1 a las %2 -Por favor, inténtelo de nuevo o contacta con el desarrollador del software. +Por favor, inténtalo de nuevo o contacta con el desarrollador del software. @@ -5634,12 +5869,12 @@ Por favor, inténtelo de nuevo o contacta con el desarrollador del software. Software Keyboard - Software del Teclado + Software del teclado Enter Text - Introducir Texto + Introducir texto @@ -5655,13 +5890,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK Aceptar - + Cancel Cancelar @@ -5671,7 +5906,7 @@ p, li { white-space: pre-wrap; } Enter a hotkey - Ingrese combinación de teclas de acceso rápido + Introduce una combinación de teclas @@ -5679,7 +5914,7 @@ p, li { white-space: pre-wrap; } Call stack - Pila de Llamadas + Llamadas acumuladas @@ -5687,7 +5922,7 @@ p, li { white-space: pre-wrap; } waiting for mutex 0x%1 - esperando por mutex 0x%1 + esperando al mutex 0x%1 @@ -5705,12 +5940,12 @@ p, li { white-space: pre-wrap; } waiting for all objects - esperando todos los objetos + esperando a todos los objetos waiting for one of the following objects - esperando uno de los siguientes objetos + esperando a uno de los siguientes objetos @@ -5741,12 +5976,12 @@ p, li { white-space: pre-wrap; } sleeping - dormido + reposando waiting for IPC reply - esperando para respuesta IPC + esperando respuesta IPC @@ -5831,12 +6066,12 @@ p, li { white-space: pre-wrap; } last running ticks = %1 - Últimos ticks consecutivos = %1 + últimos ticks consecutivos = %1 not waiting for mutex - no esperando por mutex + no esperando al mutex @@ -5844,7 +6079,7 @@ p, li { white-space: pre-wrap; } waited by thread - esperado por hilo + esperado por el hilo @@ -5852,7 +6087,7 @@ p, li { white-space: pre-wrap; } &Wait Tree - &Árbol de Espera + &Árbol de espera \ No newline at end of file diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts index 89aed0e6c..4ae16542c 100644 --- a/dist/languages/fr.ts +++ b/dist/languages/fr.ts @@ -183,7 +183,7 @@ p, li { white-space: pre-wrap; }</style></head><body style=" An error occurred while sending the Testcase - Une erreur est survenue en envoyant le cas de test + Une erreur est survenue lors de l'envoi du cas-type @@ -320,13 +320,13 @@ Cette option améliore la vitesse en réduisant la précision des instructions f <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - <div>Cette option améliore la vitesse des fonctions à virgule flottante 32 bits ASIMD en utilisant des modes d'arrondis incorrects.</div> + <div>Cette option améliore la vitesse des fonctions à virgule flottante 32 bits ASIMD en utilisant des modes d'arrondissement incorrects.</div> Faster ASIMD instructions (32 bits only) - Instructions ASIMD plus rapides (seulement 32 bits) + Instructions ASIMD plus rapides (32 bits seulement) @@ -382,7 +382,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Pour le débogage seulement.</span><br/>Si vous n'êtes pas sûr(e) de ce qu'ils font, gardez les tous activés.<br/>Ces paramètres, quand ils sont désactivés, prennent effet seulement quand le Débogage CPU est activé. </p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Pour le débogage seulement.</span><br/>Si vous n'êtes pas sûr(e) de ce qu'ils font, gardez les tous activés.<br/>Ces paramètres, lorsque désactivés, prennent effet seulement quand le Débogage CPU est activé. </p></body></html> @@ -541,7 +541,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f Show Log in Console - Afficher le log dans la console + Afficher le relevé d'événements dans la console @@ -551,7 +551,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f When checked, the max size of the log increases from 100 MB to 1 GB - Quand coché, la taille maximum du log augmente de 100 MB à 1 GB + Lorsque coché, la taille maximum du relevé d'événements augmente de 100 Mo à 1 Go @@ -576,7 +576,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f When checked, the graphics API enters a slower debugging mode - Quand coché, l'API graphique entre dans un mode de débug plus lent + Lorsque coché, l'API graphique entre dans un mode de débogage plus lent @@ -596,7 +596,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower - Quand coché, cela désactive le compilateur de macros JIT. L'activer ralentit les jeux + Lorsque coché, désactive le compilateur de macros JIT. L'activer ralentit les jeux @@ -664,7 +664,12 @@ Cette option améliore la vitesse en réduisant la précision des instructions f Activer l'Auto-Stub** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. **Ce sera réinitialisé automatiquement quand yuzu fermera. @@ -944,67 +949,78 @@ Cette option améliore la vitesse en réduisant la précision des instructions f Général - - Framerate Cap - Limite du 'frame rate' + + + Use global framerate cap + - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. Requière l'utilisation du raccourci Basculer la Limite des IPS pour être pris en compte. - + + Framerate Cap + Limite du 'frame rate' + + + x x - + Limit Speed Percent Limiter la vitesse en pourcentages - + % % - + Multicore CPU Emulation Emulation CPU Multicœur - + Confirm exit while emulation is running Confirmer la sortie pendent l'émulation en cours - + Prompt for user on game boot Demander un utilisateur au lancement d'un jeu - + Pause emulation when in background Mettre en pause l’émulation lorsque mis en arrière plan - + Hide mouse on inactivity Cacher la souris en cas d'inavtivité - + Reset All Settings Réinitialiser Tous les Paramètres - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Ceci réinitialise tout les paramètres et supprime toutes les configurations par jeu. Cela ne va pas supprimer les répertoires de jeu, les profils, ou les profils d'entrée. Continuer ? @@ -1079,7 +1095,7 @@ Cette option améliore la vitesse en réduisant la précision des instructions f GPU Video Decoding (Default) - Décodage Vidéo sur le CPU (par défaut) + Décodage Vidéo sur le GPU (par défaut) @@ -1122,18 +1138,113 @@ Cette option améliore la vitesse en réduisant la précision des instructions f Étirer à la fenêtre - - + + Resolution: + Résolution : + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [EXPÉRIMENTAL] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [EXPÉRIMENTAL] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + Filtre de fenêtre adaptatif + + + + Nearest Neighbor + Plus proche voisin + + + + Bilinear + Bilinéaire + + + + Bicubic + Bicubique + + + + Gaussian + Gaussien + + + + ScaleForce + ScaleForce + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + AMD FidelityFX™️ Super Resolution [Vulkan seulement] + + + + Anti-Aliasing Method: + Méthode d'anticrénelage : + + + + None + Aucune + + + + FXAA + FXAA + + + + Use global background color Utiliser une couleur d'arrière plan globale - + Set background color: Définir la couleur d'arrière plan: - + Background Color: Couleur de L’arrière plan : @@ -1202,28 +1313,33 @@ Cette option améliore la vitesse en réduisant la précision des instructions f + Automatic + Automatique + + + Default Défaut - - - 2x (WILL BREAK THINGS) - 2x (VA BRISER DES TRUCS) - - 4x (WILL BREAK THINGS) - 4x (VA BRISER DES TRUCS) + 2x + 2x - 8x (WILL BREAK THINGS) - 8x (VA BRISER DES TRUCS) + 4x + 4x - 16x (WILL BREAK THINGS) - 16x (VA BRISER DES TRUCS) + 8x + 8x + + + + 16x + 16x @@ -1550,8 +1666,8 @@ Cette option améliore la vitesse en réduisant la précision des instructions f - Other - Autres + Emulated Devices + @@ -1560,66 +1676,75 @@ Cette option améliore la vitesse en réduisant la précision des instructions f - Emulate Analog with Keyboard Input - Emuler l'analogique avec une entrée clavier - - - - Enable mouse panning - Activer le mouvement panorama avec la souris - - - - Mouse sensitivity - Sensibilité de la souris - - - - % - % - - - - - Advanced - Avancé - - - - Touchscreen - Écran tactile - - - Mouse Souris - - Motion / Touch - La motion / Toucher + + Touchscreen + Écran tactile - - - Configure - Configurer + + Advanced + Avancé - + Debug Controller Déboguer les manettes - + + + Configure + Configurer + + + + Other + Autres + + + + Emulate Analog with Keyboard Input + Emuler l'analogique avec une entrée clavier + + + Requires restarting yuzu Nécessite de redémarrer yuzu - + Enable XInput 8 player support (disables web applet) Activer le support de 8 joueurs avecc XInput (désactiver l'appliquette web) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Activer le mouvement panorama avec la souris + + + + Mouse sensitivity + Sensibilité de la souris + + + + % + % + + + + Motion / Touch + La motion / Toucher + ConfigureInputPlayer @@ -1634,425 +1759,441 @@ Cette option améliore la vitesse en réduisant la précision des instructions f Connecter la manette - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Deux Joycons - - - - - Left Joycon - Joycon de gauche - - - - - Right Joycon - Joycon de droit - - - - - Handheld - Mode Portable - - - + Input Device Périphérique d'entrée - - Any - N'importe quel - - - - Keyboard/Mouse - Clavier/Souris - - - + Profile Profil - + Save Sauvegarde - + New Nouveau - + Delete Supprimer - - + + Left Stick Stick Gauche - - - - - - + + + + + + Up Haut - - - - - - - + + + + + + + Left Gauche - - - - - - - + + + + + + + Right Droite - - - - - - + + + + + + Down Bas - - - - + + + + Pressed Appuyé - - - - + + + + Modifier Modificateur - - + + Range Portée - - + + % % - - + + Deadzone: 0% Zone morte: 0% - - + + Modifier Range: 0% Modification de la course: 0% - + D-Pad Pavé directionnel - - - + + + L L - - - + + + ZL ZL - - + + Minus Moins - - + + Capture Capturer - - - + + + Plus Plus - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Mouvement 1 - + Motion 2 Mouvement 2 - + Face Buttons Boutons - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Stick Droit - - - - + + + + Clear Effacer - - - - + + + + [not set] [non défini] - - + + Toggle button Bouton d'activation - - + + Invert button + + + + + + Invert axis + Inverser l'axe + + + + Set threshold Définir le seuil - + Choose a value between 0% and 100% Choisissez une valeur entre 0% et 100% - + Map Analog Stick Mapper le stick analogique - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Après avoir appuyé sur OK, bougez d'abord votre joystick horizontalement, puis verticalement. Pour inverser les axes, bougez d'abord votre joystick verticalement, puis horizontalement. - - Invert axis - Inverser l'axe - - - - + + Deadzone: %1% Zone morte: %1% - - + + Modifier Range: %1% Modification de la course: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Deux Joycons + + + + Left Joycon + Joycon de gauche + + + + Right Joycon + Joycon de droit + + + + Handheld + Mode Portable + + + GameCube Controller Manette GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pause - + Z Z - + Control Stick Stick de contrôle - + C-Stick C-Stick - + Shake! Secouez ! - + [waiting] [en attente] - + New Profile Nouveau Profil - + Enter a profile name: Entrez un nom de profil : - - + + Create Input Profile Créer un profil d'entrée - + The given profile name is not valid! Le nom de profil donné est invalide ! - + Failed to create the input profile "%1" Échec de la création du profil d'entrée "%1" - + Delete Input Profile Supprimer le profil d'entrée - + Failed to delete the input profile "%1" Échec de la suppression du profil d'entrée "%1" - + Load Input Profile Charger le profil d'entrée - + Failed to load the input profile "%1" Échec du chargement du profil d'entrée "%1" - + Save Input Profile Sauvegarder le profil d'entrée - + Failed to save the input profile "%1" Échec de la sauvegarde du profil d'entrée "%1" @@ -2078,85 +2219,75 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h ConfigureMotionTouch - + Configure Motion / Touch Configurer le contrôle par mouvement / tactile - - Mouse Motion - Mouvement de souris - - - - Sensitivity: - Sensibilité: - - - + Touch Tactile - + UDP Calibration: Calibration UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configurer - - Use button mapping: - Utiliser le mappage des boutons: + + Touch from button profile: + - + CemuhookUDP Config Configurer CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Vous pouvez utiliser n'importe quelle source d'entrée UDP compatible Cemuhook pour fournir le contrôle par mouvement et l'entrée tactile - + Server: Serveur: - + Port: Port: - + Learn More Plus d'informations - - + + Test Tester - + Add Server Ajouter un serveur - + Remove Server Retirer un serveur @@ -2166,145 +2297,81 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Plus d'informations</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Le numéro de port contient des caractères invalides - + Port has to be in range 0 and 65353 Le port doit être entre 0 et 65353 - + IP address is not valid L'adresse IP n'est pas valide - + This UDP server already exists Ce serveur UDP existe déjà - + Unable to add more than 8 servers Impossible d'ajouter plus de 8 serveurs - + Testing Essai - + Configuring Configuration - + Test Successful Test réussi - + Successfully received data from the server. Données reçues du serveur avec succès. - + Test Failed Test échoué - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Impossible de recevoir des données valides du serveur.<br>Veuillez vérifier que le serveur est correctement configuré et que l'adresse et le port sont corrects. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Le test UDP ou la configuration de l'étalonnage est en cours.<br>Veuillez attendre qu'ils se terminent. - - ConfigureMouseAdvanced - - - Configure Mouse - Configuration de la souris - - - - Mouse Buttons - Boutons de la souris - - - - Forward: - Avant : - - - - Back: - Arrière : - - - - Left: - Gauche : - - - - Middle: - Milieu : - - - - Right: - Droite : - - - - - Clear - Effacer - - - - Defaults - Défauts - - - - [not set] - [pas défini] - - - - Restore Default - Réinitialiser - - - - [press key] - [appuyez sur une touche] - - ConfigureNetwork @@ -2408,7 +2475,7 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h Adv. Graphics - + Adv. Graphiques @@ -2592,12 +2659,12 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h Error resizing user image - + Erreur de redimensionnement de l'image utilisateur Unable to resize image - + Impossible de redimensionner l'image @@ -3064,12 +3131,12 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - + <html><head/><body><p>Lit l'entrée du contrôleur à partir des scripts dans le même format que 'TAS-nx' <br/> Pour une explication plus détaillée, veuillez consulter le <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">page d'aide </span></a>sur le site Yuzu.</p></body></html> To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). - + Pour vérifier quelles touches de raccourci contrôlent la lecture/l'enregistrement, veuillez vous reporter aux paramètres des touches de raccourci (Configurer -> Général -> Touches de raccourci). @@ -3088,31 +3155,26 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h - Automatic controller profile swapping - Changer automatiquement le profile de la manette - - - Loop script Script de boucle - + Pause execution during loads Mettre en pause l'exécution pendant le chargement - + Script Directory Dossier de script - + Path Chemin - + ... ... @@ -3125,7 +3187,7 @@ Pour inverser les axes, bougez d'abord votre joystick verticalement, puis h Configuration du TAS - + Select TAS Load Directory... Sélectionner le dossier de chargement du TAS... @@ -3187,37 +3249,37 @@ Faites glisser les points pour modifier la position ou double-cliquez sur les ce Y - + New Profile Nouveau profil - + Enter the name for the new profile. Saisissez le nom du nouveau profil. - + Delete Profile Supprimer le profil - + Delete profile %1? Supprimer le profil %1? - + Rename Profile Renommer le profil - + New name: Nouveau nom: - + [press key] [appuyez sur une touche] @@ -3637,12 +3699,12 @@ Faites glisser les points pour modifier la position ou double-cliquez sur les ce ControllerDialog - + Controller P1 Contrôleur joueur 1 - + &Controller P1 &Contrôleur joueur 1 @@ -3650,90 +3712,95 @@ Faites glisser les points pour modifier la position ou double-cliquez sur les ce GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Des données anonymes sont collectées</a> pour aider à améliorer yuzu. <br/><br/>Voulez-vous partager vos données d'utilisations avec nous ? - + Telemetry Télémétrie - + Loading Web Applet... Chargement du Web Applet... - - + + Disable Web Applet Désactiver l'applet web - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Désactiver l'applet web l'empêchera de s'afficher à nouveau pour le reste de la session émulée. Cela peut causer des comportements indéfinis et ne devrait être utilisé qu'avec Super Mario 3D All-Stars. Voulez-vous vraiment désactiver l'applet web? - + The amount of shaders currently being built La quantité de shaders en cours de construction - + + The current selected resolution scaling multiplier. + Le multiplicateur de mise à l'échelle de résolution actuellement sélectionné. + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Valeur actuelle de la vitesse de l'émulation. Des valeurs plus hautes ou plus basses que 100% indique que l'émulation fonctionne plus vite ou plus lentement qu'une véritable Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Combien d'image par seconde le jeu est en train d'afficher. Ceci vas varier de jeu en jeu et de scènes en scènes. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Temps pris pour émuler une image par seconde de la switch, sans compter le limiteur d'image par seconde ou la synchronisation verticale. Pour une émulation à pleine vitesse, ceci devrait être au maximum à 16.67 ms. - + Invalid config detected Configuration invalide détectée - + Handheld controller can't be used on docked mode. Pro controller will be selected. Contrôleur portable ne peut pas être utilisé en mode téléviseur. La manette Pro sera sélectionnée. - + DOCK MODE TV - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Effacer les fichiers récents - - TAS Recording - Enregistrement TAS + + &Continue + &Continuer - - Overwrite file of player 1? - Ecraser le fichier du joueur 1 ? + + &Pause + @@ -3784,657 +3851,724 @@ Faites glisser les points pour modifier la position ou double-cliquez sur les ce Une erreur inconnue est survenue. Veuillez consulter le journal des logs pour plus de détails. - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Démarrer - - - + Save Data Enregistrer les données - + Mod Data Donnés du Mod - + Error Opening %1 Folder Erreur dans l'ouverture du dossier %1. - - + + Folder does not exist! Le dossier n'existe pas ! - + Error Opening Transferable Shader Cache Erreur lors de l'ouverture des Shader Cache Transferable - + Failed to create the shader cache directory for this title. Impossible de créer le dossier de cache du shader pour ce jeu. - + Contents Contenus - + Update Mise à jour - + DLC DLC - + Remove Entry Supprimer l'entrée - + Remove Installed Game %1? Supprimer le jeu installé %1? - - - - - - + + + + + + Successfully Removed Supprimé avec succès - + Successfully removed the installed base game. Suppression du jeu de base installé avec succès. - - - + + + Error Removing %1 Erreur lors de la suppression %1 - + The base game is not installed in the NAND and cannot be removed. Le jeu de base n'est pas installé dans la NAND et ne peut pas être supprimé. - + Successfully removed the installed update. Suppression de la mise à jour installée avec succès. - + There is no update installed for this title. Il n'y a pas de mise à jour installée pour ce titre. - + There are no DLC installed for this title. Il n'y a pas de DLC installé pour ce titre. - + Successfully removed %1 installed DLC. Suppression de %1 DLC installé(s) avec succès. - + Delete OpenGL Transferable Shader Cache? Supprimer la Cache OpenGL de Shader Transférable? - + Delete Vulkan Transferable Shader Cache? Supprimer la Cache Vulkan de Shader Transférable? - + Delete All Transferable Shader Caches? Supprimer Toutes les Caches de Shader Transférable? - + Remove Custom Game Configuration? Supprimer la configuration personnalisée du jeu? - + Remove File Supprimer fichier - - + + Error Removing Transferable Shader Cache Erreur lors de la suppression du cache de shader transférable - - + + A shader cache for this title does not exist. Un shader cache pour ce titre n'existe pas. - + Successfully removed the transferable shader cache. Suppression du cache de shader transférable avec succès. - + Failed to remove the transferable shader cache. Échec de la suppression du cache de shader transférable. - - + + Error Removing Transferable Shader Caches Erreur durant la Suppression des Caches de Shader Transférable - + Successfully removed the transferable shader caches. Suppression des caches de shader transférable effectuée avec succès. - + Failed to remove the transferable shader cache directory. Impossible de supprimer le dossier de la cache de shader transférable. - - + + Error Removing Custom Configuration Erreur lors de la suppression de la configuration personnalisée - + A custom configuration for this title does not exist. Il n'existe pas de configuration personnalisée pour ce titre. - + Successfully removed the custom game configuration. Suppression de la configuration de jeu personnalisée avec succès. - + Failed to remove the custom game configuration. Échec de la suppression de la configuration personnalisée du jeu. - - + + RomFS Extraction Failed! L'extraction de la RomFS a échoué ! - + There was an error copying the RomFS files or the user cancelled the operation. Une erreur s'est produite lors de la copie des fichiers RomFS ou l'utilisateur a annulé l'opération. - + Full Plein - + Skeleton Squelette - + Select RomFS Dump Mode Sélectionnez le mode d'extraction de la RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Veuillez sélectionner la manière dont vous souhaitez que le fichier RomFS soit extrait.<br>Full copiera tous les fichiers dans le nouveau répertoire, tandis que<br>skeleton créera uniquement la structure de répertoires. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root Il n'y a pas assez d'espace libre dans %1 pour extraire la RomFS. Veuillez libérer de l'espace ou sélectionner un autre dossier d'extraction dans Émulation > Configuration > Système > Système de fichier > Extraire la racine - + Extracting RomFS... Extraction de la RomFS ... - - + + Cancel Annuler - + RomFS Extraction Succeeded! Extraction de la RomFS réussi ! - + The operation completed successfully. L'opération s'est déroulée avec succès. - + Error Opening %1 Erreur lors de l'ouverture %1 - + Select Directory Sélectionner un répertoire - + Properties Propriétés - + The game properties could not be loaded. Les propriétés du jeu n'ont pas pu être chargées. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Exécutable Switch (%1);;Tous les fichiers (*.*) - + Load File Charger un fichier - + Open Extracted ROM Directory Ouvrir le dossier des ROM extraites - + Invalid Directory Selected Destination sélectionnée invalide - + The directory you have selected does not contain a 'main' file. Le répertoire que vous avez sélectionné ne contient pas de fichier "main". - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Fichier Switch installable (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Installer les fichiers - + %n file(s) remaining %n fichier restant%n fichiers restants - + Installing file "%1"... Installation du fichier "%1" ... - - + + Install Results Résultats d'installation - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Pour éviter d'éventuels conflits, nous déconseillons aux utilisateurs d'installer des jeux de base sur la NAND. Veuillez n'utiliser cette fonctionnalité que pour installer des mises à jour et des DLC. - + %n file(s) were newly installed %n fichier a été nouvellement installé%n fichiers ont été nouvellement installés - + %n file(s) were overwritten %n fichier a été écrasé%n fichiers ont été écrasés - + %n file(s) failed to install %n fichier n'a pas pu être installé%n fichiers n'ont pas pu être installés - + System Application Application Système - + System Archive Archive Système - + System Application Update Mise à jour de l'application système - + Firmware Package (Type A) Paquet micrologiciel (Type A) - + Firmware Package (Type B) Paquet micrologiciel (Type B) - + Game Jeu - + Game Update Mise à jour de jeu - + Game DLC DLC de jeu - + Delta Title Titre Delta - + Select NCA Install Type... Sélectionner le type d'installation du NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Veuillez sélectionner le type de titre auquel vous voulez installer ce NCA : (Dans la plupart des cas, le titre par défaut : 'Jeu' est correct.) - + Failed to Install Échec de l'installation - + The title type you selected for the NCA is invalid. Le type de titre que vous avez sélectionné pour le NCA n'est pas valide. - + File not found Fichier non trouvé - + File "%1" not found Fichier "%1" non trouvé - - - &Continue - &Continuer - - - + OK OK - + Missing yuzu Account Compte yuzu manquant - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Pour soumettre un test de compatibilité pour un jeu, vous devez lier votre compte yuzu.<br><br/>Pour lier votre compte yuzu, aller à Emulation &gt; Configuration&gt; Web. - + Error opening URL Erreur lors de l'ouverture de l'URL - + Unable to open the URL "%1". Impossible d'ouvrir l'URL "%1". - + + TAS Recording + Enregistrement TAS + + + + Overwrite file of player 1? + Ecraser le fichier du joueur 1 ? + + + Amiibo File (%1);; All Files (*.*) Fichier Amiibo (%1);; Tous les fichiers (*.*) - + Load Amiibo Charger un Amiibo - + Error opening Amiibo data file Erreur lors de l'ouverture du fichier de données Amiibo - + Unable to open Amiibo file "%1" for reading. Impossible d'ouvrir le fichier Amiibo "%1" à lire. - + Error reading Amiibo data file Erreur lors de la lecture du fichier de données Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Impossible de lire entièrement les données Amiibo. On s'attend à lire %1 octets, mais il n'a pu lire que %2 octets - + Error loading Amiibo data Erreur lors du chargement des données Amiibo - + Unable to load Amiibo data. Impossible de charger les données Amiibo. - + Capture Screenshot Capture d'écran - + PNG Image (*.png) Image PNG (*.png) - + TAS state: Running %1/%2 Etat du TAS : En cours d'exécution %1/%2 - + TAS state: Recording %1 Etat du TAS : Enregistrement %1 - + TAS state: Idle %1/%2 Etat du TAS : Inactif %1:%2 - + TAS State: Invalid Etat du TAS : Invalide + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) Compilation: %n shaderCompilation: %n shaders - + + Scale: %1x + %1 is the resolution scaling factor + Échelle : %1x + + + Speed: %1% / %2% Vitesse : %1% / %2% - + Speed: %1% Vitesse : %1% - + Game: %1 FPS (Unlocked) Jeu: %1 IPS (Débloqué) - + Game: %1 FPS Jeu : %1 FPS - + Frame: %1 ms Frame : %1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU HAUT - + GPU EXTREME GPU EXTRÊME - + GPU ERROR GPU ERREUR - + + NEAREST + PLUS PROCHE + + + + + BILINEAR + BILINÉAIRE + + + + BICUBIC + BICUBIQUE + + + + GAUSSIAN + GAUSSIEN + + + + SCALEFORCE + SCALEFORCE + + + + FSR + FSR + + + + + NO AA + AUCUN AA + + + + FXAA + FXAA + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Le jeu que vous essayez de charger a besoin de fichiers additionnels que vous devez extraire depuis votre Switch avant de jouer.<br/><br/>Pour plus d'information sur l'extraction de ces fichiers, veuillez consulter la page du wiki suivante : <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Extraction des archives système et des Shared Fonts depuis la Switch</a>.<br/><br/>Voulez-vous quitter la liste des jeux ? Une émulation continue peut entraîner des crashs, la corruption de données de sauvegarde ou d’autres bugs. - + yuzu was unable to locate a Switch system archive. %1 yuzu n'a pas été capable de localiser un système d'archive Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu n'a pas été capable de localiser un système d'archive Switch. %1. %2 - + System Archive Not Found Archive système introuvable - + System Archive Missing Archive Système Manquante - + yuzu was unable to locate the Switch shared fonts. %1 Yuzu n'a pas été capable de localiser les polices partagées de la Switch. %1 - + Shared Fonts Not Found Les polices partagées non pas été trouvées - + Shared Font Missing Polices Partagée Manquante - + Fatal Error Erreur fatale - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu a rencontré une erreur fatale, veuillez consulter les logs pour plus de détails. Pour plus d'informations sur l'accès aux logs, veuillez consulter la page suivante : <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'> Comment télécharger le fichier des logs </a>.<br/><br/>Voulez-vous quitter la liste des jeux ? Une émulation continue peut entraîner des crashs, la corruption de données de sauvegarde ou d’autres bugs. - + Fatal Error encountered Erreur Fatale rencontrée - + Confirm Key Rederivation Confirmer la réinstallation de la clé - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4451,37 +4585,37 @@ et éventuellement faites des sauvegardes. Cela supprimera vos fichiers de clé générés automatiquement et ré exécutera le module d'installation de clé. - + Missing fuses Fusibles manquants - + - Missing BOOT0 - BOOT0 manquant - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Main manquant - + - Missing PRODINFO - PRODINFO manquant - + Derivation Components Missing Composants de dérivation manquants - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Il manque des composants qui peuvent empêcher la dérivation de clé de se terminer. <br>Veuillez suivre<a href='https://yuzu-emu.org/help/quickstart/'>le guide de démarrage rapide de yuzu</a> pour obtenir toutes vos clés et tous vos jeux.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + Les clés de chiffrement sont manquantes. <br>Veuillez suivre <a href='https://yuzu-emu.org/help/quickstart/'>le guide de démarrage rapide yuzu</a> pour obtenir tous vos clés, firmware et jeux.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4490,39 +4624,39 @@ Cela peut prendre jusqu'à une minute en fonction des performances de votre système. - + Deriving Keys Installation des clés - + Select RomFS Dump Target Sélectionner la cible d'extraction du RomFS - + Please select which RomFS you would like to dump. Veuillez sélectionner quel RomFS vous voulez extraire. - + Are you sure you want to close yuzu? Êtes vous sûr de vouloir fermer yuzu ? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Êtes-vous sûr d'arrêter l'émulation ? Tout progrès non enregistré sera perdu. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4534,38 +4668,38 @@ Voulez-vous ignorer ceci and quitter quand même ? GRenderWindow - + OpenGL not available! OpenGL n'est pas disponible! - + yuzu has not been compiled with OpenGL support. yuzu n'a pas été compilé avec le support OpenGL. - - + + Error while initializing OpenGL! Erreur lors de l'initialisation d'OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Votre GPU peut ne pas prendre en charge OpenGL, ou vous n'avez pas les derniers pilotes graphiques. - + Error while initializing OpenGL 4.6! Erreur lors de l'initialisation d'OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Votre GPU peut ne pas prendre en charge OpenGL 4.6 ou vous ne disposez pas du dernier pilote graphique: %1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Votre GPU peut ne pas prendre en charge une ou plusieurs extensions OpenGL requises. Veuillez vous assurer que vous disposez du dernier pilote graphique.<br><br>GL Renderer:<br>%1<br><br>Extensions non prises en charge:<br>%2 @@ -4925,190 +5059,205 @@ Screen. &Émulation - + &View &Vue - + &Reset Window Size &Réinitialiser la taille de la fenêtre - - Reset Window Size to &720p - &Réinitialiser la taille de la fenêtre à 720p - - - - Reset Window Size to 720p - Réinitialiser la taille de la fenêtre à 720p - - - - Reset Window Size to &900p - Réinitialiser la taille de la fenêtre à &900p - - - - Reset Window Size to 900p - Réinitialiser la taille de la fenêtre à 900p - - - - Reset Window Size to &1080p - Réinitialiser la taille de la fenêtre à &1080p - - - - Reset Window Size to 1080p - Réinitialiser la taille de la fenêtre à 1080p - - - + &Debugging &Débogage - + + Reset Window Size to &720p + &Réinitialiser la taille de la fenêtre à 720p + + + + Reset Window Size to 720p + Réinitialiser la taille de la fenêtre à 720p + + + + Reset Window Size to &900p + Réinitialiser la taille de la fenêtre à &900p + + + + Reset Window Size to 900p + Réinitialiser la taille de la fenêtre à 900p + + + + Reset Window Size to &1080p + Réinitialiser la taille de la fenêtre à &1080p + + + + Reset Window Size to 1080p + Réinitialiser la taille de la fenêtre à 1080p + + + &Tools &Outils - + + &TAS + + + + &Help &Aide - + &Install Files to NAND... &Installer des fichiers sur la NAND... - + L&oad File... &Charger un fichier... - + Load &Folder... &Charger un dossier - + E&xit Q&uitter - - &Start - &Démarrer - - - + &Pause &Pause - + &Stop &Arrêter - + &Reinitialize keys... &Réinitialiser les clés... - + &About yuzu &À propos de yuzu - + Single &Window Mode &Mode fenêtre unique - + Con&figure... &Configurer... - + Display D&ock Widget Headers &Afficher les en-têtes du widget Dock - + Show &Filter Bar &Afficher la barre de filtre - + Show &Status Bar &Afficher la barre d'état - + Show Status Bar Afficher la barre d'état - + F&ullscreen P&lein écran - + &Restart &Redémarrer - + Load &Amiibo... Charger un &Amiibo - + &Report Compatibility &Signaler la compatibilité - + Open &Mods Page Ouvrir la &Page des Mods - + Open &Quickstart Guide Ouvrir le &Guide de Démarrage rapide - + &FAQ &FAQ - + Open &yuzu Folder Ouvrir le &Dossier de Yuzu - + &Capture Screenshot &Capture d'écran - - Configure &TAS... - Configurer le &TAS... + + &Configure TAS... + - + Configure C&urrent Game... Configurer le J&eu actuel... + + + &Start + &Démarrer + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5154,10 +5303,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE Démarrer/Pause + + + Charging + + QObject @@ -5188,142 +5342,222 @@ p, li { white-space: pre-wrap; } - - + Shift Maj - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [non défini] - - Hat %1 %2 Chapeau %1 %2 - - - - - - + + + + Axis %1%2 Axe %1%2 - Button %1 Bouton %1 - - - + + + [unknown] [inconnu] - + + Left + + + + + Right + + + - Click 0 - Clic 0 + Down + - - Click 1 - Clic 1 + Up + - - Click 2 - Clic 2 + Z + - - Click 3 - Clic 3 + R + - - Click 4 - Clic 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - Axe GameCube %1%2 + + [invalid] + - - GC Button %1 - Bouton GameCube %1 + + + %1%2Hat %3 + - - TAS Axis %1 - Axe TAS %1 + + + + %1%2Axis %3 + - - TAS Btn %1 - Btn TAS %1 + + %1%2Axis %3,%4,%5 + - - Motion %1 - Mouvement %1 + + %1%2Motion %3 + - - %1Button %2 - %1Bouton %2 + + + %1%2Button %3 + - - SDL Motion - SDL Motion - - - - %1Click %2 - %1Clic %2 - - - + [unused] [inutilisé] @@ -5364,7 +5598,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5377,7 +5611,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Deux Joycons @@ -5390,7 +5624,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Joycon gauche @@ -5403,7 +5637,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Joycon droit @@ -5431,7 +5665,7 @@ p, li { white-space: pre-wrap; } - + Handheld Portable @@ -5552,7 +5786,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Manette GameCube @@ -5646,13 +5880,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Annuler diff --git a/dist/languages/it.ts b/dist/languages/it.ts index 9934199c7..7511099b1 100644 --- a/dist/languages/it.ts +++ b/dist/languages/it.ts @@ -378,7 +378,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Solo durante il debug.</span><br/>Se non sei sicuro su cosa facciano queste opzioni, lasciale tutte attive.<br/>Queste opzioni avranno effetto solo se la modalità di Debug della CPU è attiva</p></body></html> @@ -654,7 +654,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -934,67 +939,78 @@ p, li { white-space: pre-wrap; } Generale - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Percentuale Limite Velocità - + % % - + Multicore CPU Emulation Emulazione CPU Multicore - + Confirm exit while emulation is running Richiedi conferma di uscire mentre l'emulazione è in corso - + Prompt for user on game boot Richiedi utente all'avvio di un gioco - + Pause emulation when in background Pausa emulazione quando in background - + Hide mouse on inactivity Nascondi il puntatore del mouse se inattivo - + Reset All Settings Resetta tutte le impostazioni - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Questo resetta tutte le impostazioni e rimuove tutte le configurazioni per gioco. Questo, non cancellerà le cartelle di gioco, i profili o i profili di input. Vuoi Procedere ? @@ -1112,18 +1128,113 @@ p, li { white-space: pre-wrap; } Allunga a finestra - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Usa il colore di sfondo globale - + Set background color: Imposta colore dello sfondo: - + Background Color: Colore Sfondo: @@ -1192,27 +1303,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Predefinito - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1540,8 +1656,8 @@ p, li { white-space: pre-wrap; } - Other - Altro + Emulated Devices + @@ -1550,66 +1666,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emula le levette analogiche con la tastiera - - - - Enable mouse panning - Abilita mouse panning - - - - Mouse sensitivity - Sensibilità del mouse - - - - % - - - - - - Advanced - Avanzate - - - - Touchscreen - Touchscreen - - - Mouse Mouse - - Motion / Touch - Movimento/tocco + + Touchscreen + Touchscreen - - - Configure - Configura + + Advanced + Avanzate - + Debug Controller Debug Controller - + + + Configure + Configura + + + + Other + Altro + + + + Emulate Analog with Keyboard Input + Emula le levette analogiche con la tastiera + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Abilita mouse panning + + + + Mouse sensitivity + Sensibilità del mouse + + + + % + + + + + Motion / Touch + Movimento/tocco + ConfigureInputPlayer @@ -1624,425 +1749,441 @@ p, li { white-space: pre-wrap; } Controller connesso - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Due Joycon - - - - - Left Joycon - Joycon sinistro - - - - - Right Joycon - Joycon destro - - - - - Handheld - Portatile - - - + Input Device Dispositivo input - - Any - Qualsiasi - - - - Keyboard/Mouse - Tastiera/mouse - - - + Profile Profilo - + Save Salva - + New Nuovo - + Delete Elimina - - + + Left Stick Stick Sinistro - - - - - - + + + + + + Up Su - - - - - - - + + + + + + + Left Sinistra - - - - - - - + + + + + + + Right Destra - - - - - - + + + + + + Down Giù - - - - + + + + Pressed Premuto - - - - + + + + Modifier Modificatore - - + + Range Raggio - - + + % % - - + + Deadzone: 0% Zona morta: 0% - - + + Modifier Range: 0% Modifica raggio: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Meno - - + + Capture Cattura - - - + + + Plus Più - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Movimento 1 - + Motion 2 Movimento 2 - + Face Buttons Pulsanti Frontali - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Stick Destro - - - - + + + + Clear Cancella - - - - + + + + [not set] [non impostato] - - + + Toggle button Premi il bottone - - + + Invert button + + + + + + Invert axis + Inverti assi + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick Mappa la levetta analogica - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Dopo aver premuto OK, prima muovi la levetta orizzontalmente, e poi verticalmente. Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalmente. - - Invert axis - Inverti assi - - - - + + Deadzone: %1% Zona morta: %1% - - + + Modifier Range: %1% Modifica raggio: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Due Joycon + + + + Left Joycon + Joycon sinistro + + + + Right Joycon + Joycon destro + + + + Handheld + Portatile + + + GameCube Controller Controller GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Inizia / Interrompi - + Z Z - + Control Stick Levetta di Controllo - + C-Stick Levetta C - + Shake! Scuoti! - + [waiting] [in attesa] - + New Profile Nuovo Profilo - + Enter a profile name: Inserisci un nome profilo: - - + + Create Input Profile Crea un profilo di Input - + The given profile name is not valid! Il nome profilo dato non è valido! - + Failed to create the input profile "%1" Impossibile creare il profilo di input "%1" - + Delete Input Profile Elimina un profilo di Input - + Failed to delete the input profile "%1" Impossibile eliminare il profilo di input "%1" - + Load Input Profile Carica un profilo di Input - + Failed to load the input profile "%1" Impossibile caricare il profilo di input "%1" - + Save Input Profile Salva un profilo di Input - + Failed to save the input profile "%1" Impossibile creare il profilo di input "%1" @@ -2068,85 +2209,75 @@ Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalme ConfigureMotionTouch - + Configure Motion / Touch Configura movimento/tocco - - Mouse Motion - Movimento del mouse - - - - Sensitivity: - Sensibilità: - - - + Touch Touch - + UDP Calibration: Calibrazione UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configura - - Use button mapping: - Usa mappatura pulsanti + + Touch from button profile: + - + CemuhookUDP Config Configurazione CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Dovresti utilizzare qualsiasi sorgente di ingresso UDP compatibile con Cemuhook per fornire input di movimento e tocco. - + Server: Server: - + Port: Porta: - + Learn More Per saperne di più - - + + Test Test - + Add Server Aggiungi un Server - + Remove Server Rimuovi un Server @@ -2156,145 +2287,81 @@ Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalme <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Per saperne di più</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Il numero di porta ha caratteri non validi - + Port has to be in range 0 and 65353 La valore della porta deve essere compreso tra 0 e 65353 inclusi - + IP address is not valid Indirizzo IP non valido - + This UDP server already exists Questo server UDP esiste già - + Unable to add more than 8 servers Impossibile aggiungere più di 8 server - + Testing Testando - + Configuring Configurando - + Test Successful Test riuscito - + Successfully received data from the server. Ricevuti con successo dati dal server. - + Test Failed Test fallito - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Impossibile ricevere dati validi dal server.<br> Verificare che il server sia impostato correttamente e che indirizzo e porta siano corretti. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. È in corso il test UDP o la configurazione della calibrazione,<br> attendere che finiscano. - - ConfigureMouseAdvanced - - - Configure Mouse - Configura Mouse - - - - Mouse Buttons - Pulsanti Mouse - - - - Forward: - Avanti: - - - - Back: - Indietro: - - - - Left: - Sinistro: - - - - Middle: - Centrale: - - - - Right: - Destro: - - - - - Clear - Cancella - - - - Defaults - Predefiniti - - - - [not set] - [non impostato] - - - - Restore Default - Ripristina Predefinito - - - - [press key] - [premi un pulsante] - - ConfigureNetwork @@ -3049,12 +3116,12 @@ Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalme TAS - + TAS <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - + <html><head/><body><p>Gli script vengono letti seguendo lo stesso formato degli script di TAS-nx.<br/>Per saperne di più, puoi consultare <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">questa pagina</span></a>sul sito di yuzu.</p></body></html> @@ -3064,45 +3131,40 @@ Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalme WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method. - + IMPORTANTE: questa funzione è ancora in fase sperimentale.<br/>Gli script NON verranno riprodotti perfettamente. Settings - + Impostazioni Enable TAS features - + Attiva le funzioni di TASing - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Cartella degli script - + Path - + ... @@ -3115,7 +3177,7 @@ Per invertire gli assi, prima muovi la levetta verticalmente, e poi orizzontalme - + Select TAS Load Directory... @@ -3177,37 +3239,37 @@ Trascina i punti per cambiare posizione, oppure clicca due volte la cella in tab Y - + New Profile Nuovo Profilo - + Enter the name for the new profile. Inserisci il nome per il nuovo profilo: - + Delete Profile Elimina Profilo - + Delete profile %1? Elimina profilo %1? - + Rename Profile Rinomina Profilo - + New name: Nuovo nome: - + [press key] [premi pulsante] @@ -3297,7 +3359,7 @@ Trascina i punti per cambiare posizione, oppure clicca due volte la cella in tab Filename - + Nome del file @@ -3307,12 +3369,12 @@ Trascina i punti per cambiare posizione, oppure clicca due volte la cella in tab Title ID - + ID del gioco (Title ID) Title Name - + Nome del gioco @@ -3627,12 +3689,12 @@ Trascina i punti per cambiare posizione, oppure clicca due volte la cella in tab ControllerDialog - + Controller P1 Controller P1 - + &Controller P1 &Controller P1 @@ -3640,90 +3702,95 @@ Trascina i punti per cambiare posizione, oppure clicca due volte la cella in tab GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Vengono raccolti dati anonimi</a> per aiutarci a migliorare yuzu. <br/><br/>Desideri condividere i tuoi dati di utilizzo con noi? - + Telemetry Telemetria - + Loading Web Applet... Caricamento Web Applet... - - + + Disable Web Applet Disabilita l'Applet Web - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? La disabilitazione dell'applet Web farà sì che non venga più mostrata per il resto della sessione emulata. Questo può portare a un comportamento indefinito e dovrebbe essere usato solo con Super Mario 3D All-Stars. Sei sicuro di voler disabilitare l'applet web? - + The amount of shaders currently being built Il numero di shaders al momento in costruzione - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocità corrente dell'emulazione. Valori più alti o più bassi di 100% indicano che l'emulazione sta funzionando più velocemente o lentamente rispetto a una Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quanti frame al secondo il gioco mostra attualmente. Questo varia da gioco a gioco e da situazione a situazione. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo utilizzato per emulare un frame della Switch, non contando i limiti ai frame o il v-sync. Per un'emulazione alla massima velocità, il valore dev'essere al massimo 16.67 ms. - + Invalid config detected Trovata configurazione invalida - + Handheld controller can't be used on docked mode. Pro controller will be selected. Il controller Handheld non può essere utilizzato in modalità docked. Verrà selezionato il controller Pro. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Cancella i File Recenti - - TAS Recording - + + &Continue + &Continua - - Overwrite file of player 1? + + &Pause @@ -3775,658 +3842,725 @@ Per un'emulazione alla massima velocità, il valore dev'essere al mass E' stato riscontrato un errore sconosciuto. Visualizza il log per maggiori dettagli. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Avvia - - - + Save Data Dati di Salvataggio - + Mod Data Dati delle Mod - + Error Opening %1 Folder Errore nell'Apertura della Cartella %1 - - + + Folder does not exist! La cartella non esiste! - + Error Opening Transferable Shader Cache Errore nell'Apertura della Cache Shader Trasferibile - + Failed to create the shader cache directory for this title. - + Contents Contenuti - + Update Aggiorna - + DLC DLC - + Remove Entry Rimuovi voce - + Remove Installed Game %1? Rimuovere i giochi installati %1? - - - - - - + + + + + + Successfully Removed Rimosso con successo - + Successfully removed the installed base game. Rimosso con successo il gioco base installato - - - + + + Error Removing %1 Errore durante la rimozione %1 - + The base game is not installed in the NAND and cannot be removed. Il gioco base non è installato su NAND e non può essere rimosso. - + Successfully removed the installed update. Aggiornamento rimosso on successo. - + There is no update installed for this title. Non c'è alcun aggiornamento installato per questo gioco. - + There are no DLC installed for this title. Non c'è alcun DLC installato per questo gioco. - + Successfully removed %1 installed DLC. Rimossi con successo %1 DLC installati. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Rimuovere la configurazione personalizzata del gioco? - + Remove File Rimuovi file? - - + + Error Removing Transferable Shader Cache Errore rimuovendo la shader cache trasferibile. - - + + A shader cache for this title does not exist. Una cache di shader per questo titolo non esiste. - + Successfully removed the transferable shader cache. Rimossa con successo la shader cache trasferibile. - + Failed to remove the transferable shader cache. Impossibile rimuovere la cache dello shader trasferibile. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Errore rimuovendo la configurazione personalizzata - + A custom configuration for this title does not exist. Una configurazione personalizzata per questo gioco non esiste. - + Successfully removed the custom game configuration. Rimossa con successo la configurazione personalizzata del gioco. - + Failed to remove the custom game configuration. Impossibile rimuovere la configurazione personalizzata del gioco - - + + RomFS Extraction Failed! Estrazione RomFS Fallita! - + There was an error copying the RomFS files or the user cancelled the operation. C'è stato un errore nella copia dei file del RomFS o l'operazione è stata annullata dall'utente. - + Full Completa - + Skeleton Scheletro. - + Select RomFS Dump Mode Seleziona Modalità Estrazione RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Seleziona come vorresti estrarre il RomFS. <br>Completo copierà tutti i file in una nuova cartella mentre<br>scheletro creerà solamente le cartelle e le sottocartelle. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Estrazione RomFS in corso... - - + + Cancel Annulla - + RomFS Extraction Succeeded! Estrazione RomFS Riuscita! - + The operation completed successfully. L'operazione è stata completata con successo. - + Error Opening %1 Errore nell'Apertura di %1 - + Select Directory Seleziona Cartella - + Properties Proprietà - + The game properties could not be loaded. Le proprietà del gioco non sono potute essere caricate. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Eseguibile Switch (%1);;Tutti i File (*.*) - + Load File Carica File - + Open Extracted ROM Directory Apri Cartella ROM Estratta - + Invalid Directory Selected Cartella Selezionata Non Valida - + The directory you have selected does not contain a 'main' file. La cartella che hai selezionato non contiene un file "main". - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) File installabili Switch (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Installa files - + %n file(s) remaining - + Installing file "%1"... Installazione del file "%1"... - - + + Install Results Installa risultati - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Per evitare possibli conflitti, scoraggiamo gli utenti dall'installare giochi base su NAND. Per favore, usare questa funzione solo per installare aggiornamenti e DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Applicazione di Sistema - + System Archive Archivio di Sistema - + System Application Update Aggiornamento Applicazione di Sistema - + Firmware Package (Type A) Pacchetto Firmware (Tipo A) - + Firmware Package (Type B) Pacchetto Firmware (Tipo B) - + Game Gioco - + Game Update Aggiornamento di Gioco - + Game DLC DLC Gioco - + Delta Title Titolo Delta - + Select NCA Install Type... Seleziona il Tipo di Installazione NCA - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Seleziona il tipo del file NCA da installare: (Nella maggior parte dei casi, il predefinito 'Gioco' va bene.) - + Failed to Install Installazione Fallita - + The title type you selected for the NCA is invalid. Il tipo che hai selezionato per l'NCA non è valido. - + File not found File non trovato - + File "%1" not found File "%1" non trovato - - - &Continue - &Continua - - - + OK OK - + Missing yuzu Account Account di yuzu non trovato - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Per segnalare la compatibilità di un gioco, devi collegare il tuo account yuzu. <br><br/>Per collegare il tuo account yuzu, vai su Emulazione &gt; Configurazione &gt; Web. - + Error opening URL Errore aprendo l'URL - + Unable to open the URL "%1". Impossibile aprire l'URL "% 1". - + + TAS Recording + + + + + Overwrite file of player 1? + Vuoi sovrascrivere lo script del giocatore 1? + + + Amiibo File (%1);; All Files (*.*) File Amiibo (%1);; Tutti I File (*.*) - + Load Amiibo Carica Amiibo - + Error opening Amiibo data file Errore nell'apertura del file dati Amiibo - + Unable to open Amiibo file "%1" for reading. Impossibile aprire e leggere il file Amiibo "%1". - + Error reading Amiibo data file Errore nella lettura dei dati del file Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Impossibile leggere tutti i dati dell'Amiibo. E' stato possibile leggere solamente %2 byte di %1. - + Error loading Amiibo data Errore nel caricamento dei dati dell'Amiibo. - + Unable to load Amiibo data. Impossibile caricare i dati dell'Amiibo. - + Capture Screenshot Cattura Screenshot - + PNG Image (*.png) Immagine PNG (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Velocità: %1% / %2% - + Speed: %1% Velocità: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Gioco: %1 FPS - + Frame: %1 ms Frame: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Il gioco che stai provando a caricare richiede ulteriori file che devono essere estratti dalla tua Switch prima di poter giocare. <br/><br/>Per maggiori informazioni sull'estrazione di questi file, visualizza la seguente pagina della wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Estrazione di Archivi di Sistema e Font Condivisi da una Console Switch</a>.<br/><br/>Vuoi uscire e tornare alla lista dei giochi? Continuare l'emulazione potrebbe risultare in crash, salvataggi corrotti o altri bug. - + yuzu was unable to locate a Switch system archive. %1 yuzu non ha potuto individuare un archivio di sistema della Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu non ha potuto individuare un archivio di sistema della Switch: %1. %2 - + System Archive Not Found Archivio di Sistema Non Trovato - + System Archive Missing Archivio di Sistema Mancante - + yuzu was unable to locate the Switch shared fonts. %1 yuzu non ha potuto individuare i font condivisi della Switch. %1 - + Shared Fonts Not Found Font Condivisi Non Trovati - + Shared Font Missing Font Condivisi Mancanti - + Fatal Error Errore Fatale - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu ha riscontrato un errore fatale, visualizza il log per maggiori dettagli. Per maggiori informazioni su come accedere al log, visualizza la seguente pagina: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Come Caricare Il File Log</a>.<br/><br/>Vuoi uscire e tornare alla lista dei giochi? Continuare l'emulazione potrebbe risultare in crash, salvataggi corrotti o altri bug. - + Fatal Error encountered Errore Fatale riscontrato - + Confirm Key Rederivation Conferma Riderivazione Chiave - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4443,37 +4577,37 @@ e facoltativamente fai dei backup. Questo eliminerà i tuoi file di chiavi autogenerati e ri-avvierà il processo di derivazione delle chiavi. - + Missing fuses Fusi mancanti - + - Missing BOOT0 - Manca BOOT0 - + - Missing BCPKG2-1-Normal-Main - Manca BCPKG2-1-Normal-Main - + - Missing PRODINFO - Manca PRODINFO - + Derivation Components Missing Componenti di derivazione mancanti - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Mancano componenti che potrebbero impedire il completamento della derivazione della chiave. <br>Segui <a href='https://yuzu-emu.org/help/quickstart/'>la guida rapida di yuzu</a> per ottenere tutte le chiavi e i giochi.<br><br><small>(% 1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4482,39 +4616,39 @@ Questa operazione potrebbe durare fino a un minuto in base alle prestazioni del tuo sistema. - + Deriving Keys Derivazione Chiavi - + Select RomFS Dump Target Seleziona Target dell'Estrazione del RomFS - + Please select which RomFS you would like to dump. Seleziona quale RomFS vorresti estrarre. - + Are you sure you want to close yuzu? Sei sicuro di voler chiudere yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Sei sicuro di voler fermare l'emulazione? Tutti i progressi non salvati verranno perduti. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4526,38 +4660,38 @@ Desideri uscire comunque? GRenderWindow - + OpenGL not available! OpenGL non disponibile! - + yuzu has not been compiled with OpenGL support. yuzu non è stato compilato con il supporto OpenGL. - - + + Error while initializing OpenGL! Errore durante l'inizializzazione di OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. La tua GPU potrebbe non supportare OpenGL, o non hai installato l'ultima versione dei driver video. - + Error while initializing OpenGL 4.6! Errore durante l'inizializzazione di OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 La tua GPU potrebbe non supportare una o più estensioni OpenGL richieste. Assicurati di avere gli ultimi driver grafici.<br><br>Estensioni non supportate:<br> @@ -4915,190 +5049,205 @@ Iniziale. &Emulazione - + &View &Visualizza - + &Reset Window Size - - Reset Window Size to &720p - Ripristina le dimensioni della finestra a &720p - - - - Reset Window Size to 720p - Ripristina le dimensioni della finestra a 720p - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - Ripristina le dimensioni della finestra a &1080p - - - - Reset Window Size to 1080p - Ripristina le dimensioni della finestra a 1080p - - - + &Debugging Debugging - + + Reset Window Size to &720p + Ripristina le dimensioni della finestra a &720p + + + + Reset Window Size to 720p + Ripristina le dimensioni della finestra a 720p + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + Ripristina le dimensioni della finestra a &1080p + + + + Reset Window Size to 1080p + Ripristina le dimensioni della finestra a 1080p + + + &Tools Strumenti - + + &TAS + + + + &Help &Aiuto - + &Install Files to NAND... Installa i file su NAND... - + L&oad File... Carica File... - + Load &Folder... Carica Cartella... - + E&xit &Esci - - &Start - &Avvia - - - + &Pause &Pausa - + &Stop &Stop - + &Reinitialize keys... Ri-inizializzando le chiavi... - + &About yuzu Riguardo yuzu - + Single &Window Mode Modalità Finestra Singola - + Con&figure... Configura... - + Display D&ock Widget Headers Visualizza le Intestazioni del Dock dei Widget - + Show &Filter Bar Mostra Barra Filtri - + Show &Status Bar Mostra Barra Stato - + Show Status Bar Mostra Barra Stato - + F&ullscreen Schermo intero - + &Restart &Riavvia - + Load &Amiibo... Carica &Amiibo... - + &Report Compatibility &Segnala la Compatibilità - + Open &Mods Page Apri la pagina delle mods - + Open &Quickstart Guide Apri la guida rapida - + &FAQ Domande frequenti - + Open &yuzu Folder Apri la cartella di yuzu - + &Capture Screenshot Cattura schermo - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... Configura il gioco in uso.. + + + &Start + &Avvia + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5144,10 +5293,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE INIZIA/INTERROMPI + + + Charging + + QObject @@ -5178,142 +5332,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [non impostato] - - Hat %1 %2 Hat %1 %2 - - - - - - + + + + Axis %1%2 Asse %1%2 - Button %1 Pulsante %1 - - - + + + [unknown] [sconosciuto] - + + Left + + + + + Right + + + - Click 0 - Clicca 0 + Down + - - Click 1 - Clicca 1 + Up + - - Click 2 - Clicca 2 + Z + - - Click 3 - Clicca 3 + R + - - Click 4 - Clicca 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - Assi GC %1%2 - - - - GC Button %1 - Pulsanti GC %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Mavimento %1 - - - - %1Button %2 + + + + %1%2Axis %3 - - SDL Motion - Movimento SDL + + %1%2Axis %3,%4,%5 + - - %1Click %2 - %1Click %2 + + %1%2Motion %3 + - + + + %1%2Button %3 + + + + [unused] [inutilizzato] @@ -5354,7 +5588,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5367,7 +5601,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Doppi Joycon @@ -5380,7 +5614,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Joycon Sinistro @@ -5393,7 +5627,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Joycon Destro @@ -5421,7 +5655,7 @@ p, li { white-space: pre-wrap; } - + Handheld Portatile @@ -5542,7 +5776,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Controller GameCube @@ -5636,13 +5870,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Annulla diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts index aa8dbec5e..f641f99ed 100644 --- a/dist/languages/ja_JP.ts +++ b/dist/languages/ja_JP.ts @@ -656,7 +656,12 @@ p, li { white-space: pre-wrap; } 自動スタブの有効化** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. **yuzuを終了したときに自動的にリセットされます. @@ -936,67 +941,78 @@ p, li { white-space: pre-wrap; } 全般 - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x x - + Limit Speed Percent エミュレーション速度の制限 - + % % - + Multicore CPU Emulation マルチコアCPUエミュレーション - + Confirm exit while emulation is running エミュレーション停止時に確認 - + Prompt for user on game boot ゲーム起動時に確認を表示 - + Pause emulation when in background バックグラウンド時にエミュレーションを一時停止 - + Hide mouse on inactivity 非アクティブ時にマウスカーソルを隠す - + Reset All Settings すべての設定をリセット - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? @@ -1114,18 +1130,113 @@ p, li { white-space: pre-wrap; } ウィンドウに合わせる - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color 共通設定を使用 - + Set background color: 背景色の設定: - + Background Color: 背景色: @@ -1194,28 +1305,33 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default デフォルト - - - 2x (WILL BREAK THINGS) - 2x (破綻の可能性あり) - - 4x (WILL BREAK THINGS) - 4x (破綻の可能性あり) + 2x + - 8x (WILL BREAK THINGS) - 8x (破綻の可能性あり) + 4x + - 16x (WILL BREAK THINGS) - 16x (破綻の可能性あり) + 8x + + + + + 16x + @@ -1542,8 +1658,8 @@ p, li { white-space: pre-wrap; } - Other - その他 + Emulated Devices + @@ -1552,66 +1668,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - キーボードでアナログ入力をエミュレート - - - - Enable mouse panning - - - - - Mouse sensitivity - マウス感度 - - - - % - % - - - - - Advanced - 高度な設定 - - - - Touchscreen - タッチスクリーン - - - Mouse マウス - - Motion / Touch - モーション / タッチ + + Touchscreen + タッチスクリーン - - - Configure - 設定 + + Advanced + 高度な設定 - + Debug Controller デバッグ用コントローラ - + + + Configure + 設定 + + + + Other + その他 + + + + Emulate Analog with Keyboard Input + キーボードでアナログ入力をエミュレート + + + Requires restarting yuzu yuzuの再起動が必要 - + Enable XInput 8 player support (disables web applet) XInput 8プレイヤーサポートの有効化 (webアプレットの無効化) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + マウス感度 + + + + % + % + + + + Motion / Touch + モーション / タッチ + ConfigureInputPlayer @@ -1626,425 +1751,441 @@ p, li { white-space: pre-wrap; } 有効 - - - - Pro Controller - Proコントローラ - - - - - Dual Joycons - Joy-Con(L/R) - - - - - Left Joycon - Joy-Con(L) - - - - - Right Joycon - Joy-Con(R) - - - - - Handheld - 携帯モード - - - + Input Device 入力デバイス - - Any - すべての入力デバイス - - - - Keyboard/Mouse - キーボード / マウス - - - + Profile プロファイル - + Save 保存 - + New 新規 - + Delete 削除 - - + + Left Stick Lスティック - - - - - - + + + + + + Up - - - - - - - + + + + + + + Left - - - - - - - + + + + + + + Right - - - - - - + + + + + + Down - - - - + + + + Pressed 押下 - - - - + + + + Modifier 変更 - - + + Range 範囲 - - + + % % - - + + Deadzone: 0% デッドゾーン:0% - - + + Modifier Range: 0% 変更範囲:0% - + D-Pad 方向ボタン - - - + + + L L - - - + + + ZL ZL - - + + Minus - - + + Capture キャプチャー - - - + + + Plus - - + + Home HOME - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 モーション1 - + Motion 2 モーション2 - + Face Buttons ABXYボタン - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Rスティック - - - - + + + + Clear クリア - - - - + + + + [not set] [未設定] - - + + Toggle button - - + + Invert button + + + + + + Invert axis + 軸を反転 + + + + Set threshold しきい値を設定 - + Choose a value between 0% and 100% 0%から100%の間の値を選択してください - + Map Analog Stick アナログスティックをマップ - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. OKを押したあと, まずジョイスティックを水平方向に動かし, 次に垂直方向に動かしてください. 軸を反転させる場合は, 最初に垂直方向に動かし, 次に水平方向に動かしてください. - - Invert axis - 軸を反転 - - - - + + Deadzone: %1% デッドゾーン:%1% - - + + Modifier Range: %1% 変更範囲:%1% - + + + Pro Controller + Proコントローラ + + + + Dual Joycons + Joy-Con(L/R) + + + + Left Joycon + Joy-Con(L) + + + + Right Joycon + Joy-Con(R) + + + + Handheld + 携帯モード + + + GameCube Controller ゲームキューブコントローラ - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause - + Z Z - + Control Stick - + C-Stick Cスティック - + Shake! - + [waiting] [待機中] - + New Profile 新規プロファイル - + Enter a profile name: プロファイル名を入力: - - + + Create Input Profile 入力プロファイルを作成 - + The given profile name is not valid! プロファイル名が無効です! - + Failed to create the input profile "%1" 入力プロファイル "%1" の作成に失敗しました - + Delete Input Profile 入力プロファイルを削除 - + Failed to delete the input profile "%1" 入力プロファイル "%1" の削除に失敗しました - + Load Input Profile 入力プロファイルをロード - + Failed to load the input profile "%1" 入力プロファイル "%1" のロードに失敗しました - + Save Input Profile 入力プロファイルをセーブ - + Failed to save the input profile "%1" 入力プロファイル "%1" のセーブに失敗しました @@ -2070,85 +2211,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch モーション / タッチ設定 - - Mouse Motion - マウスモーション - - - - Sensitivity: - 感度: - - - + Touch タッチの設定 - + UDP Calibration: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure 設定 - - Use button mapping: - ボタンマッピングを使用: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDPの設定 - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. モーションとタッチの入力元として、Cemuhook互換のUDP入力ソースを使用します。 - + Server: サーバー: - + Port: ポート: - + Learn More 詳細情報 - - + + Test テスト - + Add Server サーバを追加 - + Remove Server サーバを削除 @@ -2158,145 +2289,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">詳細情報</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters ポート番号に無効な文字が含まれています - + Port has to be in range 0 and 65353 ポート番号は0から65353の間で設定してください - + IP address is not valid IPアドレスが無効です - + This UDP server already exists このUDPサーバはすでに存在してます - + Unable to add more than 8 servers 8個以上のサーバを追加することはできません - + Testing テスト中... - + Configuring 設定中... - + Test Successful テスト成功 - + Successfully received data from the server. サーバーからのデータ受信に成功しました。 - + Test Failed テスト失敗 - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. 有効なデータを受信できませんでした。<br>サーバーが正しくセットアップされ、アドレスとポートが正しいことを確認してください。 - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDPテストまたはキャリブレーション実行中です。<br>完了までお待ちください。 - - ConfigureMouseAdvanced - - - Configure Mouse - マウス設定 - - - - Mouse Buttons - マウスボタン - - - - Forward: - 進む: - - - - Back: - 戻る: - - - - Left: - 左: - - - - Middle: - 中央: - - - - Right: - 右: - - - - - Clear - 消去 - - - - Defaults - デフォルト - - - - [not set] - [未設定] - - - - Restore Default - デフォルトに戻す - - - - [press key] - [キーを入力] - - ConfigureNetwork @@ -3080,31 +3147,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - コントローラプロファイルを自動で切り替え - - - Loop script スクリプトを繰り返し実行 - + Pause execution during loads ロード中は実行を一時停止 - + Script Directory スクリプトディレクトリ - + Path パス - + ... ... @@ -3117,7 +3179,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< TAS 設定 - + Select TAS Load Directory... TAS ロードディレクトリを選択... @@ -3179,37 +3241,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile 新規プロファイル - + Enter the name for the new profile. プロファイル名を入力 - + Delete Profile プロファイルの削除 - + Delete profile %1? プロファイル%1を削除しますか? - + Rename Profile プロファイルのリネーム - + New name: 新しいプロファイル名: - + [press key] [キーを押す] @@ -3629,12 +3691,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 コントローラ P1 - + &Controller P1 コントローラ P1(&C) @@ -3642,90 +3704,95 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? yuzuを改善するための<a href='https://yuzu-emu.org/help/feature/telemetry/'>匿名データが収集されました</a>。<br/><br/>統計情報データを共有しますか? - + Telemetry テレメトリ - + Loading Web Applet... Webアプレットをロード中... - - + + Disable Web Applet Webアプレットの無効化 - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built ビルド中のシェーダー数 - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 現在のエミュレーション速度。値が100%より高いか低い場合、エミュレーション速度がSwitchより速いか遅いことを示します。 - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. ゲームが現在表示している1秒あたりのフレーム数。これはゲームごと、シーンごとに異なります。 - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Switchフレームをエミュレートするのにかかる時間で、フレームリミットやV-Syncは含まれません。フルスピードエミュレーションの場合、最大で16.67ミリ秒になります。 - + Invalid config detected 無効な設定を検出しました - + Handheld controller can't be used on docked mode. Pro controller will be selected. 携帯コントローラはドックモードで使用できません. Proコントローラが選択されます. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files 最近のファイルをクリア(&C) - - TAS Recording - TAS 記録中 + + &Continue + - - Overwrite file of player 1? - プレイヤー1のファイルを上書きしますか? + + &Pause + @@ -3776,659 +3843,726 @@ Drag points to change position, or double-click table cells to edit values.不明なエラーが発生しました。詳細はログを確認して下さい。 - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - 開始 - - - + Save Data データのセーブ - + Mod Data Modデータ - + Error Opening %1 Folder ”%1”フォルダを開けませんでした - - + + Folder does not exist! フォルダが存在しません! - + Error Opening Transferable Shader Cache シェーダキャッシュを開けませんでした - + Failed to create the shader cache directory for this title. このタイトル用のシェーダキャッシュディレクトリの作成に失敗しました - + Contents コンテンツ - + Update アップデート - + DLC DLC - + Remove Entry エントリ削除 - + Remove Installed Game %1? インストールされているゲーム%1を削除しますか? - - - - - - + + + + + + Successfully Removed 削除しました - + Successfully removed the installed base game. インストールされたゲームを正常に削除しました。 - - - + + + Error Removing %1 %1削除エラー - + The base game is not installed in the NAND and cannot be removed. ゲームはNANDにインストールされていないため、削除できません。 - + Successfully removed the installed update. インストールされたアップデートを正常に削除しました。 - + There is no update installed for this title. このタイトルのアップデートはインストールされていません。 - + There are no DLC installed for this title. このタイトルにはDLCがインストールされていません。 - + Successfully removed %1 installed DLC. %1にインストールされたDLCを正常に削除しました。 - + Delete OpenGL Transferable Shader Cache? 転送可能なOpenGLシェーダキャッシュを削除しますか? - + Delete Vulkan Transferable Shader Cache? 転送可能なVulkanシェーダキャッシュを削除しますか? - + Delete All Transferable Shader Caches? 転送可能なすべてのシェーダキャッシュを削除しますか? - + Remove Custom Game Configuration? カスタムゲーム設定を削除しますか? - + Remove File ファイル削除 - - + + Error Removing Transferable Shader Cache 転送可能なシェーダーキャッシュの削除エラー - - + + A shader cache for this title does not exist. このタイトル用のシェーダキャッシュは存在しません。 - + Successfully removed the transferable shader cache. 転送可能なシェーダーキャッシュが正常に削除されました。 - + Failed to remove the transferable shader cache. 転送可能なシェーダーキャッシュを削除できませんでした。 - - + + Error Removing Transferable Shader Caches 転送可能なシェーダキャッシュの削除エラー - + Successfully removed the transferable shader caches. 転送可能なシェーダキャッシュを正常に削除しました. - + Failed to remove the transferable shader cache directory. 転送可能なシェーダキャッシュディレクトリの削除に失敗しました. - - + + Error Removing Custom Configuration カスタム設定の削除エラー - + A custom configuration for this title does not exist. このタイトルのカスタム設定は存在しません。 - + Successfully removed the custom game configuration. カスタムゲーム設定を正常に削除しました。 - + Failed to remove the custom game configuration. カスタムゲーム設定の削除に失敗しました。 - - + + RomFS Extraction Failed! RomFSの解析に失敗しました! - + There was an error copying the RomFS files or the user cancelled the operation. RomFSファイルをコピー中にエラーが発生したか、ユーザー操作によりキャンセルされました。 - + Full フル - + Skeleton スケルトン - + Select RomFS Dump Mode RomFSダンプモードの選択 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. RomFSのダンプ方法を選択してください。<br>”完全”はすべてのファイルが新しいディレクトリにコピーされます。<br>”スケルトン”はディレクトリ構造を作成するだけです。 - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... RomFSを解析中... - - + + Cancel キャンセル - + RomFS Extraction Succeeded! RomFS解析成功! - + The operation completed successfully. 操作は成功しました。 - + Error Opening %1 ”%1”を開けませんでした - + Select Directory ディレクトリの選択 - + Properties プロパティ - + The game properties could not be loaded. ゲームプロパティをロード出来ませんでした。 - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch実行ファイル (%1);;すべてのファイル (*.*) - + Load File ファイルのロード - + Open Extracted ROM Directory 展開されているROMディレクトリを開く - + Invalid Directory Selected 無効なディレクトリが選択されました - + The directory you have selected does not contain a 'main' file. 選択されたディレクトリに”main”ファイルが見つかりませんでした。 - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) インストール可能なスイッチファイル (*.nca *.nsp *.xci);;任天堂コンテンツアーカイブ (*.nca);;任天堂サブミッションパッケージ (*.nsp);;NXカートリッジイメージ (*.xci) - + Install Files ファイルのインストール - + %n file(s) remaining - + Installing file "%1"... "%1"ファイルをインストールしています・・・ - - + + Install Results インストール結果 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed %n ファイルが新たにインストールされました - + %n file(s) were overwritten %n ファイルが上書きされました - + %n file(s) failed to install %n ファイルのインストールに失敗しました - + System Application システムアプリケーション - + System Archive システムアーカイブ - + System Application Update システムアプリケーションアップデート - + Firmware Package (Type A) ファームウェアパッケージ(Type A) - + Firmware Package (Type B) ファームウェアパッケージ(Type B) - + Game ゲーム - + Game Update ゲームアップデート - + Game DLC ゲームDLC - + Delta Title 差分タイトル - + Select NCA Install Type... NCAインストール種別を選択・・・ - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) インストールするNCAタイトル種別を選択して下さい: (ほとんどの場合、デフォルトの”ゲーム”で問題ありません。) - + Failed to Install インストール失敗 - + The title type you selected for the NCA is invalid. 選択されたNCAのタイトル種別が無効です。 - + File not found ファイルが存在しません - + File "%1" not found ファイル”%1”が存在しません - - - &Continue - - - - + OK OK - + Missing yuzu Account yuzuアカウントが存在しません - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. ゲームの互換性テストケースを送信するには、yuzuアカウントをリンクする必要があります。<br><br/>yuzuアカウントをリンクするには、エミュレーション > 設定 > Web から行います。 - + Error opening URL URLオープンエラー - + Unable to open the URL "%1". URL"%1"を開けません。 - + + TAS Recording + TAS 記録中 + + + + Overwrite file of player 1? + プレイヤー1のファイルを上書きしますか? + + + Amiibo File (%1);; All Files (*.*) amiiboファイル (%1);;すべてのファイル (*.*) - + Load Amiibo amiiboのロード - + Error opening Amiibo data file amiiboデータファイルを開けませんでした - + Unable to open Amiibo file "%1" for reading. amiiboデータファイル”%1”を読み込めませんでした。 - + Error reading Amiibo data file amiiboデータファイルを読み込み中にエラーが発生した - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. amiiboデータを完全には読み取ることができませんでした。%1バイトを読み込もうとしましたが、%2バイトしか読み取れませんでした。 - + Error loading Amiibo data amiiboデータ読み込み中にエラーが発生しました - + Unable to load Amiibo data. amiiboデータをロードできませんでした。 - + Capture Screenshot スクリーンショットのキャプチャ - + PNG Image (*.png) PNG画像 (*.png) - + TAS state: Running %1/%2 TAS 状態: 実行中 %1/%2 - + TAS state: Recording %1 TAS 状態: 記録中 %1 - + TAS state: Idle %1/%2 TAS 状態: アイドル %1/%2 - + TAS State: Invalid TAS 状態: 無効 + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) 構築中: %n シェーダー - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% 速度:%1% / %2% - + Speed: %1% 速度:%1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS ゲーム:%1 FPS - + Frame: %1 ms フレーム:%1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU HIGH - + GPU EXTREME GPU EXTREME - + GPU ERROR GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. ロードしようとしているゲームはプレイする前に、追加のファイルを必要とします。それはSwitchからダンプする必要があります。<br/><br/>これらのファイルのダンプの詳細については、次のWikiページを参照してください:<a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>スイッチコンソールからのシステムアーカイブと共有フォントをダンプする</a>。<br/><br/>ゲームリストに戻りますか?エミュレーションを続けると、クラッシュ、保存データの破損、またはその他のバグが発生する可能性があります。 - + yuzu was unable to locate a Switch system archive. %1 yuzuはSwitchのシステムアーカイブ "%1" を見つけられませんでした。 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzuはSwitchのシステムアーカイブ "%1" "%2" を見つけられませんでした。 - + System Archive Not Found システムアーカイブが見つかりません - + System Archive Missing システムアーカイブが見つかりません - + yuzu was unable to locate the Switch shared fonts. %1 yuzuはSwitchの共有フォント "%1" を見つけられませんでした。 - + Shared Fonts Not Found 共有フォントが存在しません - + Shared Font Missing 共有フォントが存在しません - + Fatal Error 致命的なエラー - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzuが致命的なエラーを検出しました。詳細については、ログを参照してください。ログへのアクセスの詳細については、次のページを参照してください。<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>ログファイルをアップロードする方法</a>。<br/><br/>ゲームリストに戻りますか?エミュレーションを続けると、クラッシュ、保存データの破損、またはその他のバグが発生する可能性があります。 - + Fatal Error encountered 致命的なエラー発生 - + Confirm Key Rederivation キーの再取得確認 - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4445,37 +4579,37 @@ This will delete your autogenerated key files and re-run the key derivation modu これにより、自動生成されたキーファイルが削除され、キー導出モジュールが再実行されます。 - + Missing fuses ヒューズがありません - + - Missing BOOT0 - BOOT0がありません - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Mainがありません - + - Missing PRODINFO - PRODINFOがありません - + Derivation Components Missing 派生コンポーネントがありません - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - コンポーネントが見つからず、キーの導出が完了しない可能性があります。<br>ゲームとキーを取得するために、<a href='https://yuzu-emu.org/help/quickstart/'>yuzuクイックスタートガイド</a>の手順に従って下さい。<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4484,39 +4618,39 @@ on your system's performance. 1分以上かかります。 - + Deriving Keys 派生キー - + Select RomFS Dump Target RomFSダンプターゲットの選択 - + Please select which RomFS you would like to dump. ダンプしたいRomFSを選択して下さい。 - + Are you sure you want to close yuzu? yuzuを終了してもよろしいですか? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. エミュレーションを停止してもよろしいですか?セーブされていない進行状況は失われます。 - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4528,38 +4662,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! OpenGLは使用できません! - + yuzu has not been compiled with OpenGL support. yuzuはOpenGLサポート付きでコンパイルされていません。 - - + + Error while initializing OpenGL! OpenGL初期化エラー - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPUがOpenGLをサポートしていないか、グラフィックスドライバーが最新ではありません。 - + Error while initializing OpenGL 4.6! OpenGL4.6初期化エラー! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPUがOpenGL4.6をサポートしていないか, グラフィックスドライバーが最新ではありません.<br><br>GL レンダラ:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPUが1つ以上の必要なOpenGL拡張機能をサポートしていない可能性があります. 最新のグラフィックドライバを使用していることを確認してください.<br><br>GL レンダラ:<br>%1<br><br>サポートされていない拡張機能:<br>%2 @@ -4916,190 +5050,205 @@ Screen. エミュレーション(&E) - + &View 表示(&V) - + &Reset Window Size ウインドウサイズをリセット(&R) - - Reset Window Size to &720p - ウインドウサイズを&720Pにリセット - - - - Reset Window Size to 720p - ウインドウサイズを720Pにリセット - - - - Reset Window Size to &900p - ウインドウサイズを&900Pにリセット - - - - Reset Window Size to 900p - ウインドウサイズを900Pにリセット - - - - Reset Window Size to &1080p - ウインドウサイズを&1080Pにリセット - - - - Reset Window Size to 1080p - ウインドウサイズを1080Pにリセット - - - + &Debugging デバッグ(&D) - + + Reset Window Size to &720p + ウインドウサイズを&720Pにリセット + + + + Reset Window Size to 720p + ウインドウサイズを720Pにリセット + + + + Reset Window Size to &900p + ウインドウサイズを&900Pにリセット + + + + Reset Window Size to 900p + ウインドウサイズを900Pにリセット + + + + Reset Window Size to &1080p + ウインドウサイズを&1080Pにリセット + + + + Reset Window Size to 1080p + ウインドウサイズを1080Pにリセット + + + &Tools ツール(&T) - + + &TAS + + + + &Help ヘルプ(&H) - + &Install Files to NAND... ファイルをNANDにインストール...(&I) - + L&oad File... ファイルをロード...(&L) - + Load &Folder... フォルダをロード...(&F) - + E&xit 終了(&E) - - &Start - 実行(&S) - - - + &Pause 中断(&P) - + &Stop 停止(&S) - + &Reinitialize keys... 鍵を再初期化...(&R) - + &About yuzu yuzuについて(&A) - + Single &Window Mode シングルウインドウモード(&W) - + Con&figure... 設定...(&F) - + Display D&ock Widget Headers ドックウィジェットヘッダの表示(&O) - + Show &Filter Bar フィルタバーを表示(&F) - + Show &Status Bar ステータスバーを表示(&S) - + Show Status Bar ステータスバーの表示 - + F&ullscreen 全画面表示(&F) - + &Restart 再実行(&R) - + Load &Amiibo... &Amiiboをロード... - + &Report Compatibility 互換性を報告(&R) - + Open &Mods Page &Modページを開く - + Open &Quickstart Guide クイックスタートガイドを開く(&Q) - + &FAQ &FAQ - + Open &yuzu Folder &yuzuフォルダを開く - + &Capture Screenshot スクリーンショットをキャプチャ(&C) - - Configure &TAS... - &TASを設定... + + &Configure TAS... + - + Configure C&urrent Game... 現在のゲームを設定...(&U) + + + &Start + 実行(&S) + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5141,10 +5290,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5175,142 +5329,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [未設定] - - Hat %1 %2 十字キー %1 %2 - - - - - - + + + + Axis %1%2 軸 %1%2 - Button %1 ボタン %1 - - - + + + [unknown] [不明] - + + Left + + + + + Right + + + - Click 0 - クリック0 + Down + - - Click 1 - クリック1 + Up + - - Click 2 - クリック2 + Z + - - Click 3 - クリック3 + R + - - Click 4 - クリック4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC Axis %1%2 - - - - GC Button %1 - GC ボタン %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - モーション %1 - - - - %1Button %2 - %1ボタン %2 - - - - SDL Motion - SDLモーション - - - - %1Click %2 + + + + %1%2Axis %3 - + + %1%2Axis %3,%4,%5 + + + + + %1%2Motion %3 + + + + + + %1%2Button %3 + + + + [unused] [未使用] @@ -5351,7 +5585,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Proコントローラ @@ -5364,7 +5598,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Joy-Con(L/R) @@ -5377,7 +5611,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Joy-Con(L) @@ -5390,7 +5624,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Joy-Con(R) @@ -5418,7 +5652,7 @@ p, li { white-space: pre-wrap; } - + Handheld 携帯モード @@ -5539,7 +5773,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller ゲームキューブコントローラ @@ -5628,13 +5862,13 @@ p, li { white-space: pre-wrap; } - - + + OK OK - + Cancel キャンセル diff --git a/dist/languages/ko_KR.ts b/dist/languages/ko_KR.ts index 10bfd647d..ddd450583 100644 --- a/dist/languages/ko_KR.ts +++ b/dist/languages/ko_KR.ts @@ -658,7 +658,12 @@ p, li { white-space: pre-wrap; } 자동 스텁 활성화** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. **Yuzu가 종료되면 자동으로 재설정됩니다. @@ -938,67 +943,78 @@ p, li { white-space: pre-wrap; } 일반 - - Framerate Cap - 프레임 속도 제한 + + + Use global framerate cap + - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. 사용하려면 FPS Limiter Toggle 핫키를 사용해야 합니다. - + + Framerate Cap + 프레임 속도 제한 + + + x x - + Limit Speed Percent 속도 퍼센트 제한 - + % % - + Multicore CPU Emulation 멀티 코어 CPU 에뮬레이션 - + Confirm exit while emulation is running 에뮬레이터가 작동 중일 때 종료 시 확인 - + Prompt for user on game boot 게임 부팅시 유저 선택 화면 표시 - + Pause emulation when in background 백그라운드에 있을 시 에뮬레이션 일시중지 - + Hide mouse on inactivity 비활성 상태일 때 마우스 숨기기 - + Reset All Settings 모든 설정 초기화 - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? 모든 환경 설정과 게임별 맞춤 설정이 초기화됩니다. 게임 디렉토리나 프로필, 또는 입력 프로필은 삭제되지 않습니다. 진행하시겠습니까? @@ -1116,18 +1132,113 @@ p, li { white-space: pre-wrap; } 창에 맞게 늘림 - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color 전역 배경색 사용 - + Set background color: 배경색 설정: - + Background Color: 배경색: @@ -1196,28 +1307,33 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default 기본값 - - - 2x (WILL BREAK THINGS) - 2x (실행에 문제가 있을 수 있습니다) - - 4x (WILL BREAK THINGS) - 4x (실행에 문제가 있을 수 있습니다) + 2x + - 8x (WILL BREAK THINGS) - 8x (실행에 문제가 있을 수 있습니다) + 4x + - 16x (WILL BREAK THINGS) - 16x (실행에 문제가 있을 수 있습니다) + 8x + + + + + 16x + @@ -1544,8 +1660,8 @@ p, li { white-space: pre-wrap; } - Other - 기타 + Emulated Devices + @@ -1554,66 +1670,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - 키보드 입력으로 아날로그 입력 에뮬레이션 - - - - Enable mouse panning - 마우스 패닝 활성화 - - - - Mouse sensitivity - 마우스 감도 - - - - % - % - - - - - Advanced - 고급 - - - - Touchscreen - 터치 스크린 - - - Mouse 마우스 - - Motion / Touch - 모션 컨트롤/ 터치 + + Touchscreen + 터치 스크린 - - - Configure - 설정 + + Advanced + 고급 - + Debug Controller 디버그 컨트롤러 - + + + Configure + 설정 + + + + Other + 기타 + + + + Emulate Analog with Keyboard Input + 키보드 입력으로 아날로그 입력 에뮬레이션 + + + Requires restarting yuzu yuzu를 다시 시작해야 합니다. - + Enable XInput 8 player support (disables web applet) XInput 8 플레이어 지원 활성화(웹 애플릿 비활성화) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + 마우스 패닝 활성화 + + + + Mouse sensitivity + 마우스 감도 + + + + % + % + + + + Motion / Touch + 모션 컨트롤/ 터치 + ConfigureInputPlayer @@ -1628,425 +1753,441 @@ p, li { white-space: pre-wrap; } 컨트롤러 연결 - - - - Pro Controller - 프로 컨트롤러 - - - - - Dual Joycons - 듀얼 조이콘 - - - - - Left Joycon - 왼쪽 조이콘 - - - - - Right Joycon - 오른쪽 조이콘 - - - - - Handheld - 휴대 - - - + Input Device 입력 장치 - - Any - 모든 장치 - - - - Keyboard/Mouse - 키보드/마우스 - - - + Profile 프로필 - + Save 저장 - + New 새로 생성 - + Delete 삭제 - - + + Left Stick L 스틱 - - - - - - + + + + + + Up 위쪽 - - - - - - - + + + + + + + Left 왼쪽 - - - - - - - + + + + + + + Right 오른쪽 - - - - - - + + + + + + Down 아래쪽 - - - - + + + + Pressed 누르기 - - - - + + + + Modifier 수정자 - - + + Range 범위 - - + + % % - - + + Deadzone: 0% 데드존: 0% - - + + Modifier Range: 0% 수정자 범위: 0% - + D-Pad D-패드 - - - + + + L L - - - + + + ZL ZL - - + + Minus - - - + + Capture 캡쳐 - - - + + + Plus + - - + + Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 모션 1 - + Motion 2 모션 2 - + Face Buttons A/B/X/Y버튼 - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick R 스틱 - - - - + + + + Clear 초기화 - - - - + + + + [not set] [설정 안 됨] - - + + Toggle button 토글 버튼 - - + + Invert button + + + + + + Invert axis + 축 뒤집기 + + + + Set threshold 임계값 설정 - + Choose a value between 0% and 100% 0%에서 100% 안의 값을 고르세요 - + Map Analog Stick 아날로그 스틱 맵핑 - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. OK 버튼을 누른 후에 먼저 조이스틱을 수평으로 움직이고, 그 다음 수직으로 움직이세요. 축을 뒤집으려면 수직으로 먼저 움직인 뒤에 수평으로 움직이세요. - - Invert axis - 축 뒤집기 - - - - + + Deadzone: %1% 데드존: %1% - - + + Modifier Range: %1% 수정자 범위: %1% - + + + Pro Controller + 프로 컨트롤러 + + + + Dual Joycons + 듀얼 조이콘 + + + + Left Joycon + 왼쪽 조이콘 + + + + Right Joycon + 오른쪽 조이콘 + + + + Handheld + 휴대 + + + GameCube Controller GameCube 컨트롤러 - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause 시작 / 일시 정지 - + Z Z - + Control Stick 컨트롤 스틱 - + C-Stick C-Stick - + Shake! 흔드세요! - + [waiting] [대기중] - + New Profile 새 프로필 - + Enter a profile name: 프로필 이름을 입력하세요: - - + + Create Input Profile 입력 프로필 생성 - + The given profile name is not valid! 해당 프로필 이름은 사용할 수 없습니다! - + Failed to create the input profile "%1" "%1" 입력 프로필 생성 실패 - + Delete Input Profile 입력 프로필 삭제 - + Failed to delete the input profile "%1" "%1" 입력 프로필 삭제 실패 - + Load Input Profile 입력 프로필 불러오기 - + Failed to load the input profile "%1" "%1" 입력 프로필 불러오기 실패 - + Save Input Profile 입력 프로필 저장 - + Failed to save the input profile "%1" "%1" 입력 프로필 저장 실패 @@ -2072,85 +2213,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch 모션 설정 / 터치 - - Mouse Motion - 마우스 모션 - - - - Sensitivity: - 감도: - - - + Touch 터치 - + UDP Calibration: UDP 조정: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure 설정 - - Use button mapping: - 버튼 매핑 사용: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP 설정 - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Cemuhook 호환이 가능한 모든 UDP 인풋 장치를 모션 컨트롤과 터치 입력용으로 사용할 수 있습니다. - + Server: 서버: - + Port: 포트: - + Learn More 자세히 알아보기 - - + + Test 테스트 - + Add Server 서버 추가 - + Remove Server 원격 서버 @@ -2160,145 +2291,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">자세히 알아보기</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters 포트 번호에 유효하지 않은 글자가 있습니다. - + Port has to be in range 0 and 65353 포트 번호는 0부터 65353까지이어야 합니다. - + IP address is not valid IP 주소가 유효하지 않습니다. - + This UDP server already exists 해당 UDP 서버는 이미 존재합니다. - + Unable to add more than 8 servers 8개보다 많은 서버를 추가하실 수는 없습니다. - + Testing 테스트 중 - + Configuring 설정 중 - + Test Successful 테스트 성공 - + Successfully received data from the server. 서버에서 성공적으로 데이터를 받았습니다. - + Test Failed 테스트 실패 - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. 서버에서 유효한 데이터를 수신할 수 없습니다.<br>서버가 올바르게 설정되어 있고 주소와 포트가 올바른지 확인하십시오. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP 테스트와 교정 설정이 진행 중입니다.<br>끝날 때까지 기다려주세요. - - ConfigureMouseAdvanced - - - Configure Mouse - 마우스 설정 - - - - Mouse Buttons - 마우스 버튼 - - - - Forward: - 앞: - - - - Back: - 뒤: - - - - Left: - 왼쪽: - - - - Middle: - 중앙: - - - - Right: - 오른쪽: - - - - - Clear - 비우기 - - - - Defaults - 기본값 - - - - [not set] - [설정 안됨] - - - - Restore Default - 초기화 - - - - [press key] - [키 입력] - - ConfigureNetwork @@ -2402,7 +2469,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Adv. Graphics - + 고급 그래픽 @@ -2586,12 +2653,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Error resizing user image - + 사용자 이미지 크기 조정 오류 Unable to resize image - + 이미지 크기를 조정할 수 없습니다 @@ -3058,12 +3125,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - + <html><head/><body><p>TAS-nx 스크립트와 동일한 형식의 스크립트에서 컨트롤러 입력을 읽습니다.<br/>더 자세한 설명은 yuzu 웹사이트에 있는 <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a>를 참조하세요.</p></body></html> To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). - + 재생/녹화를 제어하는 ​​단축키를 확인하려면 단축키 설정(설정 -> 일반 -> 단축키)을 참조하십시오. @@ -3082,31 +3149,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - 자동 컨트롤러 프로필 교체 - - - Loop script 반복 스크립트 - + Pause execution during loads 로드 중 실행 일시 중지 - + Script Directory 스크립트 주소 - + Path 주소 - + ... ... @@ -3119,7 +3181,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< TAS 설정 - + Select TAS Load Directory... TAS 로드 디렉토리 선택... @@ -3181,37 +3243,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile 새 프로필 - + Enter the name for the new profile. 새 프로필의 이름을 적으시오. - + Delete Profile 프로필 삭제하기 - + Delete profile %1? %1 프로필을 삭제하시겠습니까? - + Rename Profile 프로필 이름 재설정 - + New name: 새 이름: - + [press key] [키 입력] @@ -3631,12 +3693,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 컨트롤러 P1 - + &Controller P1 컨트롤러 P1(&C) @@ -3644,90 +3706,95 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? yuzu를 개선하기 위해 <a href='https://yuzu-emu.org/help/feature/telemetry/'>익명 데이터가 수집됩니다.</a> <br/><br/>사용 데이터를 공유하시겠습니까? - + Telemetry 원격 측정 - + Loading Web Applet... 웹 애플릿을 로드하는 중... - - + + Disable Web Applet 웹 애플릿 비활성화 - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? 웹 애플릿을 비활성화할 시 앞으로 에뮬레이트할 때 해당 화면이 더 이상 뜨지 않습니다. 이는 알 수 없는 문제를 일으킬 수 있으며 Super Mario 3D All-Stars에만 사용해야 합니다. 웹 애플릿을 정말로 비활성화 하시겠습니까? - + The amount of shaders currently being built 현재 생성중인 셰이더의 양 - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 현재 에뮬레이션 속도. 100%보다 높거나 낮은 값은 에뮬레이션이 Switch보다 빠르거나 느린 것을 나타냅니다. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 게임이 현재 표시하고 있는 초당 프레임 수입니다. 이것은 게임마다 다르고 장면마다 다릅니다. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 프레임 제한이나 수직 동기화를 계산하지 않고 Switch 프레임을 에뮬레이션 하는 데 걸린 시간. 최대 속도로 에뮬레이트 중일 때에는 대부분 16.67 ms 근처입니다. - + Invalid config detected 유효하지 않은 설정 감지 - + Handheld controller can't be used on docked mode. Pro controller will be selected. 휴대 모드용 컨트롤러는 거치 모드에서 사용할 수 없습니다. 프로 컨트롤러로 대신 선택됩니다. - + DOCK 거치 모드 - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files Clear Recent Files(&C) - - TAS Recording - TAS 레코딩 + + &Continue + 계속(&C) - - Overwrite file of player 1? - 플레이어 1의 파일을 덮어쓰시겠습니까? + + &Pause + @@ -3778,660 +3845,727 @@ Drag points to change position, or double-click table cells to edit values.알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참고하십시오. - + (64-bit) (64비트) - + (32-bit) (32비트) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - 시작 - - - + Save Data 세이브 데이터 - + Mod Data 모드 데이터 - + Error Opening %1 Folder %1 폴더 열기 오류 - - + + Folder does not exist! 폴더가 존재하지 않습니다! - + Error Opening Transferable Shader Cache 전달 가능한 셰이더 캐시 열기 오류 - + Failed to create the shader cache directory for this title. 이 타이틀에 대한 셰이더 캐시 디렉토리를 생성하지 못했습니다. - + Contents 컨텐츠 - + Update 업데이트 - + DLC DLC - + Remove Entry 항목 제거 - + Remove Installed Game %1? 설치된 게임을 삭제 %1? - - - - - - + + + + + + Successfully Removed 삭제 완료 - + Successfully removed the installed base game. 설치된 기본 게임을 성공적으로 제거했습니다. - - - + + + Error Removing %1 삭제 중 오류 발생 %1 - + The base game is not installed in the NAND and cannot be removed. 기본 게임은 NAND에 설치되어 있지 않으며 제거 할 수 없습니다. - + Successfully removed the installed update. 설치된 업데이트를 성공적으로 제거했습니다. - + There is no update installed for this title. 이 타이틀에 대해 설치된 업데이트가 없습니다. - + There are no DLC installed for this title. 이 타이틀에 설치된 DLC가 없습니다. - + Successfully removed %1 installed DLC. 설치된 %1 DLC를 성공적으로 제거했습니다. - + Delete OpenGL Transferable Shader Cache? OpenGL 전송 가능한 셰이더 캐시를 삭제하시겠습니까? - + Delete Vulkan Transferable Shader Cache? Vulkan 전송 가능한 셰이더 캐시를 삭제하시겠습니까? - + Delete All Transferable Shader Caches? 모든 전송 가능한 셰이더 캐시를 삭제하시겠습니까? - + Remove Custom Game Configuration? 사용자 지정 게임 구성을 제거 하시겠습니까? - + Remove File 파일 제거 - - + + Error Removing Transferable Shader Cache 전달 가능한 셰이더 캐시 제거 오류 - - + + A shader cache for this title does not exist. 이 타이틀에 대한 셰이더 캐시가 존재하지 않습니다. - + Successfully removed the transferable shader cache. 전달 가능한 셰이더 캐시를 성공적으로 제거했습니다. - + Failed to remove the transferable shader cache. 전송 가능한 셰이더 캐시를 제거하지 못했습니다. - - + + Error Removing Transferable Shader Caches 전송 가능한 셰이더 캐시 제거 오류 - + Successfully removed the transferable shader caches. 전송 가능한 셰이더 캐시를 성공적으로 제거했습니다. - + Failed to remove the transferable shader cache directory. 전송 가능한 셰이더 캐시 디렉토리를 제거하지 못했습니다. - - + + Error Removing Custom Configuration 사용자 지정 구성 제거 오류 - + A custom configuration for this title does not exist. 이 타이틀에 대한 사용자 지정 구성이 존재하지 않습니다. - + Successfully removed the custom game configuration. 사용자 지정 게임 구성을 성공적으로 제거했습니다. - + Failed to remove the custom game configuration. 사용자 지정 게임 구성을 제거하지 못했습니다. - - + + RomFS Extraction Failed! RomFS 추출 실패! - + There was an error copying the RomFS files or the user cancelled the operation. RomFS 파일을 복사하는 중에 오류가 발생했거나 사용자가 작업을 취소했습니다. - + Full 전체 - + Skeleton 뼈대 - + Select RomFS Dump Mode RomFS 덤프 모드 선택 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. RomFS 덤프 방법을 선택하십시오.<br>전체는 모든 파일을 새 디렉토리에 복사하고<br>뼈대는 디렉토리 구조 만 생성합니다. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root %1에 RomFS를 추출하기에 충분한 여유 공간이 없습니다. 공간을 확보하거나 에뮬레이견 > 설정 > 시스템 > 파일시스템 > 덤프 경로에서 다른 덤프 디렉토리를 선택하십시오. - + Extracting RomFS... RomFS 추출 중... - - + + Cancel 취소 - + RomFS Extraction Succeeded! RomFS 추출이 성공했습니다! - + The operation completed successfully. 작업이 성공적으로 완료되었습니다. - + Error Opening %1 %1 열기 오류 - + Select Directory 경로 선택 - + Properties 속성 - + The game properties could not be loaded. 게임 속성을 로드 할 수 없습니다. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch 실행파일 (%1);;모든 파일 (*.*) - + Load File 파일 로드 - + Open Extracted ROM Directory 추출된 ROM 디렉토리 열기 - + Invalid Directory Selected 잘못된 디렉토리 선택 - + The directory you have selected does not contain a 'main' file. 선택한 디렉토리에 'main'파일이 없습니다. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) 설치 가능한 Switch 파일 (*.nca *.nsp *.xci);;Nintendo 컨텐츠 아카이브 (*.nca);;Nintendo 서브미션 패키지 (*.nsp);;NX 카트리지 이미지 (*.xci) - + Install Files 파일 설치 - + %n file(s) remaining %n개의 파일이 남음 - + Installing file "%1"... 파일 "%1" 설치 중... - - + + Install Results 설치 결과 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. 충돌을 피하기 위해, 낸드에 베이스 게임을 설치하는 것을 권장하지 않습니다. 이 기능은 업데이트나 DLC를 설치할 때에만 사용해주세요. - + %n file(s) were newly installed %n개의 파일이 새로 설치되었습니다. - + %n file(s) were overwritten %%n개의 파일을 덮어썼습니다. - + %n file(s) failed to install %n개의 파일을 설치하지 못했습니다. - + System Application 시스템 애플리케이션 - + System Archive 시스템 아카이브 - + System Application Update 시스템 애플리케이션 업데이트 - + Firmware Package (Type A) 펌웨어 패키지 (A타입) - + Firmware Package (Type B) 펌웨어 패키지 (B타입) - + Game 게임 - + Game Update 게임 업데이트 - + Game DLC 게임 DLC - + Delta Title 델타 타이틀 - + Select NCA Install Type... NCA 설치 유형 선택... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) 이 NCA를 설치할 타이틀 유형을 선택하세요: (대부분의 경우 기본값인 '게임'이 괜찮습니다.) - + Failed to Install 설치 실패 - + The title type you selected for the NCA is invalid. NCA 타이틀 유형이 유효하지 않습니다. - + File not found 파일을 찾을 수 없음 - + File "%1" not found 파일 "%1"을 찾을 수 없습니다 - - - &Continue - 계속(&C) - - - + OK OK - + Missing yuzu Account yuzu 계정 누락 - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. 게임 호환성 테스트 결과를 제출하려면 yuzu 계정을 연결해야합니다.<br><br/>yuzu 계정을 연결하려면 에뮬레이션 &gt; 설정 &gt; 웹으로 가세요. - + Error opening URL URL 열기 오류 - + Unable to open the URL "%1". URL "%1"을 열 수 없습니다. - + + TAS Recording + TAS 레코딩 + + + + Overwrite file of player 1? + 플레이어 1의 파일을 덮어쓰시겠습니까? + + + Amiibo File (%1);; All Files (*.*) Amiibo 파일 (%1);; 모든 파일 (*.*) - + Load Amiibo Amiibo 로드 - + Error opening Amiibo data file Amiibo 데이터 파일 열기 오류 - + Unable to open Amiibo file "%1" for reading. Amiibo 파일 "%1"을(를) 읽을 수 없습니다. - + Error reading Amiibo data file Amiibo 데이터 파일 읽기 오류 - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Amiibo 데이터를 완전히 읽을 수 없습니다. %1 바이트를 읽으려고 했지만 %2 바이트만 읽을 수 있었습니다. - + Error loading Amiibo data Amiibo 데이터 로드 오류 - + Unable to load Amiibo data. Amiibo 데이터를 로드할 수 없습니다. - + Capture Screenshot 스크린샷 캡처 - + PNG Image (*.png) PNG 이미지 (*.png) - + TAS state: Running %1/%2 TAS 상태: %1/%2 실행 중 - + TAS state: Recording %1 TAS 상태: 레코딩 %1 - + TAS state: Idle %1/%2 TAS 상태: 유휴 %1/%2 - + TAS State: Invalid TAS 상태: 유효하지 않음 + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) 빌드중: %n개 셰이더 - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% 속도: %1% / %2% - + Speed: %1% 속도: %1% - + Game: %1 FPS (Unlocked) 게임: %1 FPS (제한없음) - + Game: %1 FPS 게임: %1 FPS - + Frame: %1 ms 프레임: %1 ms - + GPU NORMAL GPU 보통 - + GPU HIGH GPU 높음 - + GPU EXTREME GPU 굉장함 - + GPU ERROR GPU 오류 - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. 해당 게임은 플레이하기 전에 Switch 기기에서 추가 파일을 덤프해야합니다.<br/><br/>이러한 파일 덤프에 대한 자세한 내용은 다음 위키 페이지를 참조하십시오: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Switch 콘솔에서 시스템 아카이브 및 공유 글꼴 덤프</a>.<br/><br/>게임 목록으로 돌아가시겠습니까? 이를 무시하고 에뮬레이션을 계속하면 충돌, 저장 데이터 손상 또는 기타 버그가 발생할 수 있습니다. - + yuzu was unable to locate a Switch system archive. %1 yuzu가 Switch 시스템 아카이브를 찾을 수 없습니다. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu가 Switch 시스템 아카이브를 찾을 수 없습니다: %1. %2 - + System Archive Not Found 시스템 아카이브를 찾을 수 없음 - + System Archive Missing 시스템 아카이브 누락 - + yuzu was unable to locate the Switch shared fonts. %1 yuzu가 Switch 공유 글꼴을 찾을 수 없습니다. %1 - + Shared Fonts Not Found 공유 글꼴을 찾을 수 없음 - + Shared Font Missing 공유 글꼴 누락 - + Fatal Error 치명적인 오류 - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. 치명적인 오류가 발생했습니다. 자세한 내용은 로그를 확인하십시오. 로그 액세스에 대한 자세한 내용은 다음 페이지를 참조하십시오: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>로그 파일을 업로드하는 방법</a>.<br/><br/>게임 목록으로 돌아가시겠습니까? 이를 무시하고 에뮬레이션을 계속하면 충돌, 저장 데이터 손상 또는 기타 버그가 발생할 수 있습니다. - + Fatal Error encountered 치명적인 오류 발생 - + Confirm Key Rederivation 키 재생성 확인 - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4448,37 +4582,37 @@ This will delete your autogenerated key files and re-run the key derivation modu 자동 생성되었던 키 파일들이 삭제되고 키 생성 모듈이 다시 실행됩니다. - + Missing fuses 퓨즈 누락 - + - Missing BOOT0 - BOOT0 누락 - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Main 누락 - + - Missing PRODINFO - PRODINFO 누락 - + Derivation Components Missing 파생 구성 요소 누락 - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - 구성요소가 누락되어 키 파생이 완료되지 못할 수 있습니다. <br>모든 키와 게임을 얻으려면 <a href='https://yuzu-emu.org/help/quickstart/'>yuzu 빠른 시작 가이드</a>를 참조하세요<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4487,39 +4621,39 @@ on your system's performance. 소요될 수 있습니다. - + Deriving Keys 파생 키 - + Select RomFS Dump Target RomFS 덤프 대상 선택 - + Please select which RomFS you would like to dump. 덤프할 RomFS를 선택하십시오. - + Are you sure you want to close yuzu? yuzu를 닫으시겠습니까? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. 에뮬레이션을 중지하시겠습니까? 모든 저장되지 않은 진행 상황은 사라집니다. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4531,38 +4665,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! OpenGL을 사용할 수 없습니다! - + yuzu has not been compiled with OpenGL support. yuzu는 OpenGL 지원으로 컴파일되지 않았습니다. - - + + Error while initializing OpenGL! OpenGL을 초기화하는 동안 오류가 발생했습니다! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 사용하시는 GPU가 OpenGL을 지원하지 않거나, 최신 그래픽 드라이버가 설치되어 있지 않습니다. - + Error while initializing OpenGL 4.6! OpenGL 4.6 초기화 중 오류 발생! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 사용하시는 GPU가 OpenGL 4.6을 지원하지 않거나 최신 그래픽 드라이버가 설치되어 있지 않습니다. <br><br>GL 렌더링 장치:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 사용하시는 GPU가 1개 이상의 OpenGL 확장 기능을 지원하지 않습니다. 최신 그래픽 드라이버가 설치되어 있는지 확인하세요. <br><br>GL 렌더링 장치:<br>%1<br><br>지원하지 않는 확장 기능:<br>%2 @@ -4924,190 +5058,205 @@ Screen. 에뮬레이션(&E) - + &View 보기(&V) - + &Reset Window Size 창 크기 초기화 (&R) - - Reset Window Size to &720p - 창 크기를 720p로 맞추기(&7) - - - - Reset Window Size to 720p - 창 크기를 720p로 맞추기 - - - - Reset Window Size to &900p - 창 크기를 900p로 맞추기(&9) - - - - Reset Window Size to 900p - 창 크기를 900p로 맞추기 - - - - Reset Window Size to &1080p - 창 크기를 1080p로 맞추기(&1) - - - - Reset Window Size to 1080p - 창 크기를 1080p로 맞추기 - - - + &Debugging 디버깅(&D) - + + Reset Window Size to &720p + 창 크기를 720p로 맞추기(&7) + + + + Reset Window Size to 720p + 창 크기를 720p로 맞추기 + + + + Reset Window Size to &900p + 창 크기를 900p로 맞추기(&9) + + + + Reset Window Size to 900p + 창 크기를 900p로 맞추기 + + + + Reset Window Size to &1080p + 창 크기를 1080p로 맞추기(&1) + + + + Reset Window Size to 1080p + 창 크기를 1080p로 맞추기 + + + &Tools 도구(&T) - + + &TAS + + + + &Help 도움말(&H) - + &Install Files to NAND... 낸드에 파일 설치(&I) - + L&oad File... 파일 불러오기...(&L) - + Load &Folder... 폴더 불러오기...(&F) - + E&xit 종료(&X) - - &Start - 시작(&S) - - - + &Pause 일시중지(&P) - + &Stop 정지(&S) - + &Reinitialize keys... &키 재설정...(&R) - + &About yuzu yuzu 정보(&A) - + Single &Window Mode 싱글 창 모드(&W) - + Con&figure... 설정(&f) - + Display D&ock Widget Headers 독 위젯 헤더 표시(&o) - + Show &Filter Bar 필터링 바 표시(&F) - + Show &Status Bar 상태 표시줄 보이기(&S) - + Show Status Bar 상태 표시줄 보이기 - + F&ullscreen 전체 화면(&u) - + &Restart 재시작(&R) - + Load &Amiibo... Amiibo 불러오기...(&A) - + &Report Compatibility 호환성 보고(&R) - + Open &Mods Page 게임 모드 페이지 열기(&M) - + Open &Quickstart Guide 빠른 시작 가이드 열기(&Q) - + &FAQ FAQ(&F) - + Open &yuzu Folder yuzu 폴더 열기(&y) - + &Capture Screenshot 스크린샷 찍기(&C) - - Configure &TAS... - TAS 설정...(&T) + + &Configure TAS... + - + Configure C&urrent Game... 실행중인 게임 맞춤 설정...(&u) + + + &Start + 시작(&S) + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5153,10 +5302,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE 시작/일시 정지 + + + Charging + + QObject @@ -5187,142 +5341,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [설정 안 됨] - - Hat %1 %2 방향키 %1 %2 - - - - - - + + + + Axis %1%2 축 %1%2 - Button %1 버튼 %1 - - - + + + [unknown] [알 수 없음] - + + Left + + + + + Right + + + - Click 0 - 클릭 0 + Down + - - Click 1 - 클릭 1 + Up + - - Click 2 - 클릭 2 + Z + - - Click 3 - 클릭 3 + R + - - Click 4 - 클릭 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC 축 %1%2 + + [invalid] + - - GC Button %1 - GC 버튼 %1 + + + %1%2Hat %3 + - - TAS Axis %1 - TAS Axis %1 + + + + %1%2Axis %3 + - - TAS Btn %1 - TAS 버튼 %1 + + %1%2Axis %3,%4,%5 + - - Motion %1 - 모션 %1 + + %1%2Motion %3 + - - %1Button %2 - %1버튼 %2 + + + %1%2Button %3 + - - SDL Motion - SDL 모션 - - - - %1Click %2 - %1클릭 %2 - - - + [unused] [미사용] @@ -5363,7 +5597,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller 프로 컨트롤러 @@ -5376,7 +5610,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons 듀얼 조이콘 @@ -5389,7 +5623,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon 왼쪽 조이콘 @@ -5402,7 +5636,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon 오른쪽 조이콘 @@ -5430,7 +5664,7 @@ p, li { white-space: pre-wrap; } - + Handheld 휴대 모드용 @@ -5551,7 +5785,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller GameCube 컨트롤러 @@ -5645,13 +5879,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel 취소 diff --git a/dist/languages/nb.ts b/dist/languages/nb.ts index 22c002326..039816080 100644 --- a/dist/languages/nb.ts +++ b/dist/languages/nb.ts @@ -633,7 +633,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -913,67 +918,78 @@ p, li { white-space: pre-wrap; } Generelt - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Begrens Farts-Prosent - + % % - + Multicore CPU Emulation - + Confirm exit while emulation is running Bekreft lukking mens emuleringen kjører - + Prompt for user on game boot - + Pause emulation when in background Pause emulasjon i bakgrunnen - + Hide mouse on inactivity Gjem mus under inaktivitet - + Reset All Settings - + yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? @@ -1091,18 +1107,113 @@ p, li { white-space: pre-wrap; } Strekk til Vindu - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color - + Set background color: Velg bakgrunnsfarge: - + Background Color: Bakgrunnsfarge: @@ -1171,27 +1282,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Standard - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1519,8 +1635,8 @@ p, li { white-space: pre-wrap; } - Other - Andre + Emulated Devices + @@ -1529,66 +1645,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - - - - - Enable mouse panning - - - - - Mouse sensitivity - - - - - % - - - - - - Advanced - Avansert - - - - Touchscreen - Touch-skjerm - - - Mouse Mus - - Motion / Touch - Bevegelse / Touch + + Touchscreen + Touch-skjerm - - - Configure - Konfigurer + + Advanced + Avansert - + Debug Controller Feilsøkingskontroller - + + + Configure + Konfigurer + + + + Other + Andre + + + + Emulate Analog with Keyboard Input + + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + + + + + % + + + + + Motion / Touch + Bevegelse / Touch + ConfigureInputPlayer @@ -1603,424 +1728,440 @@ p, li { white-space: pre-wrap; } Tilkoble Kontroller - - - - Pro Controller - Pro-Kontroller - - - - - Dual Joycons - Doble Joycons - - - - - Left Joycon - Venstre Joycon - - - - - Right Joycon - Høyre Joycon - - - - - Handheld - Håndholdt - - - + Input Device - - Any - - - - - Keyboard/Mouse - Tastatur/Mus - - - + Profile Profil - + Save Lagre - + New Ny - + Delete Slett - - + + Left Stick Venstre Pinne - - - - - - + + + + + + Up Opp - - - - - - - + + + + + + + Left Venstre - - - - - - - + + + + + + + Right Høyre - - - - - - + + + + + + Down Ned - - - - + + + + Pressed Trykket - - - - + + + + Modifier Modifikator - - + + Range Område - - + + % % - - + + Deadzone: 0% Dødsone: 0% - - + + Modifier Range: 0% Modifikatorområde: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture - - - + + + Plus Pluss - - + + Home Hjem - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 - + Motion 2 - + Face Buttons Frontknapper - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Høyre Pinne - - - - + + + + Clear - - - - + + + + [not set] - - + + Toggle button - - + + Invert button + + + + + + Invert axis + + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. - - Invert axis - - - - - + + Deadzone: %1% Dødsone: %1% - - + + Modifier Range: %1% Modifikatorområde: %1% - + + + Pro Controller + Pro-Kontroller + + + + Dual Joycons + Doble Joycons + + + + Left Joycon + Venstre Joycon + + + + Right Joycon + Høyre Joycon + + + + Handheld + Håndholdt + + + GameCube Controller - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause - + Z - + Control Stick - + C-Stick - + Shake! - + [waiting] [venter] - + New Profile - + Enter a profile name: - - + + Create Input Profile - + The given profile name is not valid! - + Failed to create the input profile "%1" - + Delete Input Profile - + Failed to delete the input profile "%1" - + Load Input Profile - + Failed to load the input profile "%1" - + Save Input Profile - + Failed to save the input profile "%1" @@ -2046,85 +2187,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch Konfigurer Bevegelse / Touch - - Mouse Motion - - - - - Sensitivity: - Sensitivitet: - - - + Touch Touch - + UDP Calibration: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Konfigurer - - Use button mapping: + + Touch from button profile: - + CemuhookUDP Config CemuhookUDP-Konfigurasjon - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Du kan bruke hvilken som helst Cemuhook-kompatibel UDP inputkilde for å gi bevegelses- og touch-input. - + Server: Server: - + Port: Port: - + Learn More Lær Mer - - + + Test Test - + Add Server - + Remove Server @@ -2134,145 +2265,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Lær Mer</span></a> - + %1:%2 - - - - - - + + + + + + yuzu - + Port number has invalid characters - + Port has to be in range 0 and 65353 - + IP address is not valid - + This UDP server already exists - + Unable to add more than 8 servers - + Testing Testing - + Configuring Konfigurering - + Test Successful Test Vellykket - + Successfully received data from the server. Mottatt data fra serveren vellykket. - + Test Failed Test Feilet - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Kunne ikke motta gyldig data fra serveren.<br>Vennligst bekreft at serveren er satt opp riktig og at adressen og porten er riktige. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP-Test eller kalibrasjonskonfigurering er i fremgang.<br>Vennligst vent for dem til å bli ferdig. - - ConfigureMouseAdvanced - - - Configure Mouse - Konfigurer Mus - - - - Mouse Buttons - Museknapper - - - - Forward: - Frem: - - - - Back: - Tilbake: - - - - Left: - Venstre: - - - - Middle: - Midten: - - - - Right: - Høyre: - - - - - Clear - Fjern - - - - Defaults - Standardverdier - - - - [not set] - [ikke satt] - - - - Restore Default - Gjenopprett Standardverdi - - - - [press key] - [trykk på en knapp] - - ConfigureNetwork @@ -3056,31 +3123,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3093,7 +3155,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - + Select TAS Load Directory... @@ -3154,37 +3216,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile Ny Profil - + Enter the name for the new profile. Skriv inn navnet til den nye profilen. - + Delete Profile Slett Profil - + Delete profile %1? Slett profil %1? - + Rename Profile Endre Navn på Profil - + New name: Nytt navn: - + [press key] [trykk knapp] @@ -3604,12 +3666,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 - + &Controller P1 @@ -3617,89 +3679,94 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonym data blir samlet inn</a>for å hjelpe til med å forbedre yuzu.<br/><br/>Vil du dele din bruksdata med oss? - + Telemetry Telemetri - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Nåværende emuleringshastighet. Verdier høyere eller lavere en 100% indikerer at emuleringen kjører raskere eller tregere enn en Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hvor mange bilder per sekund spiller viser. Dette vil variere fra spill til spill og scene til scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid det tar for å emulere et Switch bilde. Teller ikke med bildebegrensing eller v-sync. For full-hastighet emulering burde dette være 16.67 ms. på det høyeste. - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - + DOCK - + VULKAN - + OPENGL - + &Clear Recent Files - - TAS Recording + + &Continue - - Overwrite file of player 1? + + &Pause @@ -3751,656 +3818,723 @@ Drag points to change position, or double-click table cells to edit values.En ukjent feil oppstod. Se loggen for flere detaljer. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Start - - - + Save Data Lagre Data - + Mod Data Mod Data - + Error Opening %1 Folder Feil Under Åpning av %1 Mappen - - + + Folder does not exist! Mappen eksisterer ikke! - + Error Opening Transferable Shader Cache - + Failed to create the shader cache directory for this title. - + Contents Innhold - + Update Oppdatering - + DLC DLC - + Remove Entry - + Remove Installed Game %1? Fjern Installert Spill %1? - - - - - - + + + + + + Successfully Removed - + Successfully removed the installed base game. - - - + + + Error Removing %1 Feil Under Fjerning av %1 - + The base game is not installed in the NAND and cannot be removed. Grunnspillet er ikke installert i NAND og kan ikke bli fjernet. - + Successfully removed the installed update. Fjernet vellykket den installerte oppdateringen. - + There is no update installed for this title. Det er ingen oppdatering installert for denne tittelen. - + There are no DLC installed for this title. Det er ingen DLC installert for denne tittelen. - + Successfully removed %1 installed DLC. Fjernet vellykket %1 installerte DLC-er. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Fjern Tilpasset Spillkonfigurasjon? - + Remove File Fjern Fil - - + + Error Removing Transferable Shader Cache Feil Under Fjerning Av Overførbar Shader Cache - - + + A shader cache for this title does not exist. - + Successfully removed the transferable shader cache. Fjernet vellykket den overførbare shader cachen. - + Failed to remove the transferable shader cache. Feil under fjerning av den overførbare shader cachen. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Feil Under Fjerning Av Tilpasset Konfigurasjon - + A custom configuration for this title does not exist. En tilpasset konfigurasjon for denne tittelen finnes ikke. - + Successfully removed the custom game configuration. Fjernet vellykket den tilpassede spillkonfigurasjonen. - + Failed to remove the custom game configuration. Feil under fjerning av den tilpassede spillkonfigurasjonen. - - + + RomFS Extraction Failed! Utvinning av RomFS Feilet! - + There was an error copying the RomFS files or the user cancelled the operation. Det oppstod en feil under kopiering av RomFS filene eller så kansellerte brukeren operasjonen. - + Full Fullstendig - + Skeleton Skjelett - + Select RomFS Dump Mode Velg RomFS Dump Modus - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Velg hvordan du vil dumpe RomFS.<br>Fullstendig vil kopiere alle filene til en ny mappe mens <br>skjelett vil bare skape mappestrukturen. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Utvinner RomFS... - - + + Cancel Avbryt - + RomFS Extraction Succeeded! RomFS Utpakking lyktes! - + The operation completed successfully. Operasjonen fullført vellykket. - + Error Opening %1 Feil ved åpning av %1 - + Select Directory Velg Mappe - + Properties Egenskaper - + The game properties could not be loaded. Spillets egenskaper kunne ikke bli lastet inn. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch Kjørbar Fil (%1);;Alle Filer (*.*) - + Load File Last inn Fil - + Open Extracted ROM Directory Åpne Utpakket ROM Mappe - + Invalid Directory Selected Ugyldig Mappe Valgt - + The directory you have selected does not contain a 'main' file. Mappen du valgte inneholder ikke en 'main' fil. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Installerbar Switch-Fil (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xcI) - + Install Files Installer Filer - + %n file(s) remaining - + Installing file "%1"... Installerer fil "%1"... - - + + Install Results Insallasjonsresultater - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systemapplikasjon - + System Archive Systemarkiv - + System Application Update Systemapplikasjonsoppdatering - + Firmware Package (Type A) Firmware Pakke (Type A) - + Firmware Package (Type B) Firmware-Pakke (Type B) - + Game Spill - + Game Update Spilloppdatering - + Game DLC Spill tilleggspakke - + Delta Title Delta Tittel - + Select NCA Install Type... Velg NCA Installasjonstype... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Vennligst velg typen tittel du vil installere denne NCA-en som: (I de fleste tilfellene, standarden 'Spill' fungerer.) - + Failed to Install Feil under Installasjon - + The title type you selected for the NCA is invalid. Titteltypen du valgte for NCA-en er ugyldig. - + File not found Fil ikke funnet - + File "%1" not found Filen "%1" ikke funnet - - - &Continue - - - - + OK - + Missing yuzu Account Mangler yuzu Bruker - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. For å sende inn et testtilfelle for spillkompatibilitet, må du linke yuzu-brukeren din.<br><br/>For å linke yuzu-brukeren din, gå til Emulasjon &gt; Konfigurasjon &gt; Nett. - + Error opening URL Feil under åpning av URL - + Unable to open the URL "%1". Kunne ikke åpne URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Amiibo-Fil (%1);; Alle Filer (*.*) - + Load Amiibo Last inn Amiibo - + Error opening Amiibo data file Feil ved Åpning av Amiibo data fil - + Unable to open Amiibo file "%1" for reading. Kunne ikke åpne Amiibo-fil "%1" for lesing. - + Error reading Amiibo data file Feil under lesing av Amiibo datafil. - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Kunne ikke lese all Amiibo-data. Forventet å lese minst %1 bytes, men kunne bare lese %2 bytes. - + Error loading Amiibo data Feil ved lasting av Amiibo data - + Unable to load Amiibo data. Kunne ikke laste Amiibo-data. - + Capture Screenshot Ta Skjermbilde - + PNG Image (*.png) PNG Bilde (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Hastighet: %1% / %2% - + Speed: %1% Hastighet: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Spill: %1 FPS - + Frame: %1 ms Ramme: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Spillet du prøver å laste krever at ekstra filer fra din Switch blir dumpet før du spiller.<br/><br/>For mer informasjon om dumping av disse filene, vennligst se den følgende wiki-siden: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping av System-Arkiv og Shared Fonts fra en Switch-Konsoll</a>.<br/><br/>Vil du gå tilbake til spillisten? Fortsetting av emulasjon kan føre til krasjing, ødelagt lagringsdata, eller andre feil. - + yuzu was unable to locate a Switch system archive. %1 yuzu kunne ikke finne et Switch system-arkiv. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu kunne ikke finne et Switch system-arkiv: %1. %2 - + System Archive Not Found System Arkiv Ikke Funnet - + System Archive Missing System Arkiv Mangler - + yuzu was unable to locate the Switch shared fonts. %1 yuzu kunne ikke finne Switch shared fonts. %1 - + Shared Fonts Not Found Shared Fonts Ikke Funnet - + Shared Font Missing Shared Font Mangler - + Fatal Error Fatal Feil - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu har oppdaget en fatal feil, vennligst se loggen for flere detaljer. For mer informasjon om å finne loggen, vennligst se den følgende siden: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Hvordan å Laste Opp Log-Filen</a>.<br/><br/>Vil du gå tilbake til spillisten? Fortsetting av emulasjon kan føre til krasjing, ødelagt lagringsdata, eller andre feil. - + Fatal Error encountered Fatal Feil oppstått - + Confirm Key Rederivation Bekreft Nøkkel-Redirevasjon - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4417,37 +4551,37 @@ og eventuelt lag backups. Dette vil slette dine autogenererte nøkkel-filer og kjøre nøkkel-derivasjonsmodulen på nytt. - + Missing fuses Mangler fuses - + - Missing BOOT0 - Mangler BOOT0 - + - Missing BCPKG2-1-Normal-Main - Mangler BCPKG2-1-Normal-Main - + - Missing PRODINFO - Mangler PRODINFO - + Derivation Components Missing Derivasjonskomponenter Mangler - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Komponenter som kan hindre nøkkel-derivasjon fra å fullføre mangler.<br>Vennligst følg <a href='https://yuzu-emu.org/help/quickstart/'>yuzu quickstart-guiden</a> for å få alle dine nøkler og spill.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4456,39 +4590,39 @@ Dette kan ta opp til et minutt avhengig av systemytelsen din. - + Deriving Keys Deriverer Nøkler - + Select RomFS Dump Target Velg RomFS Dump-Mål - + Please select which RomFS you would like to dump. Vennligst velg hvilken RomFS du vil dumpe. - + Are you sure you want to close yuzu? Er du sikker på at du vil lukke yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Er du sikker på at du vil stoppe emulasjonen? All ulagret fremgang vil bli tapt. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4498,38 +4632,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! OpenGL ikke tilgjengelig! - + yuzu has not been compiled with OpenGL support. yuzu har ikke blitt kompilert med OpenGL-støtte. - - + + Error while initializing OpenGL! Feil under initialisering av OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4885,190 +5019,205 @@ Screen. &Emulering - + &View &Vis - + &Reset Window Size - - Reset Window Size to &720p - - - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - - - Reset Window Size to 1080p - - - - + &Debugging - + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + &Tools - + + &TAS + + + + &Help &Hjelp - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit &Avslutt - - &Start - &Start - - - + &Pause &Pause - + &Stop &Stop - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar - + F&ullscreen - + &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5110,10 +5259,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5144,142 +5298,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [ikke satt] - - Hat %1 %2 Hatt %1 %2 - - - - - - + + + + Axis %1%2 Akse %1%2 - Button %1 Knapp %1 - - - + + + [unknown] [ukjent] - + + Left + + + + + Right + + + - Click 0 + Down - - Click 1 + Up - - Click 2 + Z - - Click 3 + R - - Click 4 + L - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 - - GC Axis %1%2 + + [invalid] - - GC Button %1 + + + %1%2Hat %3 - - TAS Axis %1 + + + + %1%2Axis %3 - - TAS Btn %1 + + %1%2Axis %3,%4,%5 - - Motion %1 + + %1%2Motion %3 - - %1Button %2 + + + %1%2Button %3 - - SDL Motion - - - - - %1Click %2 - - - - + [unused] [ubrukt] @@ -5320,7 +5554,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5333,7 +5567,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons @@ -5346,7 +5580,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon @@ -5359,7 +5593,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon @@ -5387,7 +5621,7 @@ p, li { white-space: pre-wrap; } - + Handheld @@ -5508,7 +5742,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5592,13 +5826,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts index 85252334d..d2ea219f7 100644 --- a/dist/languages/nl.ts +++ b/dist/languages/nl.ts @@ -320,7 +320,9 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - + +<div>Deze optie verbetert de snelheid of 32-bit ASIMD floating-point functies door incorrecte afronding modellen te gebruiken.</div> + @@ -368,7 +370,8 @@ p, li { white-space: pre-wrap; } CPU - + CPU + @@ -498,7 +501,10 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> - + +<div style="white-space: nowrap">Deze optimazie versneld geheugen toegang door het gastprogramma.</div> +<div style="white-space: nowrap">Door dit aan te leggen geeft toegang tot PageTable::pointers in uitgezonden code.</div> +<div style="white-space: nowrap">Door dit uit te leggen forceerd u alle geheugen toegang door Memory::Read/Memory::Write functies te gaan.</div> @@ -649,7 +655,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -929,67 +940,78 @@ p, li { white-space: pre-wrap; } Algemeen - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Limiteer Snelheid Percentage - + % % - + Multicore CPU Emulation Multicore CPU Emulatie - + Confirm exit while emulation is running Bevestig sluiten terwijl emulatie nog bezig is - + Prompt for user on game boot Vraag voor gebruiker bij het opstartten van het spel. - + Pause emulation when in background Pauzeer Emulatie wanneer yuzu op de achtergrond openstaat - + Hide mouse on inactivity Verstop muis wanneer inactief - + Reset All Settings Reset alle instellingen - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Hiermee worden alle instellingen gereset en alle configuraties per game verwijderd. Hiermee worden gamedirectory's, profielen of invoerprofielen niet verwijderd. Doorgaan? @@ -1107,18 +1129,113 @@ p, li { white-space: pre-wrap; } Rek naar Venster - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Gebruik globale achtergrondkleur - + Set background color: Gebruik achtergrondkleur: - + Background Color: Achtergrondkleur: @@ -1187,27 +1304,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Standaard - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1535,8 +1657,8 @@ p, li { white-space: pre-wrap; } - Other - Ander + Emulated Devices + @@ -1545,66 +1667,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emuleer Anolooge invoer met toetsenbord - - - - Enable mouse panning - Schakel muis panning in - - - - Mouse sensitivity - Muis Gevoeligheid - - - - % - - - - - - Advanced - Gedadvanceerd - - - - Touchscreen - Touchscreen - - - Mouse Muis - - Motion / Touch - Beweging / Touch + + Touchscreen + Touchscreen - - - Configure - Configureer + + Advanced + Gedadvanceerd - + Debug Controller Debug Controller - + + + Configure + Configureer + + + + Other + Ander + + + + Emulate Analog with Keyboard Input + Emuleer Anolooge invoer met toetsenbord + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Schakel muis panning in + + + + Mouse sensitivity + Muis Gevoeligheid + + + + % + + + + + Motion / Touch + Beweging / Touch + ConfigureInputPlayer @@ -1619,425 +1750,441 @@ p, li { white-space: pre-wrap; } Verbindt Controller - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Twee Joycons - - - - - Left Joycon - Linker Joycon - - - - - Right Joycon - Rechter Joycon - - - - - Handheld - Mobiel - - - + Input Device Invoer Apparaat - - Any - Elke - - - - Keyboard/Mouse - Toetsenbord/muis - - - + Profile Profiel - + Save Opslaan - + New Nieuw - + Delete Verwijder - - + + Left Stick Linker Stick - - - - - - + + + + + + Up Boven: - - - - - - - + + + + + + + Left Links: - - - - - - - + + + + + + + Right Rechts: - - - - - - + + + + + + Down Beneden: - - - - + + + + Pressed Ingedrukt: - - - - + + + + Modifier Modificatie: - - + + Range Berijk - - + + % % - - + + Deadzone: 0% Deadzone: 0% - - + + Modifier Range: 0% Bewerk Range: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Min - - + + Capture Vastleggen - - - + + + Plus Plus: - - + + Home Home: - - - - + + + + R R: - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Beweging 1 - + Motion 2 Beweging 2 - + Face Buttons Gezicht Knoppen - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Rechter Stick - - - - + + + + Clear Verwijder - - - - + + + + [not set] [niet ingesteld] - - + + Toggle button Shakel Knop - - + + Invert button + + + + + + Invert axis + Spiegel As + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick Zet Analoge Stick - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Na OK in te drukken, beweeg je joystick eerst horizontaal en dan verticaal. Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal. - - Invert axis - Spiegel As - - - - + + Deadzone: %1% Deadzone: %1% - - + + Modifier Range: %1% Bewerk Range: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Twee Joycons + + + + Left Joycon + Linker Joycon + + + + Right Joycon + Rechter Joycon + + + + Handheld + Mobiel + + + GameCube Controller GameCube Controller - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pauze - + Z Z - + Control Stick Control Stick - + C-Stick C-Stick - + Shake! Shudden! - + [waiting] [aan het wachten] - + New Profile Nieuw Profiel - + Enter a profile name: Voer nieuwe gebruikersnaam in: - - + + Create Input Profile Creëer een nieuw Invoer Profiel - + The given profile name is not valid! De ingevoerde Profiel naam is niet geldig - + Failed to create the input profile "%1" Het is mislukt om Invoer Profiel "%1 te Creëer - + Delete Input Profile Verwijder invoer profiel - + Failed to delete the input profile "%1" Het is mislukt om Invoer Profiel "%1 te Verwijderen - + Load Input Profile Laad invoer profiel - + Failed to load the input profile "%1" Het is mislukt om Invoer Profiel "%1 te Laden - + Save Input Profile Sla Invoer profiel op - + Failed to save the input profile "%1" Het is mislukt om Invoer Profiel "%1 Op te slaan @@ -2063,85 +2210,75 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal. ConfigureMotionTouch - + Configure Motion / Touch Configureer Beweging / Touch - - Mouse Motion - Muis Beweging - - - - Sensitivity: - Gevoeligheid: - - - + Touch Touch - + UDP Calibration: UDP Calibratie: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configureer - - Use button mapping: - Gebruik knoptoewijzing: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP Configuratie - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. U kunt elke Cemuhook-compatibele UDP-invoerbron gebruiken voor bewegings- en aanraakinvoer. - + Server: Server: - + Port: Poort: - + Learn More Leer Meer - - + + Test Test - + Add Server Voeg Server toe - + Remove Server Externe Server @@ -2151,145 +2288,81 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal. <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Leer Meer</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu Yuzu - + Port number has invalid characters Poortnummer bevat ongeldige tekens - + Port has to be in range 0 and 65353 Poort moet in bereik 0 en 65353 zijn - + IP address is not valid IP adress is niet geldig - + This UDP server already exists Deze UDP server bestaat al - + Unable to add more than 8 servers Kan niet meer dan 8 servers toevoegen - + Testing Testen - + Configuring Configureren - + Test Successful Test Succesvol - + Successfully received data from the server. De data van de server is succesvol ontvangen. - + Test Failed Test Gefaald - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Kan niet de juiste data van de server ontvangen.<br>Verifieer dat de server is goed opgezet en dat het adres en poort correct zijn. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP Test of calibratie configuratie is bezig.<br>Wacht alstublieft totdat het voltooid is. - - ConfigureMouseAdvanced - - - Configure Mouse - Configureer Muis - - - - Mouse Buttons - Muisknoppen - - - - Forward: - Voorwaarts: - - - - Back: - Terug: - - - - Left: - Links: - - - - Middle: - Middel: - - - - Right: - Rechts: - - - - - Clear - Herstellen - - - - Defaults - Standaarden - - - - [not set] - [niet ingesteld] - - - - Restore Default - Herstel Standaardwaarde - - - - [press key] - [druk op knop] - - ConfigureNetwork @@ -3073,31 +3146,26 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal. - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3110,7 +3178,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal. - + Select TAS Load Directory... @@ -3172,37 +3240,37 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen Y - + New Profile Nieuw Profiel - + Enter the name for the new profile. Voer een naam in voor het nieuwe profiel. - + Delete Profile Verwijder Profiel - + Delete profile %1? Verwijder Profiel %1? - + Rename Profile Hernoem Profiel - + New name: Nieuwe naam: - + [press key] [druk op toets] @@ -3622,12 +3690,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen ControllerDialog - + Controller P1 - + &Controller P1 @@ -3635,89 +3703,94 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Annonieme gegevens worden verzameld</a> om yuzu te helpen verbeteren. <br/><br/> Zou je jouw gebruiksgegevens met ons willen delen? - + Telemetry Telemetrie - + Loading Web Applet... Web Applet Laden... - - + + Disable Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Huidige emulatie snelheid. Waardes hoger of lager dan 100% betekent dat de emulatie sneller of langzamer loopt dan de Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hoeveel frames per seconde de game op dit moment weergeeft. Dit zal veranderen van game naar game en van scène naar scène. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tijd gebruikt om een frame van de Switch te emuleren, waarbij framelimiteren of v-sync niet wordt meegerekend. Voor emulatie op volledige snelheid zou dit maximaal 16.67 ms zijn. - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - + DOCK - + VULKAN - + OPENGL - + &Clear Recent Files - - TAS Recording + + &Continue - - Overwrite file of player 1? + + &Pause @@ -3769,656 +3842,723 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen Een onbekende fout heeft plaatsgevonden. Kijk in de log voor meer details. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Start - - - + Save Data Save Data - + Mod Data Mod Data - + Error Opening %1 Folder Fout tijdens het openen van %1 folder - - + + Folder does not exist! Folder bestaat niet! - + Error Opening Transferable Shader Cache Fout Bij Het Openen Van Overdraagbare Shader Cache - + Failed to create the shader cache directory for this title. - + Contents - + Update - + DLC - + Remove Entry - + Remove Installed Game %1? - - - - - - + + + + + + Successfully Removed - + Successfully removed the installed base game. - - - + + + Error Removing %1 - + The base game is not installed in the NAND and cannot be removed. - + Successfully removed the installed update. - + There is no update installed for this title. - + There are no DLC installed for this title. - + Successfully removed %1 installed DLC. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove File - - + + Error Removing Transferable Shader Cache - - + + A shader cache for this title does not exist. Er bestaat geen shader cache voor deze game - + Successfully removed the transferable shader cache. - + Failed to remove the transferable shader cache. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration - + A custom configuration for this title does not exist. - + Successfully removed the custom game configuration. - + Failed to remove the custom game configuration. - - + + RomFS Extraction Failed! RomFS Extractie Mislukt! - + There was an error copying the RomFS files or the user cancelled the operation. Er was een fout tijdens het kopiëren van de RomFS bestanden of de gebruiker heeft de operatie geannuleerd. - + Full Vol - + Skeleton Skelet - + Select RomFS Dump Mode Selecteer RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Selecteer alstublieft hoe je de RomFS wilt dumpen.<br>Volledig kopieërd alle bestanden in een map terwijl <br> skelet maakt alleen het map structuur. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... RomFS uitpakken... - - + + Cancel Annuleren - + RomFS Extraction Succeeded! RomFS Extractie Geslaagd! - + The operation completed successfully. De operatie is succesvol voltooid. - + Error Opening %1 Fout bij openen %1 - + Select Directory Selecteer Map - + Properties Eigenschappen - + The game properties could not be loaded. De eigenschappen van de game kunnen niet geladen worden. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch Executable (%1);;Alle bestanden (*.*) - + Load File Laad Bestand - + Open Extracted ROM Directory Open Gedecomprimeerd ROM Map - + Invalid Directory Selected Ongeldige Map Geselecteerd - + The directory you have selected does not contain a 'main' file. De map die je hebt geselecteerd bevat geen 'main' bestand. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files - + %n file(s) remaining - + Installing file "%1"... Bestand "%1" Installeren... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systeem Applicatie - + System Archive Systeem Archief - + System Application Update Systeem Applicatie Update - + Firmware Package (Type A) Filmware Pakket (Type A) - + Firmware Package (Type B) Filmware Pakket (Type B) - + Game Game - + Game Update Game Update - + Game DLC Game DLC - + Delta Title Delta Titel - + Select NCA Install Type... Selecteer NCA Installatie Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Selecteer het type titel hoe je wilt dat deze NCA installeerd: (In de meeste gevallen is de standaard 'Game' juist.) - + Failed to Install Installatie Mislukt - + The title type you selected for the NCA is invalid. Het type title dat je hebt geselecteerd voor de NCA is ongeldig. - + File not found Bestand niet gevonden - + File "%1" not found Bestand "%1" niet gevonden - - - &Continue - - - - + OK - + Missing yuzu Account Je yuzu account mist - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Om game campatibiliteit te raporteren, moet je je yuzu account koppelen.<br><br/> Om je yuzu account te koppelen, ga naar Emulatie &gt; Configuratie &gt; Web. - + Error opening URL - + Unable to open the URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Amiibo Bestand (%1);; Alle Bestanden (*.*) - + Load Amiibo Laad Amiibo - + Error opening Amiibo data file Fout tijdens het openen van het Amiibo gegevens bestand - + Unable to open Amiibo file "%1" for reading. Kan Amiibo bestand "%1" niet lezen. - + Error reading Amiibo data file Fout tijdens het lezen van het Amiibo gegevens bestand - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Kan de volledige Amiibo gegevens niet lezen. Verwacht om %1 bytes te lezen, maar het is alleen mogelijk om %2 bytes te lezen. - + Error loading Amiibo data Fout tijdens het laden van de Amiibo data - + Unable to load Amiibo data. Kan de Amiibo gegevens niet laden. - + Capture Screenshot Screenshot Vastleggen - + PNG Image (*.png) PNG afbeelding (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Snelheid: %1% / %2% - + Speed: %1% Snelheid: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Game: %1 FPS - + Frame: %1 ms Frame: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. De game die je probeert te laden heeft extra bestanden nodig van je Switch voordat je het kan spelen. <br/><br/>Voor meer informatie over het dumpen van deze bestanden, volg alsjeblieft onze wiki pagina: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Het dumpen van Systeem Archieven en de Gedeelde Lettertypen van een Switch console </a>. <br/><br/>Wil je terug gaan naar de game lijst? Verdergaan met de emulatie zal misschien gevolgen hebben als vastlopen, beschadigde opslag data, of andere problemen. - + yuzu was unable to locate a Switch system archive. %1 yuzu was niet in staat om de Switch systeem archieven te vinden. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu was niet in staat om de Switch systeem archieven te vinden. %1. %2 - + System Archive Not Found Systeem Archief Niet Gevonden - + System Archive Missing Systeem Archief Mist - + yuzu was unable to locate the Switch shared fonts. %1 yuzu was niet in staat om de Switch shared fonts te vinden. %1 - + Shared Fonts Not Found Shared Fonts Niet Gevonden - + Shared Font Missing Gedeelde Lettertypes Niet Gevonden - + Fatal Error Fatale Fout - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu is een fatale fout tegengekomen, zie de log voor meer details. Voor meer informatie over toegang krijgen tot de log, zie de volgende pagina: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Hoe upload je een log bestand</a>.<br/><br/>Zou je terug willen naar de game lijst? Doorgaan met emulatie kan resulteren in vastlapen, corrupte save gegevens, of andere problemen. - + Fatal Error encountered Fatale Fout opgetreden - + Confirm Key Rederivation Bevestig Sleutel Herafleiding - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4435,37 +4575,37 @@ en optioneel maak backups. Dit zal je automatisch gegenereerde sleutel bestanden verwijderen en de sleutel verkrijger module opnieuw starten - + Missing fuses - + - Missing BOOT0 - + - Missing BCPKG2-1-Normal-Main - + - Missing PRODINFO - + Derivation Components Missing - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4473,39 +4613,39 @@ on your system's performance. op je systeem's performatie. - + Deriving Keys Sleutels afleiden - + Select RomFS Dump Target Selecteer RomFS Dump Doel - + Please select which RomFS you would like to dump. Selecteer welke RomFS je zou willen dumpen. - + Are you sure you want to close yuzu? Weet je zeker dat je yuzu wilt sluiten? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Weet je zeker dat je de emulatie wilt stoppen? Alle onopgeslagen voortgang will verloren gaan. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4517,38 +4657,38 @@ Wilt u dit omzeilen en toch afsluiten? GRenderWindow - + OpenGL not available! - + yuzu has not been compiled with OpenGL support. - - + + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4904,190 +5044,205 @@ Screen. &Emulatie - + &View &Weergeven - + &Reset Window Size - - Reset Window Size to &720p - - - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - - - Reset Window Size to 1080p - - - - + &Debugging - + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + &Tools - + + &TAS + + + + &Help &Help - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit A&fsluiten - - &Start - &Start - - - + &Pause &Pauzeren - + &Stop &Stop - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Laat status balk zien - + F&ullscreen - + &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5129,10 +5284,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5163,142 +5323,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [niet aangegeven] - - Hat %1 %2 Hat %1 %2 - - - - - - + + + + Axis %1%2 Axis %1%2 - Button %1 Knop %1 - - - + + + [unknown] [onbekend] - + + Left + + + + + Right + + + - Click 0 + Down - - Click 1 + Up - - Click 2 + Z - - Click 3 + R - - Click 4 - Klik 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC Axis %1%2 - - - - GC Button %1 - GC knop %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Beweging %1 - - - - %1Button %2 + + + + %1%2Axis %3 - - SDL Motion + + %1%2Axis %3,%4,%5 - - %1Click %2 + + %1%2Motion %3 - + + + %1%2Button %3 + + + + [unused] [ongebruikt] @@ -5339,7 +5579,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5352,7 +5592,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons @@ -5365,7 +5605,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon @@ -5378,7 +5618,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon @@ -5406,7 +5646,7 @@ p, li { white-space: pre-wrap; } - + Handheld @@ -5527,7 +5767,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5611,13 +5851,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/pl.ts b/dist/languages/pl.ts index 7fcece92c..6800b751c 100644 --- a/dist/languages/pl.ts +++ b/dist/languages/pl.ts @@ -651,7 +651,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -931,67 +936,78 @@ p, li { white-space: pre-wrap; } Ogólne - - Framerate Cap - Limit klatek na sekundę + + + Use global framerate cap + - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + Limit klatek na sekundę + + + x x - + Limit Speed Percent Procent limitu prędkości - + % % - + Multicore CPU Emulation Emulacja CPU Wielordzeniowa - + Confirm exit while emulation is running Potwierdź wyjście podczas emulacji - + Prompt for user on game boot Pytaj o użytkownika podczas uruchamiania gry - + Pause emulation when in background Wstrzymaj emulację w tle - + Hide mouse on inactivity Ukryj mysz przy braku aktywności - + Reset All Settings Resetuj wszystkie ustawienia - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Spowoduje to zresetowanie wszystkich ustawień i usunięcie wszystkich konfiguracji gier. Nie spowoduje to usunięcia katalogów gier, profili ani profili wejściowych. Kontynuować? @@ -1109,18 +1125,113 @@ p, li { white-space: pre-wrap; } Rozciągnij do Okna - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Ustaw globalny kolor tła - + Set background color: Ustaw kolor tła: - + Background Color: Kolor tła @@ -1189,27 +1300,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Domyślne - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1537,8 +1653,8 @@ p, li { white-space: pre-wrap; } - Other - Inne + Emulated Devices + @@ -1547,66 +1663,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emuluj sygnał analogowy z wejściem z klawiatury - - - - Enable mouse panning - Włącz panoramowanie myszą - - - - Mouse sensitivity - Czułość myszy - - - - % - - - - - - Advanced - Zaawansowane - - - - Touchscreen - Ekran dotykowy - - - Mouse Mysz - - Motion / Touch - Ruch / Dotyk + + Touchscreen + Ekran dotykowy - - - Configure - Konfiguruj + + Advanced + Zaawansowane - + Debug Controller Debuguj kontroler - + + + Configure + Konfiguruj + + + + Other + Inne + + + + Emulate Analog with Keyboard Input + Emuluj sygnał analogowy z wejściem z klawiatury + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Włącz panoramowanie myszą + + + + Mouse sensitivity + Czułość myszy + + + + % + + + + + Motion / Touch + Ruch / Dotyk + ConfigureInputPlayer @@ -1621,425 +1746,441 @@ p, li { white-space: pre-wrap; } Połacz Kontroler - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Para Joyconów - - - - - Left Joycon - Lewy Joycon - - - - - Right Joycon - Prawy Joycon - - - - - Handheld - Handheld - - - + Input Device Urządzenie Wejściowe - - Any - Dowolny - - - - Keyboard/Mouse - Klawiatura/Mysz - - - + Profile Profil - + Save Zapisz - + New Nowy - + Delete Usuń - - + + Left Stick Lewa gałka - - - - - - + + + + + + Up Góra - - - - - - - + + + + + + + Left Lewo - - - - - - - + + + + + + + Right Prawo - - - - - - + + + + + + Down Dół - - - - + + + + Pressed Naciśnięty - - - - + + + + Modifier Modyfikator - - + + Range Zasięg - - + + % % - - + + Deadzone: 0% Martwa strefa: 0% - - + + Modifier Range: 0% Zasięg Modyfikatora: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture Zrzut ekranu - - - + + + Plus Plus - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Ruch 1 - + Motion 2 Ruch 2 - + Face Buttons Przednie klawisze - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Prawa gałka - - - - + + + + Clear Wyczyść - - - - + + + + [not set] [nie ustawione] - - + + Toggle button Przycisk Toggle - - + + Invert button + + + + + + Invert axis + Odwróć oś + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Po naciśnięciu OK, najpierw przesuń joystick w poziomie, a następnie w pionie. Aby odwrócić osie, najpierw przesuń joystick pionowo, a następnie poziomo. - - Invert axis - Odwróć oś - - - - + + Deadzone: %1% Martwa strefa: %1% - - + + Modifier Range: %1% Zasięg Modyfikatora: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Para Joyconów + + + + Left Joycon + Lewy Joycon + + + + Right Joycon + Prawy Joycon + + + + Handheld + Handheld + + + GameCube Controller Kontroler GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pauza - + Z Z - + Control Stick Lewa gałka - + C-Stick C-gałka - + Shake! Potrząśnij! - + [waiting] [oczekiwanie] - + New Profile Nowy profil - + Enter a profile name: Wpisz nazwę profilu: - - + + Create Input Profile Utwórz profil wejściowy - + The given profile name is not valid! Podana nazwa profilu jest nieprawidłowa! - + Failed to create the input profile "%1" Nie udało się utworzyć profilu wejściowego "%1" - + Delete Input Profile Usuń profil wejściowy - + Failed to delete the input profile "%1" Nie udało się usunąć profilu wejściowego "%1" - + Load Input Profile Załaduj profil wejściowy - + Failed to load the input profile "%1" Nie udało się wczytać profilu wejściowego "%1" - + Save Input Profile Zapisz profil wejściowy - + Failed to save the input profile "%1" Nie udało się zapisać profilu wejściowego "%1" @@ -2065,85 +2206,75 @@ Aby odwrócić osie, najpierw przesuń joystick pionowo, a następnie poziomo. ConfigureMotionTouch - + Configure Motion / Touch Konfiguruj Ruch / Dotyk - - Mouse Motion - Ruch myszy - - - - Sensitivity: - Czułość: - - - + Touch Dotyk - + UDP Calibration: Kalibracja UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Konfiguruj - - Use button mapping: - Użyj mapowania przycisków: + + Touch from button profile: + - + CemuhookUDP Config Konfiguracja CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Możesz użyć dowolnego źródła wejściowego UDP zgodnego z Cemuhook, aby zapewnić ruch i dotyk. - + Server: Serwer: - + Port: Port: - + Learn More Dowiedz się więcej - - + + Test Test - + Add Server Dodaj serwer - + Remove Server Usuń serwer @@ -2153,145 +2284,81 @@ Aby odwrócić osie, najpierw przesuń joystick pionowo, a następnie poziomo.<a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Dowiedz się więcej</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Port zawiera nieprawidłowe znaki - + Port has to be in range 0 and 65353 Port musi być w zakresie 0-65353 - + IP address is not valid Adres IP nie jest prawidłowy - + This UDP server already exists Ten serwer UDP już istnieje - + Unable to add more than 8 servers Nie można dodać więcej niż 8 serwerów - + Testing Testowanie - + Configuring Konfigurowanie - + Test Successful Test Udany - + Successfully received data from the server. Pomyślnie odebrano dane z serwera. - + Test Failed Test nieudany - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Nie można odebrać poprawnych danych z serwera.<br>Sprawdź, czy serwer jest poprawnie skonfigurowany, a adres i port są prawidłowe. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Trwa konfiguracja testu UDP lub kalibracji.<br>Poczekaj na zakończenie. - - ConfigureMouseAdvanced - - - Configure Mouse - Ustaw mysz - - - - Mouse Buttons - Przyciski myszy - - - - Forward: - Do przodu - - - - Back: - Do tyłu - - - - Left: - Lewy - - - - Middle: - Środkowy - - - - Right: - Prawy - - - - - Clear - Wyczyść - - - - Defaults - Domyślne - - - - [not set] - [nie ustawione] - - - - Restore Default - Przywróć ustawienie domyślne - - - - [press key] - [naciśnij przycisk] - - ConfigureNetwork @@ -3075,31 +3142,26 @@ Aby odwrócić osie, najpierw przesuń joystick pionowo, a następnie poziomo. - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3112,7 +3174,7 @@ Aby odwrócić osie, najpierw przesuń joystick pionowo, a następnie poziomo. - + Select TAS Load Directory... @@ -3174,37 +3236,37 @@ Przeciągnij punkty, aby zmienić pozycję, lub kliknij dwukrotnie komórki tabe Y - + New Profile Nowy profil - + Enter the name for the new profile. Wprowadź nazwę dla nowego profilu: - + Delete Profile Usuń profil - + Delete profile %1? Usunąć profil %1? - + Rename Profile Zmień nazwę profilu - + New name: Nowa nazwa: - + [press key] [naciśnij przycisk] @@ -3624,12 +3686,12 @@ Przeciągnij punkty, aby zmienić pozycję, lub kliknij dwukrotnie komórki tabe ControllerDialog - + Controller P1 Kontroler P1 - + &Controller P1 &Kontroler P1 @@ -3637,89 +3699,94 @@ Przeciągnij punkty, aby zmienić pozycję, lub kliknij dwukrotnie komórki tabe GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Dane anonimowe są gromadzone</a> aby ulepszyć yuzu. <br/><br/>Czy chcesz udostępnić nam swoje dane o użytkowaniu? - + Telemetry Telemetria - + Loading Web Applet... Ładowanie apletu internetowego... - - + + Disable Web Applet Wyłącz Aplet internetowy - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Wyłączenie apletu sieciowego spowoduje, że nie będzie on wyświetlany przez resztę emulowanej sesji. Może to prowadzić do niezdefiniowanych zachowań i powinno być używane tylko z Super Mario 3D All-Stars. Czy na pewno chcesz wyłączyć aplet sieciowy? - + The amount of shaders currently being built Ilość budowanych shaderów - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Aktualna prędkość emulacji. Wartości większe lub niższe niż 100% wskazują, że emulacja działa szybciej lub wolniej niż Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Ile klatek na sekundę gra aktualnie wyświetla. To będzie się różnić w zależności od gry, od sceny do sceny. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Czas potrzebny do emulacji klatki na sekundę Switcha, nie licząc ograniczania klatek ani v-sync. Dla emulacji pełnej szybkości powinno to wynosić co najwyżej 16,67 ms. - + Invalid config detected Wykryto nieprawidłową konfigurację - + Handheld controller can't be used on docked mode. Pro controller will be selected. Nie można używać kontrolera handheld w trybie zadokowanym. Zostanie wybrany kontroler Pro. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Usuń Ostatnie pliki - - TAS Recording - + + &Continue + &Kontynuuj - - Overwrite file of player 1? + + &Pause @@ -3771,658 +3838,725 @@ Przeciągnij punkty, aby zmienić pozycję, lub kliknij dwukrotnie komórki tabe Wystąpił nieznany błąd. Więcej informacji można znaleźć w pliku log. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Start - - - + Save Data Zapis danych - + Mod Data Dane modów - + Error Opening %1 Folder Błąd podczas otwarcia folderu %1 - - + + Folder does not exist! Folder nie istnieje! - + Error Opening Transferable Shader Cache Błąd podczas otwierania przenośnej pamięci podręcznej Shaderów. - + Failed to create the shader cache directory for this title. - + Contents Zawartość - + Update Łatka - + DLC DLC - + Remove Entry Usuń wpis - + Remove Installed Game %1? Usunąć zainstalowaną grę %1? - - - - - - + + + + + + Successfully Removed Pomyślnie usunięto - + Successfully removed the installed base game. Pomyślnie usunięto zainstalowaną grę. - - - + + + Error Removing %1 Błąd podczas usuwania %1 - + The base game is not installed in the NAND and cannot be removed. Gra nie jest zainstalowana w NAND i nie może zostać usunięta. - + Successfully removed the installed update. Pomyślnie usunięto zainstalowaną łatkę. - + There is no update installed for this title. Brak zainstalowanych łatek dla tego tytułu. - + There are no DLC installed for this title. Brak zainstalowanych DLC dla tego tytułu. - + Successfully removed %1 installed DLC. Pomyślnie usunięto %1 zainstalowane DLC. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Usunąć niestandardową konfigurację gry? - + Remove File Usuń plik - - + + Error Removing Transferable Shader Cache Błąd podczas usuwania przenośnej pamięci podręcznej Shaderów. - - + + A shader cache for this title does not exist. Pamięć podręczna Shaderów dla tego tytułu nie istnieje. - + Successfully removed the transferable shader cache. Pomyślnie usunięto przenośną pamięć podręczną Shaderów. - + Failed to remove the transferable shader cache. Nie udało się usunąć przenośnej pamięci Shaderów. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Błąd podczas usuwania niestandardowej konfiguracji - + A custom configuration for this title does not exist. Niestandardowa konfiguracja nie istnieje dla tego tytułu. - + Successfully removed the custom game configuration. Pomyślnie usunięto niestandardową konfiguracje gry. - + Failed to remove the custom game configuration. Nie udało się usunąć niestandardowej konfiguracji gry. - - + + RomFS Extraction Failed! Wypakowanie RomFS nieudane! - + There was an error copying the RomFS files or the user cancelled the operation. Wystąpił błąd podczas kopiowania plików RomFS lub użytkownik anulował operację. - + Full Pełny - + Skeleton Szkielet - + Select RomFS Dump Mode Wybierz tryb zrzutu RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Proszę wybrać w jaki sposób chcesz, aby zrzut pliku RomFS został wykonany. <br>Pełna kopia ze wszystkimi plikami do nowego folderu, gdy <br>skielet utworzy tylko strukturę folderu. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Wypakowywanie RomFS... - - + + Cancel Anuluj - + RomFS Extraction Succeeded! Wypakowanie RomFS zakończone pomyślnie! - + The operation completed successfully. Operacja zakończona sukcesem. - + Error Opening %1 Błąd podczas otwierania %1 - + Select Directory Wybierz folder... - + Properties Właściwości - + The game properties could not be loaded. Właściwości tej gry nie mogły zostać załadowane. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Plik wykonywalny Switcha (%1);;Wszystkie pliki (*.*) - + Load File Załaduj plik... - + Open Extracted ROM Directory Otwórz folder wypakowanego ROMu - + Invalid Directory Selected Wybrano niewłaściwy folder - + The directory you have selected does not contain a 'main' file. Folder wybrany przez ciebie nie zawiera 'głownego' pliku. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Instalacyjne pliki Switch'a (*.nca *.nsp *.xci);;Archiwum zawartości Nintendo (*.nca);;Pakiet poddany Nintendo (*.nsp);;Obraz z kartridża NX (*.xci) - + Install Files Zainstaluj pliki - + %n file(s) remaining - + Installing file "%1"... Instalowanie pliku "%1"... - - + + Install Results Wynik instalacji - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Aby uniknąć ewentualnych konfliktów, odradzamy użytkownikom instalowanie gier na NAND. Proszę, używaj tej funkcji tylko do instalowania łatek i DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Aplikacja systemowa - + System Archive Archiwum systemu - + System Application Update Aktualizacja aplikacji systemowej - + Firmware Package (Type A) Paczka systemowa (Typ A) - + Firmware Package (Type B) Paczka systemowa (Typ B) - + Game Gra - + Game Update Aktualizacja gry - + Game DLC Dodatek do gry - + Delta Title Tytuł Delta - + Select NCA Install Type... Wybierz typ instalacji NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Wybierz typ tytułu, do którego chcesz zainstalować ten NCA, jako: (W większości przypadków domyślna "gra" jest w porządku.) - + Failed to Install Instalacja nieudana - + The title type you selected for the NCA is invalid. Typ tytułu wybrany dla NCA jest nieprawidłowy. - + File not found Nie znaleziono pliku - + File "%1" not found Nie znaleziono pliku "%1" - - - &Continue - &Kontynuuj - - - + OK OK - + Missing yuzu Account Brakuje konta Yuzu - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Aby przesłać test zgodności gry, musisz połączyć swoje konto yuzu.<br><br/> Aby połączyć swoje konto yuzu, przejdź do opcji Emulacja &gt; Konfiguracja &gt; Sieć. - + Error opening URL Błąd otwierania adresu URL - + Unable to open the URL "%1". Nie można otworzyć adresu URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Plik Amiibo (%1);;Wszyskie pliki (*.*) - + Load Amiibo Załaduj Amiibo - + Error opening Amiibo data file Błąd otwarcia pliku danych Amiibo - + Unable to open Amiibo file "%1" for reading. Nie można otworzyć pliku Amiibo "%1" do odczytu. - + Error reading Amiibo data file Błąd podczas odczytu pliku danych Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Nie można w pełni odczytać danych Amiibo. Oczekiwano odczytu %1 bajtów, ale był on w stanie odczytać tylko %2 bajty. - + Error loading Amiibo data Błąd podczas ładowania pliku danych Amiibo - + Unable to load Amiibo data. Nie można załadować danych Amiibo. - + Capture Screenshot Zrób zrzut ekranu - + PNG Image (*.png) Obrazek PNG (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Prędkość: %1% / %2% - + Speed: %1% Prędkość: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Gra: %1 FPS - + Frame: %1 ms Klatka: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Gra, którą próbujesz wczytać, wymaga dodatkowych plików z Switch'a, które zostaną zrzucone przed graniem.<br/><br/> Aby uzyskać więcej informacji na temat wyrzucania tych plików, odwiedź następującą stronę wiki:<a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'> Zrzut archiw systemu i udostępnionych czcionek z konsoli Nintendo Switch</a>. <br/><br/>Czy chcesz wrócić do listy gier? Kontynuacja emulacji może spowodować awarie, uszkodzone dane zapisu lub inne błędy. - + yuzu was unable to locate a Switch system archive. %1 yuzu nie był w stanie znaleźć archiwum systemu Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu nie był w stanie znaleźć archiwum systemu Switch. %1. %2 - + System Archive Not Found Archiwum systemu nie znalezione. - + System Archive Missing Brak archiwum systemowego - + yuzu was unable to locate the Switch shared fonts. %1 yuzu nie był w stanie zlokalizować czcionek Switch'a. %1 - + Shared Fonts Not Found Czcionki nie zostały znalezione - + Shared Font Missing Brak wspólnej czcionki - + Fatal Error Fatalny błąd - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu napotkał błąd, proszę zobaczyć log po więcej szczegółów. Aby uzyskać więcej informacji na temat uzyskiwania dostępu do pliku log, zobacz następującą stronę: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Jak przesłać plik log</a>?<br/><br/> Czy chcesz wrócić do listy gier? Kontynuacja emulacji może spowodować awarie, uszkodzone dane zapisu lub inne błędy. - + Fatal Error encountered Wystąpił błąd krytyczny - + Confirm Key Rederivation Potwierdź ponowną aktywacje klucza - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4439,37 +4573,37 @@ i opcjonalnie tworzyć kopie zapasowe. Spowoduje to usunięcie wygenerowanych automatycznie plików kluczy i ponowne uruchomienie modułu pochodnego klucza. - + Missing fuses - + - Missing BOOT0 - Brak BOOT0 - + - Missing BCPKG2-1-Normal-Main - Brak BCPKG2-1-Normal-Main - + - Missing PRODINFO - Brak PRODINFO - + Derivation Components Missing Brak komponentów wyprowadzania - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Brakuje elementów, które mogą uniemożliwić zakończenie wyprowadzania kluczy. <br>Postępuj zgodnie z <a href='https://yuzu-emu.org/help/quickstart/'>yuzu quickstart guide</a> aby zdobyć wszystkie swoje klucze i gry.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4478,39 +4612,39 @@ Zależnie od tego może potrwać do minuty na wydajność twojego systemu. - + Deriving Keys Wyprowadzanie kluczy... - + Select RomFS Dump Target Wybierz cel zrzutu RomFS - + Please select which RomFS you would like to dump. Proszę wybrać RomFS, jakie chcesz zrzucić. - + Are you sure you want to close yuzu? Czy na pewno chcesz zamknąć yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Czy na pewno chcesz zatrzymać emulację? Wszystkie niezapisane postępy zostaną utracone. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4522,38 +4656,38 @@ Czy chcesz to ominąć i mimo to wyjść? GRenderWindow - + OpenGL not available! OpenGL niedostępny! - + yuzu has not been compiled with OpenGL support. yuzu nie zostało skompilowane z obsługą OpenGL. - - + + Error while initializing OpenGL! Błąd podczas inicjowania OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Twoja karta graficzna może nie obsługiwać OpenGL lub nie masz najnowszych sterowników karty graficznej. - + Error while initializing OpenGL 4.6! Błąd podczas inicjowania OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Twoja karta graficzna może nie obsługiwać OpenGL 4.6 lub nie masz najnowszych sterowników karty graficznej.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Twoja karta graficzna może nie obsługiwać co najmniej jednego wymaganego rozszerzenia OpenGL. Upewnij się, że masz najnowsze sterowniki karty graficznej<br><br>GL Renderer:<br>%1<br><br>Nieobsługiwane rozszerzenia:<br>%2 @@ -4914,190 +5048,205 @@ startowy. &Emulacja - + &View &Widok - + &Reset Window Size - - Reset Window Size to &720p - Zresetuj rozmiar okna do &720p - - - - Reset Window Size to 720p - Zresetuj rozmiar okna do 720p - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - Zresetuj rozmiar okna do &1080p - - - - Reset Window Size to 1080p - Zresetuj rozmiar okna do 1080p - - - + &Debugging &Debugowanie - + + Reset Window Size to &720p + Zresetuj rozmiar okna do &720p + + + + Reset Window Size to 720p + Zresetuj rozmiar okna do 720p + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + Zresetuj rozmiar okna do &1080p + + + + Reset Window Size to 1080p + Zresetuj rozmiar okna do 1080p + + + &Tools &Narzędzia - + + &TAS + + + + &Help &Pomoc - + &Install Files to NAND... &Zainstaluj pliki na NAND... - + L&oad File... - + Load &Folder... - + E&xit &Wyjście - - &Start - &Start - - - + &Pause &Pauza - + &Stop &Stop - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Pokaż pasek statusu - + F&ullscreen - + &Restart &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5143,10 +5292,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE START/PAUZA + + + Charging + + QObject @@ -5177,142 +5331,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [nie ustawione] - - Hat %1 %2 Krzyżak %1 %2 - - - - - - + + + + Axis %1%2 Oś %1%2 - Button %1 Przycisk %1 - - - + + + [unknown] [nieznane] - + + Left + + + + + Right + + + - Click 0 + Down - - Click 1 + Up - - Click 2 + Z - - Click 3 + R - - Click 4 + L - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - Oś GC %1%2 - - - - GC Button %1 - Przycisk GC %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Ruch %1 - - - - %1Button %2 + + + + %1%2Axis %3 - - SDL Motion - Ruch SDL + + %1%2Axis %3,%4,%5 + - - %1Click %2 - %1Kliknij %2 + + %1%2Motion %3 + - + + + %1%2Button %3 + + + + [unused] [nieużywane] @@ -5353,7 +5587,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro kontroler @@ -5366,7 +5600,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Para Joyconów @@ -5379,7 +5613,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Lewy Joycon @@ -5392,7 +5626,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Prawy Joycon @@ -5420,7 +5654,7 @@ p, li { white-space: pre-wrap; } - + Handheld Handheld @@ -5541,7 +5775,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Kontroler GameCube @@ -5635,13 +5869,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Anuluj diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts index 0c859297e..b2fc3113b 100644 --- a/dist/languages/pt_BR.ts +++ b/dist/languages/pt_BR.ts @@ -666,7 +666,12 @@ p, li { white-space: pre-wrap; } Ativar auto-esboço** - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. **Isto será restaurado automaticamente assim que o yuzu for fechado. @@ -946,67 +951,78 @@ p, li { white-space: pre-wrap; } Geral - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - - x + + Framerate Cap - + + x + x + + + Limit Speed Percent Limitar percentual de velocidade - + % % - + Multicore CPU Emulation Emulação de CPU multinúcleo - + Confirm exit while emulation is running Confirmar saída quando a emulação estiver em execução - + Prompt for user on game boot Escolher um usuário ao iniciar um jogo - + Pause emulation when in background Pausar emulação quando a janela ficar em segundo plano - + Hide mouse on inactivity Esconder cursor do mouse quando em inatividade - + Reset All Settings Redefinir todas as configurações - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Isto restaura todas as configurações e exclui as configurações individuais de todos os jogos. As pastas de jogos, perfis de jogos e perfis de controles não serão excluídos. Deseja prosseguir? @@ -1124,18 +1140,113 @@ p, li { white-space: pre-wrap; } Esticar para a janela - - + + Resolution: + Resolução: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [EXPERIMENTAL] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [EXPERIMENTAL] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + Gaussiana + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + Nenhum + + + + FXAA + + + + + Use global background color Usar cor de fundo global - + Set background color: Configurar cor de fundo: - + Background Color: Cor de fundo: @@ -1204,27 +1315,32 @@ p, li { white-space: pre-wrap; } + Automatic + Automático + + + Default Padrão - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) - + 2x + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1552,8 +1668,8 @@ p, li { white-space: pre-wrap; } - Other - Outro + Emulated Devices + @@ -1562,66 +1678,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emular analógico através do teclado - - - - Enable mouse panning - Ativar o giro do mouse - - - - Mouse sensitivity - Sensibilidade do mouse - - - - % - % - - - - - Advanced - Avançado - - - - Touchscreen - Touchscreen - - - Mouse Mouse - - Motion / Touch - Movimento/toque + + Touchscreen + Touchscreen - - - Configure - Configurar + + Advanced + Avançado - + Debug Controller Controle de depuração - + + + Configure + Configurar + + + + Other + Outro + + + + Emulate Analog with Keyboard Input + Emular analógico através do teclado + + + Requires restarting yuzu Requer reiniciar o yuzu - + Enable XInput 8 player support (disables web applet) Habilitar o suporte para 8 jogadores ao XInput (desabilita o applet da web) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Ativar o giro do mouse + + + + Mouse sensitivity + Sensibilidade do mouse + + + + % + % + + + + Motion / Touch + Movimento/toque + ConfigureInputPlayer @@ -1636,425 +1761,441 @@ p, li { white-space: pre-wrap; } Conectar controle - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - Par de Joycons - - - - - Left Joycon - Joycon Esquerdo - - - - - Right Joycon - Joycon Direito - - - - - Handheld - Portátil - - - + Input Device Dispositivo de entrada - - Any - Qualquer - - - - Keyboard/Mouse - Teclado/mouse - - - + Profile Perfil - + Save Salvar - + New Novo - + Delete Excluir - - + + Left Stick Analógico esquerdo - - - - - - + + + + + + Up Cima - - - - - - - + + + + + + + Left Esquerda - - - - - - - + + + + + + + Right Direita - - - - - - + + + + + + Down Baixo - - - - + + + + Pressed Pressionado - - - - + + + + Modifier Modificador - - + + Range Alcance - - + + % % - - + + Deadzone: 0% Zona morta: 0% - - + + Modifier Range: 0% Alcance de modificador: 0% - + D-Pad D-pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Menos - - + + Capture Capturar - - - + + + Plus Mais - - + + Home Botão Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Movimentação 1 - + Motion 2 Movimentação 2 - + Face Buttons Botões de rosto - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Analógico direito - - - - + + + + Clear Limpar - - - - + + + + [not set] [não definido] - - + + Toggle button Alternar pressionamento do botão - - + + Invert button + + + + + + Invert axis + Inverter eixo + + + + Set threshold Estabelecer limite - + Choose a value between 0% and 100% Escolha um valor entre 0% e 100% - + Map Analog Stick Mapear analógico - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Após pressionar OK, mova o seu direcional analógico primeiro horizontalmente e depois verticalmente. Para inverter os eixos, mova seu analógico primeiro verticalmente e depois horizontalmente. - - Invert axis - Inverter eixo - - - - + + Deadzone: %1% Zona morta: %1% - - + + Modifier Range: %1% Alcance de modificador: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + Par de Joycons + + + + Left Joycon + Joycon Esquerdo + + + + Right Joycon + Joycon Direito + + + + Handheld + Portátil + + + GameCube Controller Controle de GameCube - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Start / Pause - + Z Z - + Control Stick Direcional de controle - + C-Stick C-Stick - + Shake! Balance! - + [waiting] [esperando] - + New Profile Novo perfil - + Enter a profile name: Insira um nome para do perfil: - - + + Create Input Profile Criar perfil de controle - + The given profile name is not valid! O nome de perfil inserido não é válido! - + Failed to create the input profile "%1" Falha ao criar o perfil de controle "%1" - + Delete Input Profile Excluir perfil de controle - + Failed to delete the input profile "%1" Falha ao excluir o perfil de controle "%1" - + Load Input Profile Carregar perfil de controle - + Failed to load the input profile "%1" Falha ao carregar o perfil de controle "%1" - + Save Input Profile Salvar perfil de controle - + Failed to save the input profile "%1" Falha ao salvar o perfil de controle "%1" @@ -2080,85 +2221,75 @@ Para inverter os eixos, mova seu analógico primeiro verticalmente e depois hori ConfigureMotionTouch - + Configure Motion / Touch Configurar movimento/toque - - Mouse Motion - Movimentação com mouse - - - - Sensitivity: - Sensibilidade: - - - + Touch Toque - + UDP Calibration: Calibração UDP - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configurar - - Use button mapping: - Usar mapeamento de botões: + + Touch from button profile: + - + CemuhookUDP Config Configuração CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Você pode utilizar qualquer dispositivo de entrada compatível com o Cemuhook UDP para prover dados de movimento e toque. - + Server: Servidor: - + Port: Porta: - + Learn More Saiba mais - - + + Test Teste - + Add Server Adicionar servidor - + Remove Server Excluir servidor @@ -2168,145 +2299,81 @@ Para inverter os eixos, mova seu analógico primeiro verticalmente e depois hori <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Saiba mais</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters O número da porta tem caracteres inválidos - + Port has to be in range 0 and 65353 A porta tem que estar entre 0 e 65353 - + IP address is not valid O endereço IP não é válido - + This UDP server already exists Este servidor UDP já existe - + Unable to add more than 8 servers Não é possível adicionar mais de 8 servidores - + Testing Testando - + Configuring Configurando - + Test Successful Teste bem-sucedido - + Successfully received data from the server. Dados foram recebidos do servidor com sucesso. - + Test Failed O teste falhou - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Não foi possível receber dados válidos do servidor.<br>Verifique se o servidor foi configurado corretamente e o endereço e porta estão corretos. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Um teste UDP ou configuração de calibração está em curso no momento.<br>Aguarde até a sua conclusão. - - ConfigureMouseAdvanced - - - Configure Mouse - Configurar mouse - - - - Mouse Buttons - Botões do mouse - - - - Forward: - Dianteiro: - - - - Back: - Traseiro: - - - - Left: - Esquerdo: - - - - Middle: - Meio: - - - - Right: - Direito: - - - - - Clear - Limpar - - - - Defaults - Padrões - - - - [not set] - [não definido] - - - - Restore Default - Restaurar padrão - - - - [press key] - [pressione uma tecla] - - ConfigureNetwork @@ -2594,12 +2661,12 @@ Para inverter os eixos, mova seu analógico primeiro verticalmente e depois hori Error resizing user image - + Erro no redimensionamento da imagem do usuário Unable to resize image - + Não foi possível redimensionar a imagem @@ -3090,31 +3157,26 @@ Para inverter os eixos, mova seu analógico primeiro verticalmente e depois hori - Automatic controller profile swapping - Troca automática do perfil do controle - - - Loop script - + Pause execution during loads - + Script Directory - + Diretório do script - + Path Caminho - + ... ... @@ -3127,7 +3189,7 @@ Para inverter os eixos, mova seu analógico primeiro verticalmente e depois hori Configurar TAS - + Select TAS Load Directory... @@ -3189,37 +3251,37 @@ Mova os pontos para mudar a posição, ou clique duas vezes nas células da tabe Y - + New Profile Novo perfil - + Enter the name for the new profile. Insira o nome do novo perfil. - + Delete Profile Excluir perfil - + Delete profile %1? Excluir perfil %1? - + Rename Profile Renomear perfil - + New name: Novo nome: - + [press key] [pressione a tecla] @@ -3639,12 +3701,12 @@ Mova os pontos para mudar a posição, ou clique duas vezes nas células da tabe ControllerDialog - + Controller P1 Controle J1 - + &Controller P1 &Controle J1 @@ -3652,90 +3714,95 @@ Mova os pontos para mudar a posição, ou clique duas vezes nas células da tabe GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Dados anônimos são recolhidos</a> para ajudar a melhorar o yuzu. <br/><br/>Gostaria de compartilhar os seus dados de uso conosco? - + Telemetry Telemetria - + Loading Web Applet... Carregando applet web... - - + + Disable Web Applet Desativar o applet da web - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Desativar o applet web fará com que ele não apareça novamente até o final da sessão emulada. Isto pode causar comportamento inesperado e só deve ser usado com Super Mario 3D All-Stars. Você deseja mesmo desativar o applet web? - + The amount of shaders currently being built A quantidade de shaders sendo construídos - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocidade atual de emulação. Valores maiores ou menores que 100% indicam que a emulação está rodando mais rápida ou lentamente que em um Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quantos quadros por segundo o jogo está exibindo atualmente. Isto irá variar de jogo para jogo e cena para cena. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo que leva para emular um quadro do Switch, sem considerar o limitador de taxa de quadros ou a sincronização vertical. Um valor menor ou igual a 16.67 ms indica que a emulação está em velocidade plena. - + Invalid config detected Configuração inválida detectada - + Handheld controller can't be used on docked mode. Pro controller will be selected. O controle portátil não pode ser usado no modo encaixado na base. O Pro Controller será selecionado. - + DOCK NA BASE - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Limpar arquivos recentes - - TAS Recording - + + &Continue + &Continuar - - Overwrite file of player 1? - Sobrescrever arquivo do jogador 1? + + &Pause + @@ -3786,657 +3853,724 @@ Mova os pontos para mudar a posição, ou clique duas vezes nas células da tabe Ocorreu um erro desconhecido. Consulte o registro para mais detalhes. - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Iniciar - - - + Save Data Dados de jogos salvos - + Mod Data Dados de mods - + Error Opening %1 Folder Erro ao abrir a pasta %1 - - + + Folder does not exist! A pasta não existe! - + Error Opening Transferable Shader Cache Erro ao abrir o cache de shaders transferível - + Failed to create the shader cache directory for this title. Falha ao criar o diretório de cache de shader para este título. - + Contents Conteúdo - + Update Atualização - + DLC DLC - + Remove Entry Remover item - + Remove Installed Game %1? Remover o jogo instalado %1? - - - - - - + + + + + + Successfully Removed Removido com sucesso - + Successfully removed the installed base game. O jogo base foi removido com sucesso. - - - + + + Error Removing %1 Erro ao remover %1 - + The base game is not installed in the NAND and cannot be removed. O jogo base não está instalado na NAND e não pode ser removido. - + Successfully removed the installed update. A atualização instalada foi removida com sucesso. - + There is no update installed for this title. Não há nenhuma atualização instalada para este título. - + There are no DLC installed for this title. Não há nenhum DLC instalado para este título. - + Successfully removed %1 installed DLC. %1 DLC(s) instalados foram removidos com sucesso. - + Delete OpenGL Transferable Shader Cache? Apagar o cache de shader transferível do OpenGL? - + Delete Vulkan Transferable Shader Cache? Apagar o cache de shader transferível do Vulkan? - + Delete All Transferable Shader Caches? Apagar todos os caches de shader transferíveis? - + Remove Custom Game Configuration? Remover configurações customizadas do jogo? - + Remove File Remover arquivo - - + + Error Removing Transferable Shader Cache Erro ao remover cache de shaders transferível - - + + A shader cache for this title does not exist. Não existe um cache de shaders para este título. - + Successfully removed the transferable shader cache. O cache de shaders transferível foi removido com sucesso. - + Failed to remove the transferable shader cache. Falha ao remover o cache de shaders transferível. - - + + Error Removing Transferable Shader Caches Erro ao remover os caches de shader transferíveis - + Successfully removed the transferable shader caches. Os caches de shader transferíveis foram removidos com sucesso. - + Failed to remove the transferable shader cache directory. Falha ao remover o diretório do cache de shader transferível. - - + + Error Removing Custom Configuration Erro ao remover as configurações customizadas do jogo. - + A custom configuration for this title does not exist. Não há uma configuração customizada para este título. - + Successfully removed the custom game configuration. As configurações customizadas do jogo foram removidas com sucesso. - + Failed to remove the custom game configuration. Falha ao remover as configurações customizadas do jogo. - - + + RomFS Extraction Failed! Falha ao extrair RomFS! - + There was an error copying the RomFS files or the user cancelled the operation. Houve um erro ao copiar os arquivos RomFS ou o usuário cancelou a operação. - + Full Extração completa - + Skeleton Apenas estrutura - + Select RomFS Dump Mode Selecione o modo de extração do RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Selecione a forma como você gostaria que o RomFS seja extraído.<br>"Extração completa" copiará todos os arquivos para a nova pasta, enquanto que <br>"Apenas estrutura" criará apenas a estrutura de pastas. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Extraindo RomFS... - - + + Cancel Cancelar - + RomFS Extraction Succeeded! Extração do RomFS concluida! - + The operation completed successfully. A operação foi concluída com sucesso. - + Error Opening %1 Erro ao abrir %1 - + Select Directory Selecionar pasta - + Properties Propriedades - + The game properties could not be loaded. As propriedades do jogo não puderam ser carregadas. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Executável do Switch (%1);;Todos os arquivos (*.*) - + Load File Carregar arquivo - + Open Extracted ROM Directory Abrir pasta da ROM extraída - + Invalid Directory Selected Pasta inválida selecionada - + The directory you have selected does not contain a 'main' file. A pasta que você selecionou não contém um arquivo 'main'. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Arquivo de Switch instalável (*.nca *.nsp *.xci);; Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Instalar arquivos - + %n file(s) remaining %n arquivo restante%n arquivos restantes - + Installing file "%1"... Instalando arquivo "%1"... - - + + Install Results Resultados da instalação - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Para evitar possíveis conflitos, desencorajamos que os usuários instalem os jogos base na NAND. Por favor, use esse recurso apenas para instalar atualizações e DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Aplicativo do sistema - + System Archive Arquivo do sistema - + System Application Update Atualização de aplicativo do sistema - + Firmware Package (Type A) Pacote de firmware (tipo A) - + Firmware Package (Type B) Pacote de firmware (tipo B) - + Game Jogo - + Game Update Atualização de jogo - + Game DLC DLC de jogo - + Delta Title Título delta - + Select NCA Install Type... Selecione o tipo de instalação do NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Selecione o tipo de título como o qual você gostaria de instalar este NCA: (Na maioria dos casos, o padrão 'Jogo' serve bem.) - + Failed to Install Falha ao instalar - + The title type you selected for the NCA is invalid. O tipo de título que você selecionou para o NCA é inválido. - + File not found Arquivo não encontrado - + File "%1" not found Arquivo "%1" não encontrado - - - &Continue - &Continuar - - - + OK OK - + Missing yuzu Account Conta do yuzu faltando - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Para enviar um caso de teste de compatibilidade de jogo, você precisa entrar com a sua conta do yuzu.<br><br/>Para isso, vá para Emulação &gt; Configurar... &gt; Rede. - + Error opening URL Erro ao abrir URL - + Unable to open the URL "%1". Não foi possível abrir o URL "%1". - + + TAS Recording + Gravando TAS + + + + Overwrite file of player 1? + Sobrescrever arquivo do jogador 1? + + + Amiibo File (%1);; All Files (*.*) Arquivo Amiibo (%1);; Todos os arquivos (*.*) - + Load Amiibo Carregar Amiibo - + Error opening Amiibo data file Erro ao abrir arquivo de dados do Amiibo - + Unable to open Amiibo file "%1" for reading. Não foi possível abrir o arquivo de Amiibo "%1" para leitura. - + Error reading Amiibo data file Erro ao ler arquivo de dados de Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Não foi possível ler completamente os dados do Amiibo. O yuzu esperava ler %1 bytes, mas foi capaz de ler apenas %2 bytes. - + Error loading Amiibo data Erro ao carregar dados do Amiibo - + Unable to load Amiibo data. Não foi possível carregar os dados do Amiibo. - + Capture Screenshot Capturar tela - + PNG Image (*.png) Imagem PNG (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) Compilando: %n shader(s)Compilando: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Velocidade: %1% / %2% - + Speed: %1% Velocidade: %1% - + Game: %1 FPS (Unlocked) Jogo: %1 FPS (Desbloqueado) - + Game: %1 FPS Jogo: %1 FPS - + Frame: %1 ms Quadro: %1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU ALTA - + GPU EXTREME GPU EXTREMA - + GPU ERROR ERRO DE GPU - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + GAUSSIANA + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. O jogo que você está tentando carregar precisa que arquivos adicionais do seu Switch sejam extraídos antes de jogá-lo.<br/><br/>Para saber mais sobre como extrair esses arquivos, visite a seguinte página da wiki: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Extraindo arquivos de sistema e fontes compartilhadas de um Switch</a>.<br/><br/> Gostaria de voltar para a lista de jogos? Continuar com a emulação pode resultar em travamentos, dados salvos corrompidos ou outros problemas. - + yuzu was unable to locate a Switch system archive. %1 O yuzu não foi capaz de encontrar um arquivo de sistema do Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 O yuzu não foi capaz de encontrar um arquivo de sistema do Switch. %1. %2 - + System Archive Not Found Arquivo do sistema não encontrado - + System Archive Missing Arquivo de sistema faltando - + yuzu was unable to locate the Switch shared fonts. %1 O yuzu não foi capaz de encontrar as fontes compartilhadas do Switch. %1 - + Shared Fonts Not Found Fontes compartilhadas não encontradas - + Shared Font Missing Fonte compartilhada faltando - + Fatal Error Erro fatal - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. O yuzu encontrou um erro fatal. Consulte o registro para mais detalhes. Para mais informações sobre como acessar o registro, consulte a seguinte página: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Como enviar o arquivo de registro</a>.<br/><br/>Gostaria de voltar para a lista de jogos? Continuar com a emulação pode resultar em travamentos, dados salvos corrompidos ou outros problemas. - + Fatal Error encountered Erro fatal encontrado - + Confirm Key Rederivation Confirmar rederivação de chave - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4453,37 +4587,37 @@ e opcionalmente faça cópias de segurança. Isto excluirá o seus arquivos de chaves geradas automaticamente, e reexecutar o módulo de derivação de chaves. - + Missing fuses Faltando fusíveis - + - Missing BOOT0 - Faltando BOOT0 - + - Missing BCPKG2-1-Normal-Main - Faltando BCPKG2-1-Normal-Main - + - Missing PRODINFO - Faltando PRODINFO - + Derivation Components Missing Faltando componentes de derivação - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Há componentes faltando que podem impedir a conclusão do processo de derivação de chaves. <br>Por favor, siga <a href='https://yuzu-emu.org/help/quickstart/'>o guia de iniciação rápida</a> para obter todas as suas chaves e jogos. <br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4492,39 +4626,39 @@ Isto pode demorar até um minuto, dependendo do desempenho do seu sistema. - + Deriving Keys Derivando chaves - + Select RomFS Dump Target Selecionar alvo de extração do RomFS - + Please select which RomFS you would like to dump. Selecione qual RomFS você quer extrair. - + Are you sure you want to close yuzu? Você deseja mesmo fechar o yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Deseja mesmo parar a emulação? Qualquer progresso não salvo será perdido. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4536,38 +4670,38 @@ Deseja ignorar isso e sair mesmo assim? GRenderWindow - + OpenGL not available! OpenGL não disponível! - + yuzu has not been compiled with OpenGL support. O yuzu não foi compilado com suporte para OpenGL. - - + + Error while initializing OpenGL! Erro ao inicializar o OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Sua GPU pode não suportar OpenGL, ou você não possui o driver gráfico mais recente. - + Error while initializing OpenGL 4.6! Erro ao inicializar o OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Sua GPU pode não suportar o OpenGL 4.6, ou você não possui os drivers gráficos mais recentes.<br><br>Renderizador GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Sua GPU pode não suportar uma ou mais extensões necessárias do OpenGL. Verifique se você possui a última versão dos drivers gráficos.<br><br>Renderizador GL:<br>%1<br><br>Extensões não suportadas:<br>%2 @@ -4929,190 +5063,205 @@ tela inicial do jogo. &Emulação - + &View &Exibir - + &Reset Window Size &Restaurar tamanho da janela - - Reset Window Size to &720p - Restaurar tamanho da janela para &720p - - - - Reset Window Size to 720p - Restaurar tamanho da janela para 720p - - - - Reset Window Size to &900p - Restaurar tamanho da janela para &900p - - - - Reset Window Size to 900p - Restaurar tamanho da janela para 900p - - - - Reset Window Size to &1080p - Restaurar tamanho da janela para &1080p - - - - Reset Window Size to 1080p - Restaurar tamanho da janela para 1080p - - - + &Debugging &Depurar - + + Reset Window Size to &720p + Restaurar tamanho da janela para &720p + + + + Reset Window Size to 720p + Restaurar tamanho da janela para 720p + + + + Reset Window Size to &900p + Restaurar tamanho da janela para &900p + + + + Reset Window Size to 900p + Restaurar tamanho da janela para 900p + + + + Reset Window Size to &1080p + Restaurar tamanho da janela para &1080p + + + + Reset Window Size to 1080p + Restaurar tamanho da janela para 1080p + + + &Tools &Ferramentas - + + &TAS + + + + &Help &Ajuda - + &Install Files to NAND... &Instalar arquivos na NAND... - + L&oad File... &Carregar arquivo... - + Load &Folder... Carregar &pasta... - + E&xit S&air - - &Start - &Iniciar - - - + &Pause &Pausar - + &Stop &Parar - + &Reinitialize keys... &Reinicializar chaves... - + &About yuzu &Sobre o yuzu - + Single &Window Mode Modo de &janela única - + Con&figure... Con&figurar... - + Display D&ock Widget Headers Exibir barra de títul&os de widgets afixados - + Show &Filter Bar Exibir barra de &filtro - + Show &Status Bar Exibir barra de &status - + Show Status Bar Exibir barra de status - + F&ullscreen &Tela cheia - + &Restart &Reiniciar - + Load &Amiibo... Carregar &amiibo... - + &Report Compatibility &Reportar compatibilidade - + Open &Mods Page Abrir página de &mods - + Open &Quickstart Guide Abrir &guia de início rápido - + &FAQ &Perguntas frequentes - + Open &yuzu Folder Abrir pasta do &yuzu - + &Capture Screenshot &Captura de tela - - Configure &TAS... - Configurar &TAS... + + &Configure TAS... + - + Configure C&urrent Game... Configurar jogo &atual.. + + + &Start + &Iniciar + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5158,10 +5307,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE START/PAUSE + + + Charging + + QObject @@ -5192,142 +5346,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [não definido] - - Hat %1 %2 Direcional %1 %2 - - - - - - + + + + Axis %1%2 Eixo %1%2 - Button %1 Botão %1 - - - + + + [unknown] [desconhecido] - + + Left + + + + + Right + + + - Click 0 - Clique 0 + Down + - - Click 1 - Clique 1 + Up + - - Click 2 - Clique 2 + Z + - - Click 3 - Clique 3 + R + - - Click 4 - Clique 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - Eixo GC %1%2 - - - - GC Button %1 - Botão GC %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Movimento %1 - - - - %1Button %2 + + + + %1%2Axis %3 - - SDL Motion - Movimento do SDL + + %1%2Axis %3,%4,%5 + - - %1Click %2 - %1Clique %2 + + %1%2Motion %3 + - + + + %1%2Button %3 + + + + [unused] [não utilizado] @@ -5368,7 +5602,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5381,7 +5615,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Par de Joycons @@ -5394,7 +5628,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Joycon esquerdo @@ -5407,7 +5641,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Joycon direito @@ -5435,7 +5669,7 @@ p, li { white-space: pre-wrap; } - + Handheld Portátil @@ -5556,7 +5790,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Controle de GameCube @@ -5650,13 +5884,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK OK - + Cancel Cancelar diff --git a/dist/languages/pt_PT.ts b/dist/languages/pt_PT.ts index a55f82bbe..eb58f2718 100644 --- a/dist/languages/pt_PT.ts +++ b/dist/languages/pt_PT.ts @@ -646,7 +646,12 @@ p, li { white-space: pre-wrap; } - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -926,67 +931,78 @@ p, li { white-space: pre-wrap; } Geral - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Percentagem do limitador de velocidade - + % % - + Multicore CPU Emulation Emulação de CPU Multicore - + Confirm exit while emulation is running Confirme a saída enquanto a emulação está em execução - + Prompt for user on game boot Solicitar para o utilizador na inicialização do jogo - + Pause emulation when in background Pausar o emulador quando estiver em segundo plano - + Hide mouse on inactivity Esconder rato quando inactivo. - + Reset All Settings Restaurar todas as configurações - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? Isto restaura todas as configurações e remove as configurações específicas de cada jogo. As pastas de jogos, perfis de jogos e perfis de controlo não serão removidos. Continuar? @@ -1104,18 +1120,113 @@ p, li { white-space: pre-wrap; } Esticar à Janela - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Usar cor de fundo global - + Set background color: Definir cor de fundo: - + Background Color: Cor de fundo: @@ -1184,27 +1295,32 @@ p, li { white-space: pre-wrap; } + Automatic + + + + Default Padrão - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1532,8 +1648,8 @@ p, li { white-space: pre-wrap; } - Other - Outro + Emulated Devices + @@ -1542,66 +1658,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Emular entradas analógicas através de entradas do teclado - - - - Enable mouse panning - - - - - Mouse sensitivity - Sensibilidade do rato - - - - % - - - - - - Advanced - Avançado - - - - Touchscreen - Ecrã Táctil - - - Mouse Rato - - Motion / Touch - Movimento / Toque + + Touchscreen + Ecrã Táctil - - - Configure - Configurar + + Advanced + Avançado - + Debug Controller Controlador de Depuração - + + + Configure + Configurar + + + + Other + Outro + + + + Emulate Analog with Keyboard Input + Emular entradas analógicas através de entradas do teclado + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + Sensibilidade do rato + + + + % + + + + + Motion / Touch + Movimento / Toque + ConfigureInputPlayer @@ -1616,425 +1741,441 @@ p, li { white-space: pre-wrap; } Conectar Comando - - - - Pro Controller - Comando Pro - - - - - Dual Joycons - Joycons Duplos - - - - - Left Joycon - Joycon Esquerdo - - - - - Right Joycon - Joycon Direito - - - - - Handheld - Portátil - - - + Input Device Dispositivo de Entrada - - Any - Qualquer - - - - Keyboard/Mouse - Teclado/Rato - - - + Profile Perfil - + Save Guardar - + New Novo - + Delete Apagar - - + + Left Stick Analógico Esquerdo - - - - - - + + + + + + Up Cima - - - - - - - + + + + + + + Left Esquerda - - - - - - - + + + + + + + Right Direita - - - - - - + + + + + + Down Baixo - - - - + + + + Pressed Premido - - - - + + + + Modifier Modificador - - + + Range Alcance - - + + % % - - + + Deadzone: 0% Ponto Morto: 0% - - + + Modifier Range: 0% Modificador de Alcance: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Menos - - + + Capture Capturar - - - + + + Plus Mais - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Movimento 1 - + Motion 2 Movimento 2 - + Face Buttons Botôes de Rosto - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Analógico Direito - - - - + + + + Clear Limpar - - - - + + + + [not set] [não definido] - - + + Toggle button - - + + Invert button + + + + + + Invert axis + Inverter eixo + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick Mapear analógicos - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Após pressionar OK, mova o seu analógico primeiro horizontalmente e depois verticalmente. Para inverter os eixos, mova o seu analógico primeiro verticalmente e depois horizontalmente. - - Invert axis - Inverter eixo - - - - + + Deadzone: %1% Ponto Morto: %1% - - + + Modifier Range: %1% Modificador de Alcance: %1% - + + + Pro Controller + Comando Pro + + + + Dual Joycons + Joycons Duplos + + + + Left Joycon + Joycon Esquerdo + + + + Right Joycon + Joycon Direito + + + + Handheld + Portátil + + + GameCube Controller Controlador de depuração - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Iniciar / Pausar - + Z Z - + Control Stick - + C-Stick C-Stick - + Shake! Abane! - + [waiting] [em espera] - + New Profile Novo Perfil - + Enter a profile name: Introduza um novo nome de perfil: - - + + Create Input Profile Criar perfil de controlo - + The given profile name is not valid! O nome de perfil dado não é válido! - + Failed to create the input profile "%1" Falha ao criar o perfil de controlo "%1" - + Delete Input Profile Apagar Perfil de Controlo - + Failed to delete the input profile "%1" Falha ao apagar o perfil de controlo "%1" - + Load Input Profile Carregar perfil de controlo - + Failed to load the input profile "%1" Falha ao carregar o perfil de controlo "%1" - + Save Input Profile Guardar perfil de controlo - + Failed to save the input profile "%1" Falha ao guardar o perfil de controlo "%1" @@ -2060,85 +2201,75 @@ Para inverter os eixos, mova o seu analógico primeiro verticalmente e depois ho ConfigureMotionTouch - + Configure Motion / Touch Configurar Movimento / Toque - - Mouse Motion - Movimentação com o rato - - - - Sensitivity: - Sensibilidade: - - - + Touch Toque - + UDP Calibration: Calibração UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Configurar - - Use button mapping: - Usar mapeamento de butões: + + Touch from button profile: + - + CemuhookUDP Config Configurar CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Podes usar qualquer fonte de entrada UDP compatível com Cemuhook para fornecer entradas de toque e movimento. - + Server: Servidor: - + Port: Porta: - + Learn More Saber Mais - - + + Test Testar - + Add Server Adicionar Servidor - + Remove Server Remover Servidor @@ -2148,145 +2279,81 @@ Para inverter os eixos, mova o seu analógico primeiro verticalmente e depois ho <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Saber Mais</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters O número da porta tem caracteres inválidos - + Port has to be in range 0 and 65353 A porta tem que estar entre 0 e 65353 - + IP address is not valid O endereço IP não é válido - + This UDP server already exists - + Unable to add more than 8 servers Não é possível adicionar mais de 8 servidores - + Testing Testando - + Configuring Configurando - + Test Successful Teste Bem-Sucedido - + Successfully received data from the server. Dados recebidos do servidor com êxito. - + Test Failed Teste Falhou - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Não foi possível receber dados válidos do servidor.<br>Por favor verifica que o servidor está configurado correctamente e o endereço e porta estão correctos. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Teste UDP ou configuração de calibragem em progresso.<br> Por favor espera que termine. - - ConfigureMouseAdvanced - - - Configure Mouse - Configurar Rato - - - - Mouse Buttons - Botões do Rato - - - - Forward: - Frente: - - - - Back: - Atrás: - - - - Left: - Esquerda: - - - - Middle: - Meio: - - - - Right: - Direita: - - - - - Clear - Limpar - - - - Defaults - Padrões - - - - [not set] - [não configurado] - - - - Restore Default - Restaurar Padrões - - - - [press key] - [pressiona a tecla] - - ConfigureNetwork @@ -3070,31 +3137,26 @@ Para inverter os eixos, mova o seu analógico primeiro verticalmente e depois ho - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3107,7 +3169,7 @@ Para inverter os eixos, mova o seu analógico primeiro verticalmente e depois ho - + Select TAS Load Directory... @@ -3169,37 +3231,37 @@ Arrasta os pontos para mudar a posição, ou dá duplo-clique nas células da ta Y - + New Profile Novo Perfil - + Enter the name for the new profile. Escreve o nome para o novo perfil. - + Delete Profile Apagar Perfil - + Delete profile %1? Apagar perfil %1? - + Rename Profile Renomear Perfil - + New name: Novo nome: - + [press key] [premir tecla] @@ -3619,12 +3681,12 @@ Arrasta os pontos para mudar a posição, ou dá duplo-clique nas células da ta ControllerDialog - + Controller P1 Comando J1 - + &Controller P1 &Comando J1 @@ -3632,89 +3694,94 @@ Arrasta os pontos para mudar a posição, ou dá duplo-clique nas células da ta GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Dados anônimos são coletados</a>para ajudar a melhorar o yuzu.<br/><br/>Gostaria de compartilhar seus dados de uso conosco? - + Telemetry Telemetria - + Loading Web Applet... A Carregar o Web Applet ... - - + + Disable Web Applet Desativar Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Desativar o Web Applet fará com que ele não apareça novamente até o final da sessão emulada. Isto pode causar comportamento inesperado e só deve ser usado com Super Mario 3D All-Stars. Tem a certeza que quer desativar o Web Applet? - + The amount of shaders currently being built Quantidade de shaders a serem construídos - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocidade da emulação actual. Valores acima ou abaixo de 100% indicam que a emulação está sendo executada mais depressa ou mais devagar do que a Switch - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quantos quadros por segundo o jogo está exibindo de momento. Isto irá variar de jogo para jogo e de cena para cena. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo gasto para emular um frame da Switch, sem contar o a limitação de quadros ou o v-sync. Para emulação de velocidade máxima, esta deve ser no máximo 16.67 ms. - + Invalid config detected Configação inválida detectada - + Handheld controller can't be used on docked mode. Pro controller will be selected. O comando portátil não pode ser usado no modo encaixado na base. O Pro controller será selecionado. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Limpar arquivos recentes - - TAS Recording - + + &Continue + &Continuar - - Overwrite file of player 1? + + &Pause @@ -3766,657 +3833,724 @@ Arrasta os pontos para mudar a posição, ou dá duplo-clique nas células da ta Ocorreu um erro desconhecido. Por favor, veja o log para mais detalhes. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Começar - - - + Save Data Save Data - + Mod Data Mod Data - + Error Opening %1 Folder Erro ao abrir a pasta %1 - - + + Folder does not exist! A Pasta não existe! - + Error Opening Transferable Shader Cache Erro ao abrir os Shader Cache transferíveis - + Failed to create the shader cache directory for this title. - + Contents Conteúdos - + Update Actualização - + DLC DLC - + Remove Entry Remover Entrada - + Remove Installed Game %1? Remover Jogo Instalado %1? - - - - - - + + + + + + Successfully Removed Removido com Sucesso - + Successfully removed the installed base game. Removida a instalação do jogo base com sucesso. - - - + + + Error Removing %1 Erro ao Remover %1 - + The base game is not installed in the NAND and cannot be removed. O jogo base não está instalado no NAND e não pode ser removido. - + Successfully removed the installed update. Removida a actualização instalada com sucesso. - + There is no update installed for this title. Não há actualização instalada neste título. - + There are no DLC installed for this title. Não há DLC instalado neste título. - + Successfully removed %1 installed DLC. Removido DLC instalado %1 com sucesso. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Remover Configuração Personalizada do Jogo? - + Remove File Remover Ficheiro - - + + Error Removing Transferable Shader Cache Error ao Remover Cache de Shader Transferível - - + + A shader cache for this title does not exist. O Shader Cache para este titulo não existe. - + Successfully removed the transferable shader cache. Removido a Cache de Shader Transferível com Sucesso. - + Failed to remove the transferable shader cache. Falha ao remover a cache de shader transferível. - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Erro ao Remover Configuração Personalizada - + A custom configuration for this title does not exist. Não existe uma configuração personalizada para este titúlo. - + Successfully removed the custom game configuration. Removida a configuração personalizada do jogo com sucesso. - + Failed to remove the custom game configuration. Falha ao remover a configuração personalizada do jogo. - - + + RomFS Extraction Failed! A Extração de RomFS falhou! - + There was an error copying the RomFS files or the user cancelled the operation. Houve um erro ao copiar os arquivos RomFS ou o usuário cancelou a operação. - + Full Cheio - + Skeleton Esqueleto - + Select RomFS Dump Mode Selecione o modo de despejo do RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Por favor, selecione a forma como você gostaria que o RomFS fosse despejado<br>Full irá copiar todos os arquivos para o novo diretório enquanto<br>skeleton criará apenas a estrutura de diretórios. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Extraindo o RomFS ... - - + + Cancel Cancelar - + RomFS Extraction Succeeded! Extração de RomFS Bem-Sucedida! - + The operation completed successfully. A operação foi completa com sucesso. - + Error Opening %1 Erro ao abrir %1 - + Select Directory Selecione o Diretório - + Properties Propriedades - + The game properties could not be loaded. As propriedades do jogo não puderam ser carregadas. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Executáveis Switch (%1);;Todos os Ficheiros (*.*) - + Load File Carregar Ficheiro - + Open Extracted ROM Directory Abrir o directório ROM extraído - + Invalid Directory Selected Diretório inválido selecionado - + The directory you have selected does not contain a 'main' file. O diretório que você selecionou não contém um arquivo 'Main'. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Ficheiro Switch Instalável (*.nca *.nsp *.xci);;Arquivo de Conteúdo Nintendo (*.nca);;Pacote de Envio Nintendo (*.nsp);;Imagem de Cartucho NX (*.xci) - + Install Files Instalar Ficheiros - + %n file(s) remaining - + Installing file "%1"... Instalando arquivo "%1"... - - + + Install Results Instalar Resultados - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Para evitar possíveis conflitos, desencorajamos que os utilizadores instalem os jogos base na NAND. Por favor, use esse recurso apenas para instalar atualizações e DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Aplicação do sistema - + System Archive Arquivo do sistema - + System Application Update Atualização do aplicativo do sistema - + Firmware Package (Type A) Pacote de Firmware (Tipo A) - + Firmware Package (Type B) Pacote de Firmware (Tipo B) - + Game Jogo - + Game Update Actualização do Jogo - + Game DLC DLC do Jogo - + Delta Title Título Delta - + Select NCA Install Type... Selecione o tipo de instalação do NCA ... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Por favor, selecione o tipo de título que você gostaria de instalar este NCA como: (Na maioria dos casos, o padrão 'Jogo' é suficiente). - + Failed to Install Falha na instalação - + The title type you selected for the NCA is invalid. O tipo de título que você selecionou para o NCA é inválido. - + File not found Arquivo não encontrado - + File "%1" not found Arquivo "%1" não encontrado - - - &Continue - &Continuar - - - + OK OK - + Missing yuzu Account Conta Yuzu Ausente - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Para enviar um caso de teste de compatibilidade de jogos, você deve vincular sua conta yuzu.<br><br/>Para vincular sua conta yuzu, vá para Emulação &gt; Configuração &gt; Rede. - + Error opening URL Erro ao abrir URL - + Unable to open the URL "%1". Não foi possível abrir o URL "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Arquivo Amiibo (%1);; Todos os Arquivos (*.*) - + Load Amiibo Carregar Amiibo - + Error opening Amiibo data file Erro ao abrir o arquivo de dados do Amiibo - + Unable to open Amiibo file "%1" for reading. Não é possível abrir o arquivo Amiibo "%1" para leitura. - + Error reading Amiibo data file Erro ao ler o arquivo de dados do Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Não é possível ler completamente os dados do Amiibo. Espera-se que leia %1 bytes, mas só conseguiu ler %2 bytes. - + Error loading Amiibo data Erro ao carregar dados do Amiibo - + Unable to load Amiibo data. Não foi possível carregar os dados do Amiibo. - + Capture Screenshot Captura de Tela - + PNG Image (*.png) Imagem PNG (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Velocidade: %1% / %2% - + Speed: %1% Velocidade: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Jogo: %1 FPS - + Frame: %1 ms Quadro: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. O jogo que você está tentando carregar requer arquivos adicionais do seu Switch para serem despejados antes de jogar.<br/><br/>Para obter mais informações sobre como despejar esses arquivos, consulte a seguinte página da wiki:<a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Despejando arquivos do sistema e as fontes compartilhadas de uma consola Switch</a>.<br/><br/>Você gostaria de regressar para a lista de jogos? Continuar a emulação pode resultar em falhas, dados de salvamento corrompidos ou outros erros. - + yuzu was unable to locate a Switch system archive. %1 O yuzu não conseguiu localizar um arquivo de sistema do Switch. % 1 - + yuzu was unable to locate a Switch system archive: %1. %2 O yuzu não conseguiu localizar um arquivo de sistema do Switch: %1. %2 - + System Archive Not Found Arquivo do Sistema Não Encontrado - + System Archive Missing Arquivo de Sistema em falta - + yuzu was unable to locate the Switch shared fonts. %1 yuzu não conseguiu localizar as fontes compartilhadas do Switch. %1 - + Shared Fonts Not Found Fontes compartilhadas não encontradas - + Shared Font Missing Fontes compartilhadas em falta - + Fatal Error Erro fatal - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu encontrou um erro fatal, por favor veja o registro para mais detalhes. Para mais informações sobre como acessar o registro, por favor, veja a seguinte página:<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Como carregar o arquivo de registro</a>.<br/><br/>Você gostaria de regressar para a lista de jogos? Continuar a emulação pode resultar em falhas, dados de salvamento corrompidos ou outros erros. - + Fatal Error encountered Ocorreu um Erro fatal - + Confirm Key Rederivation Confirme a rederivação da chave - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4433,37 +4567,37 @@ e opcionalmente faça backups. Isso irá excluir os seus arquivos de chave gerados automaticamente e executará novamente o módulo de derivação de chave. - + Missing fuses Fusíveis em Falta - + - Missing BOOT0 - BOOT0 em Falta - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Main em Falta - + - Missing PRODINFO - PRODINFO em Falta - + Derivation Components Missing Componentes de Derivação em Falta - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Estão componentes em falta que podem dificultar a conclusão da derivação das chaves. <br>Por favor segue<a href='https://yuzu-emu.org/help/quickstart/'>o guia de início rápido do yuzu</a>para obteres todos os teus jogos e chaves.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4472,39 +4606,39 @@ Isto pode demorar até um minuto, dependendo do desempenho do seu sistema. - + Deriving Keys Derivando Chaves - + Select RomFS Dump Target Selecione o destino de despejo do RomFS - + Please select which RomFS you would like to dump. Por favor, selecione qual o RomFS que você gostaria de despejar. - + Are you sure you want to close yuzu? Tem a certeza que quer fechar o yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Tem a certeza de que quer parar a emulação? Qualquer progresso não salvo será perdido. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4516,38 +4650,38 @@ Deseja ignorar isso e sair mesmo assim? GRenderWindow - + OpenGL not available! OpenGL não está disponível! - + yuzu has not been compiled with OpenGL support. yuzu não foi compilado com suporte OpenGL. - - + + Error while initializing OpenGL! Erro ao inicializar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. O seu GPU pode não suportar OpenGL, ou não tem os drivers gráficos mais recentes. - + Error while initializing OpenGL 4.6! Erro ao inicializar o OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 O teu GPU pode não suportar OpenGL 4.6, ou não tem os drivers gráficos mais recentes. - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4908,190 +5042,205 @@ Inicial &Emulação - + &View &Vista - + &Reset Window Size - - Reset Window Size to &720p - Restaurar tamanho da janela para &720p - - - - Reset Window Size to 720p - Restaurar tamanho da janela para 720p - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - Restaurar tamanho da janela para &1080p - - - - Reset Window Size to 1080p - Restaurar tamanho da janela para 1080p - - - + &Debugging - + + Reset Window Size to &720p + Restaurar tamanho da janela para &720p + + + + Reset Window Size to 720p + Restaurar tamanho da janela para 720p + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + Restaurar tamanho da janela para &1080p + + + + Reset Window Size to 1080p + Restaurar tamanho da janela para 1080p + + + &Tools &Ferramentas - + + &TAS + + + + &Help &Ajuda - + &Install Files to NAND... &Instalar arquivos na NAND... - + L&oad File... C&arregar arquivo... - + Load &Folder... Carregar &pasta... - + E&xit &Sair - - &Start - &Começar - - - + &Pause &Pausa - + &Stop &Parar - + &Reinitialize keys... &Reinicializar chaves... - + &About yuzu &Sobre o yuzu - + Single &Window Mode Modo de &janela única - + Con&figure... Con&figurar... - + Display D&ock Widget Headers - + Show &Filter Bar Mostrar Barra de &Filtros - + Show &Status Bar Mostrar Barra de &Estado - + Show Status Bar Mostrar Barra de Estado - + F&ullscreen T&ela cheia - + &Restart &Reiniciar - + Load &Amiibo... Carregar &Amiibo... - + &Report Compatibility - + Open &Mods Page Abrir Página de &Mods - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder Abrir pasta &yuzu - + &Capture Screenshot &Captura de Tela - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... Configurar jogo atual... + + + &Start + &Começar + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5133,10 +5282,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5167,142 +5321,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [não configurado] - - Hat %1 %2 Hat %1 %2 - - - - - - + + + + Axis %1%2 Eixo %1%2 - Button %1 Botão %1 - - - + + + [unknown] [Desconhecido] - + + Left + + + + + Right + + + - Click 0 - Clique 0 + Down + - - Click 1 - Clique 1 + Up + - - Click 2 - Clique 2 + Z + - - Click 3 - Clique 3 + R + - - Click 4 - Clique 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 - - GC Axis %1%2 - GC Eixo %1%2 - - - - GC Button %1 - GC Butão %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 + + + + %1%2Axis %3 - - %1Button %2 + + %1%2Axis %3,%4,%5 - - SDL Motion + + %1%2Motion %3 - - %1Click %2 + + + %1%2Button %3 - + [unused] [sem uso] @@ -5343,7 +5577,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5356,7 +5590,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Par de Joycons @@ -5369,7 +5603,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Joycon Esquerdo @@ -5382,7 +5616,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Joycon Direito @@ -5410,7 +5644,7 @@ p, li { white-space: pre-wrap; } - + Handheld Portátil @@ -5531,7 +5765,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5615,13 +5849,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts index ef9c958a2..d1e9c313a 100644 --- a/dist/languages/ru_RU.ts +++ b/dist/languages/ru_RU.ts @@ -87,18 +87,18 @@ p, li { white-space: pre-wrap; } Report Compatibility - Сообщить о Совместимости + Сообщить о совместимости Report Game Compatibility - Сообщить о Совместимости Игры + Сообщить о совместимости игры <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html> - <html><head/><body><p><span style=" font-size:10pt;">Если вы захотите отправить отчёт в </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Список Совместимости yuzu</a><span style=" font-size:10pt;">, следующая информация будет собрана и отображена на сайте:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Информация о железе (ЦП / ГП / Операционная Система)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Версия yuzu</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Подключённый аккаунт yuzu</li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;">Если вы захотите отправить отчёт в </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">список совместимости yuzu</a><span style=" font-size:10pt;">, следующая информация будет собрана и отображена на сайте:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Информация о железе (ЦП / ГП / Операционная система)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Версия yuzu</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Подключённый аккаунт yuzu</li></ul></body></html> @@ -108,7 +108,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - <html><head/><body><p>Игра функционирует отлично, без звуковых или графических артефактов.</p></body></html> + <html><head/><body><p>Игра работает отлично, без звуковых или графических артефактов.</p></body></html> @@ -138,7 +138,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - <html><head/><body><p>Игра работает, но с существенными графическими или звуковыми артефактами. В некоторых зонах нельзя продвинуться даже с обходными путями.</p></body></html> + <html><head/><body><p>Игра работает, но с существенными графическими или звуковыми артефактами. В некоторых местах невозможно пройти даже с обходными путями.</p></body></html> @@ -148,7 +148,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - <html><head/><body><p>В игру невозможно играть из-за графических или звуковых артефактов. Невозможно продвинуться дальше Стартового Экрана.</p></body></html> + <html><head/><body><p>В игру невозможно играть из-за графических или звуковых артефактов. Невозможно продвинуться дальше стартового меню.</p></body></html> @@ -276,12 +276,12 @@ p, li { white-space: pre-wrap; } We recommend setting accuracy to "Auto". - Мы рекомендуем установить точность на "Точно". + Мы рекомендуем установить точность на "Авто". Unsafe CPU Optimization Settings - Небезопасные Настройки Оптимизации ЦП + Небезопасные настройки оптимизации ЦП @@ -294,7 +294,7 @@ p, li { white-space: pre-wrap; } <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> - <div>Эта опция позволяет улучшить скорость уменьшая точность сложенных умноженных инструкций на ЦП без родной поддержки FMA.</div> + <div>Эта опция повышает скорость, уменьшая точность сложенных умноженных инструкций на ЦП без родной поддержки FMA.</div> @@ -308,7 +308,7 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> - <div>Эта опция улучшает скорость работы некоторых функций с плавающей запятой за счет использования менее точных нативных приближений.</div> + <div>Эта опция повышает скорость работы некоторых функций с плавающей запятой за счет использования менее точных родных приближений.</div> @@ -322,7 +322,7 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - <div>Эта опция улучшает скорость работы 32-битных ASIMD-функций с плавающей запятой, за счёт неправильных режимамов округления.</div> + <div>Эта опция повышает скорость работы 32-битных ASIMD-функций с плавающей запятой, работая с неправильными режимами округления.</div> @@ -336,13 +336,13 @@ p, li { white-space: pre-wrap; } <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> - <div>Эта опция улучшает скорость убрав проверку NaN. Учтите, что это также снижает точность некоторых инструкций с плавающей точкой. </div> + <div>Эта опция повышает скорость, убирая проверку NaN. Обратите внимание, что это также снижает точность некоторых инструкций с плавающей точкой. </div> Inaccurate NaN handling - Неточная обработка NaN + Неправильная обработка NaN @@ -350,7 +350,7 @@ p, li { white-space: pre-wrap; } <div>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.</div> - <div>Эта опция повышает скорость работы за счет устранения проверки безопасности перед каждым чтением/записью памяти в гостя. Отключение этой опции может позволить игре читать/записывать память эмулятора.</div> + <div>Эта опция повышает скорость работы за счет устранения проверки безопасности перед каждым чтением/записью памяти у гостя. Отключение этой опции может позволить игре читать/записывать память эмулятора.</div> @@ -379,12 +379,12 @@ p, li { white-space: pre-wrap; } Toggle CPU Optimizations - Переключить оптимизацию ЦП + Включить оптимизации ЦП <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Только для отладки.</span><br/>Если вы не уверены в том, что они делают, оставьте все эти параметры включенными. <br/>Эти параметры, когда отключены, вступают в силу только при включенной отладке процессора. </p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Только для отладки.</span><br/>Если вы не уверены в том, что они делают, оставьте все эти параметры включенными. <br/>Когда отключены, эти параметры вступают в силу только при включенной отладке ЦП. </p></body></html> @@ -520,7 +520,7 @@ p, li { white-space: pre-wrap; } Enable Host MMU Emulation - Включить Эмуляцию MMU Хоста + Включить эмуляцию MMU хоста @@ -538,17 +538,17 @@ p, li { white-space: pre-wrap; } Global Log Filter - Глобальный Фильтр Журнала + Глобальный фильтр журналов Show Log in Console - Показывать Журнал в Консоли + Показывать журнал в консоли Open Log Location - Открыть Расположение Журнала + Открыть папку для журналов @@ -558,7 +558,7 @@ p, li { white-space: pre-wrap; } Enable Extended Logging** - Включить расширенное ведение Журнала** + Включить расширенное ведение журнала** @@ -568,7 +568,7 @@ p, li { white-space: pre-wrap; } Arguments String - Строка Аргументов + Строка аргументов @@ -578,17 +578,17 @@ p, li { white-space: pre-wrap; } When checked, the graphics API enters a slower debugging mode - Когда выбрано, графический API переходит в более медленный режим отладки + Когда включено, графический API переходит в более медленный режим отладки Enable Graphics Debugging - Включить Отладку Графики + Включить отладку графики When checked, it enables Nsight Aftermath crash dumps - Если флажок установлен, он включает дампы крашей Nsight Aftermath + Если флажок установлен, включает дампы крашей Nsight Aftermath @@ -613,7 +613,7 @@ p, li { white-space: pre-wrap; } Enable Shader Feedback - Включить Обратную Связь о Шейдерах + Включить обратную связь о шейдерах @@ -623,7 +623,7 @@ p, li { white-space: pre-wrap; } Disable Loop safety checks - Отключить проверку безопасности Цикла + Отключить проверку безопасности цикла @@ -633,12 +633,12 @@ p, li { white-space: pre-wrap; } Enable FS Access Log - Включить Журнал Доступа к FS + Включить журнал доступа к FS Enable Verbose Reporting Services** - Включить Службу Отчетов в развернутом виде** + Включить службу отчётов в развернутом виде** @@ -648,17 +648,17 @@ p, li { white-space: pre-wrap; } Kiosk (Quest) Mode - Режим Киоска (Квест) + Режим киоска (Квест) Enable CPU Debugging - Включить Отладку ЦП + Включить отладку ЦП Enable Debug Asserts - Включить Отладочные Сигналы + Включить отладочные сигналы @@ -666,7 +666,12 @@ p, li { white-space: pre-wrap; } Включить Автоподставку** - + + Enable all Controller Types + Включить все типы контроллеров + + + **This will be reset automatically when yuzu closes. **Это будет автоматически сброшено после закрытия yuzu. @@ -676,7 +681,7 @@ p, li { white-space: pre-wrap; } Configure Debug Controller - Настройка Отладочного Контроллера + Настройка отладочного контроллера @@ -784,7 +789,7 @@ p, li { white-space: pre-wrap; } Game List - Список Игр + Список игр @@ -807,7 +812,7 @@ p, li { white-space: pre-wrap; } Storage Directories - Пути Хранилища + Пути хранилища @@ -846,17 +851,17 @@ p, li { white-space: pre-wrap; } Current Game - Текущая Игра + Текущая игра Patch Manager - Управление Патчами + Управление патчами Dump Decompressed NSOs - Дамп Распакованных NCO + Дамп распакованных NSO @@ -871,7 +876,7 @@ p, li { white-space: pre-wrap; } Dump Root - Корень Дампа + Корень дампа @@ -881,7 +886,7 @@ p, li { white-space: pre-wrap; } Cache Game List Metadata - Кэшировать Метаданные Списка Игр + Кэшировать метаданные списка игр @@ -889,7 +894,7 @@ p, li { white-space: pre-wrap; } Reset Metadata Cache - Сбросить Кэш Метаданных + Сбросить кэш метаданных @@ -946,69 +951,80 @@ p, li { white-space: pre-wrap; } Общие - - Framerate Cap - Ограничение частоты кадров + + + Use global framerate cap + Использовать глобальное ограничение частоты кадров - + + Set framerate cap: + Установить ограничение частоты кадров: + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. Для вступления в силу требуется использование горячей клавиши FPS Limiter Toggle. - + + Framerate Cap + Ограничение частоты кадров + + + x x - + Limit Speed Percent - Ограничить Скорость в Процентах + Ограничение cкорости в процентах - + % % - + Multicore CPU Emulation - Многоядерная Эмуляция ЦП + Многоядерная эмуляция ЦП - + Confirm exit while emulation is running Подтверждать выход во время эмуляции - + Prompt for user on game boot Спрашивать пользователя при запуске игры - + Pause emulation when in background Приостанавливать эмуляцию в фоновом режиме - + Hide mouse on inactivity Спрятать мышь при неактивности - + Reset All Settings - Сбросить Все Настройки + Сбросить все настройки - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? - Это сбросит все настройки и удалит все конфигурации под отдельные игры. При этом не будут удалены каталоги игр, профили или профили ввода. Продолжить? + Это сбросит все настройки и удалит все конфигурации под отдельные игры. При этом не будут удалены пути для игр, профили или профили ввода. Продолжить? @@ -1031,7 +1047,7 @@ p, li { white-space: pre-wrap; } Shader Backend: - Бэкенд Шейдеров: + Бэкенд шейдеров: @@ -1046,7 +1062,7 @@ p, li { white-space: pre-wrap; } Graphics Settings - Настройки Графики + Настройки графики @@ -1086,7 +1102,7 @@ p, li { white-space: pre-wrap; } Fullscreen Mode: - Полноэкранный Режим: + Полноэкранный режим: @@ -1101,7 +1117,7 @@ p, li { white-space: pre-wrap; } Aspect Ratio: - Соотношение Сторон: + Соотношение сторон: @@ -1121,23 +1137,118 @@ p, li { white-space: pre-wrap; } Stretch to Window - Расстянуть до Окна + Растянуть до окна - - + + Resolution: + Разрешение: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [ЭКСПЕРИМЕНТАЛЬНО] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [ЭКСПЕРИМЕНТАЛЬНО] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + Фильтр адаптации окна + + + + Nearest Neighbor + Ближайший сосед + + + + Bilinear + Билинейный + + + + Bicubic + Бикубический + + + + Gaussian + Гаусс + + + + ScaleForce + ScaleForce + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + AMD FidelityFX™️ Super Resolution [Только Vulkan] + + + + Anti-Aliasing Method: + Метод сглаживания: + + + + None + Выкл. + + + + FXAA + FXAA + + + + Use global background color Использовать общий фоновый цвет - + Set background color: Установить фоновый цвет: - + Background Color: - Фоновый Цвет: + Фоновый цвет: @@ -1160,12 +1271,12 @@ p, li { white-space: pre-wrap; } Advanced Graphics Settings - Расширенные Настройки Графики + Расширенные настройки графики Accuracy Level: - Уровень Точности: + Уровень точности: @@ -1204,28 +1315,33 @@ p, li { white-space: pre-wrap; } + Automatic + Автоматически + + + Default Стандартная - - - 2x (WILL BREAK THINGS) - 2x (НЕСТАБИЛЬНО) - - 4x (WILL BREAK THINGS) - 4x (НЕСТАБИЛЬНО) + 2x + 2x - 8x (WILL BREAK THINGS) - 8x (НЕСТАБИЛЬНО) + 4x + 4x - 16x (WILL BREAK THINGS) - 16x (НЕСТАБИЛЬНО) + 8x + 8x + + + + 16x + 16x @@ -1552,8 +1668,8 @@ p, li { white-space: pre-wrap; } - Other - Другое + Emulated Devices + Эмулируемые устройства @@ -1562,66 +1678,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Эмуляция аналогового ввода с клавиатуры - - - - Enable mouse panning - Включить панорамирование мыши - - - - Mouse sensitivity - Чувствительность мыши - - - - % - % - - - - - Advanced - Дополнительно - - - - Touchscreen - Сенсорный Экран - - - Mouse Мышь - - Motion / Touch - Движение / Нажатие + + Touchscreen + Сенсорный Экран - - - Configure - Настроить + + Advanced + Дополнительно - + Debug Controller Отладочный Контроллер - + + + Configure + Настроить + + + + Other + Другое + + + + Emulate Analog with Keyboard Input + Эмуляция аналогового ввода с клавиатуры + + + Requires restarting yuzu Требует перезапуск yuzu - + Enable XInput 8 player support (disables web applet) Включить поддержку 8-и игроков на XInput (отключает веб-апплет) + + + Enable UDP controllers (not needed for motion) + Включить UDP контроллеры (не обязательно для движения) + + + + Enable mouse panning + Включить панорамирование мыши + + + + Mouse sensitivity + Чувствительность мыши + + + + % + % + + + + Motion / Touch + Движение / Нажатие + ConfigureInputPlayer @@ -1636,425 +1761,441 @@ p, li { white-space: pre-wrap; } Подключить Контроллер - - - - Pro Controller - Контроллер Pro - - - - - Dual Joycons - Двойные Joycon'ы - - - - - Left Joycon - Левый Joycon - - - - - Right Joycon - Правый Joycon - - - - - Handheld - Портативный - - - + Input Device Устройство Ввода - - Any - Любой - - - - Keyboard/Mouse - Клавиатура/Мышь - - - + Profile Профиль - + Save Сохранить - + New Новый - + Delete Удалить - - + + Left Stick Левый Стик - - - - - - + + + + + + Up Вверх - - - - - - - + + + + + + + Left Влево - - - - - - - + + + + + + + Right Вправо - - - - - - + + + + + + Down Вниз - - - - + + + + Pressed Нажато - - - - + + + + Modifier Модификатор - - + + Range Диапазон - - + + % % - - + + Deadzone: 0% Мёртвая зона: 0% - - + + Modifier Range: 0% Диапазон Модификатора: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Минус - - + + Capture Захват - - - + + + Plus Плюс - - + + Home Домой - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Движение 1 - + Motion 2 Движение 2 - + Face Buttons Основные Кнопки - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Правый Стик - - - - + + + + Clear Очистить - - - - + + + + [not set] [не задано] - - + + Toggle button Переключить кнопку - - + + Invert button + Инвертировать кнопку + + + + + Invert axis + Инвертировать оси + + + + Set threshold Установить порог - + Choose a value between 0% and 100% Выберите значение между 0% и 100% - + Map Analog Stick Задать Аналоговый Стик - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. После нажатия на ОК, двигайте ваш джойстик горизонтально, а затем вертикально. Чтобы инвертировать оси, сначала двигайте ваш джойстик вертикально, а затем горизонтально. - - Invert axis - Инвертировать оси - - - - + + Deadzone: %1% Мёртвая зона: %1% - - + + Modifier Range: %1% Диапазон Модификатора: %1% - + + + Pro Controller + Контроллер Pro + + + + Dual Joycons + Двойные Joycon'ы + + + + Left Joycon + Левый Joycon + + + + Right Joycon + Правый Joycon + + + + Handheld + Портативный + + + GameCube Controller Контроллер GameCube - + + Poke Ball Plus + Poke Ball Plus + + + + NES Controller + Контроллер NES + + + + SNES Controller + Контроллер SNES + + + + N64 Controller + Контроллер N64 + + + + Sega Genesis + Sega Genesis + + + Start / Pause Старт / Пауза - + Z Z - + Control Stick Управляющий Стик - + C-Stick C-Стик - + Shake! Встряхните! - + [waiting] [ожидание] - + New Profile Новый Профиль - + Enter a profile name: Введите имя профиля: - - + + Create Input Profile Создать Профиль Управления - + The given profile name is not valid! Заданное имя профиля недействительно! - + Failed to create the input profile "%1" Не удалось создать профиль управления "%1" - + Delete Input Profile Удалить Профиль Управления - + Failed to delete the input profile "%1" Не удалось удалить профиль управления "%1" - + Load Input Profile Загрузить профиль управления - + Failed to load the input profile "%1" Не удалось загрузить профиль управления "%1" - + Save Input Profile Сохранить Профиль Управления - + Failed to save the input profile "%1" Не удалось сохранить профиль управления "%1" @@ -2080,85 +2221,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch Настроить Движение / Нажатие - - Mouse Motion - Движение Мыши - - - - Sensitivity: - Чувствительность: - - - + Touch Нажатие - + UDP Calibration: Калибрация UDP: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Настроить - - Use button mapping: - Использовать привязки кнопок: + + Touch from button profile: + Коснитесь из профиля кнопки: - + CemuhookUDP Config Настройка CemuhookUDP - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Вы можете использовать любой совместимый с Cemuhook ввод UDP для движения и нажатий - + Server: Сервер: - + Port: Порт: - + Learn More Узнать Больше - - + + Test Тест - + Add Server Добавить Сервер - + Remove Server Удалить Сервер @@ -2168,145 +2299,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Узнать Больше</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Номер порта содержит недопустимые символы - + Port has to be in range 0 and 65353 Порт должен быть в районе от 0 до 65353 - + IP address is not valid IP-адрес недействителен - + This UDP server already exists Этот UDP сервер уже существует - + Unable to add more than 8 servers Невозможно добавить более 8 серверов - + Testing Тестирование - + Configuring Настройка - + Test Successful Тест Успешен - + Successfully received data from the server. Успешно получена информация с сервера - + Test Failed Тест Провален - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Не удалось получить действительные данные с сервера.<br>Убедитесь, что сервер правильно настроен, а также проверьте адрес и порт. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. Тест UDP или калибрация в процессе.<br>Пожалуйста, подождите завершения. - - ConfigureMouseAdvanced - - - Configure Mouse - Настроить Мышь - - - - Mouse Buttons - Кнопки на Мыши - - - - Forward: - Передняя: - - - - Back: - Задняя: - - - - Left: - Левая: - - - - Middle: - Средняя: - - - - Right: - Правая: - - - - - Clear - Очистить - - - - Defaults - По умолчанию - - - - [not set] - [не задано] - - - - Restore Default - Вернуть настройки по умолчанию - - - - [press key] - [нажмите кнопку] - - ConfigureNetwork @@ -2410,7 +2477,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Adv. Graphics - + Расш. Графика @@ -2594,12 +2661,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Error resizing user image - + Ошибка при изменении размера изображения пользователя Unable to resize image - + Невозможно изменить размер изображения @@ -3028,7 +3095,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< d MMM yyyy h:mm:ss AP - д МММ гггг ч:мм:сс AP + d MMM yyyy h:mm:ss AP @@ -3090,31 +3157,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - Автоматическая замена профиля контроллера - - - Loop script Зациклить скрипт - + Pause execution during loads Приостановить выполнение во время загрузки - + Script Directory Папка для скриптов - + Path Путь - + ... ... @@ -3127,7 +3189,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Настройка TAS - + Select TAS Load Directory... Выбрать папку загрузки TAS... @@ -3189,37 +3251,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile Новый Профиль - + Enter the name for the new profile. Введите имя вашего нового профиля. - + Delete Profile Удалить Профиль - + Delete profile %1? Удалить профиль %1? - + Rename Profile Переименовать Профиль - + New name: Новое название: - + [press key] [нажмите кнопку] @@ -3639,12 +3701,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 Контроллер P1 - + &Controller P1 &Контроллер P1 @@ -3652,90 +3714,95 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Анонимные данные собираются</a> для улучшения yuzu. <br/><br/>Хотели бы вы делиться данными об использовании с нами? - + Telemetry Телеметрия - + Loading Web Applet... Загрузка Веб-Апплета... - - + + Disable Web Applet Отключить Веб-Апплет - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Отключение веб-апплета приведет к тому, что он больше не будет появляться до конца текущей сессии эмуляции. Это может привести к неожиданному поведению и должно использоваться только в Super Mario 3D All-Stars. Вы уверены, что хотите отключить веб-апплет? - + The amount of shaders currently being built Количество создаваемых шейдеров на данный момент - + + The current selected resolution scaling multiplier. + Текущий выбранный множитель масштабирования разрешения. + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Текущая скорость эмуляции. Значения выше или ниже 100% указывают на то, что эмуляция идет быстрее или медленнее, чем на Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Количество кадров в секунду в данный момент. Значение будет меняться от игры к игре и от сцене к сцене. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Время, которое нужно для эмуляции 1 кадра Switch, не принимая во внимание ограничение FPS или v-sync. Для полноскоростной эмуляции значение должно быть не больше 16,67 мс. - + Invalid config detected Обнаружена недопустимая конфигурация - + Handheld controller can't be used on docked mode. Pro controller will be selected. Портативный контроллер не может быть использован в режиме док-станции. Будет выбран контроллер Pro. - + DOCK ДОК - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Очистить Недавние Файлы - - TAS Recording - Запись TAS + + &Continue + &Продолжить - - Overwrite file of player 1? - Перезаписать файл игрока 1? + + &Pause + &Пауза @@ -3786,351 +3853,346 @@ Drag points to change position, or double-click table cells to edit values.Произошла неизвестная ошибка. Пожалуйста, проверьте лог для подробностей. - + (64-bit) (64-х битный) - + (32-bit) (32-х битный) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Запустить - - - + Save Data Данные Сохранений - + Mod Data Данные Модов - + Error Opening %1 Folder Ошибка при Открытии Папки %1 - - + + Folder does not exist! Папка не существует! - + Error Opening Transferable Shader Cache Ошибка при открытии переносного кэша шейдеров - + Failed to create the shader cache directory for this title. Не удалось создать папку кэша шейдеров для этой игры. - + Contents Содержание - + Update Обновление - + DLC Загружаемый Контент - + Remove Entry Удалить Запись - + Remove Installed Game %1? Удалить Установленную Игру %1? - - - - - - + + + + + + Successfully Removed Успешно Удалено - + Successfully removed the installed base game. Установленная базовая игра успешно удалена. - - - + + + Error Removing %1 Ошибка при Удалении %1 - + The base game is not installed in the NAND and cannot be removed. Базовая игра не установлена в NAND и не может быть удалена. - + Successfully removed the installed update. Установленное обновление успешно удалено. - + There is no update installed for this title. Для этой игры нету обновлений. - + There are no DLC installed for this title. Для этой игры нет установленного загружаемого контента. - + Successfully removed %1 installed DLC. Успешно удалено %1 загружаемого контента. - + Delete OpenGL Transferable Shader Cache? Удалить переносной кэш шейдеров OpenGL? - + Delete Vulkan Transferable Shader Cache? Удалить переносной кэш шейдеров Vulkan? - + Delete All Transferable Shader Caches? Удалить весь переносной кэш шейдеров? - + Remove Custom Game Configuration? Удалить Пользовательскую Настройку Игры? - + Remove File Удалить Файл - - + + Error Removing Transferable Shader Cache Ошибка при удалении переносного кэша шейдеров - - + + A shader cache for this title does not exist. Кэш шейдеров для этой игры не существует. - + Successfully removed the transferable shader cache. Переносной кэш шейдеров успешно удалён. - + Failed to remove the transferable shader cache. Не удалось удалить переносной кэш шейдеров. - - + + Error Removing Transferable Shader Caches Ошибка при удалении переносного кэша шейдеров - + Successfully removed the transferable shader caches. Переносной кэш шейдеров успешно удален. - + Failed to remove the transferable shader cache directory. Ошибка при удалении папки переносного кэша шейдеров. - - + + Error Removing Custom Configuration Ошибка при Удалении Пользовательской Настройки - + A custom configuration for this title does not exist. Пользовательская настройка для этой игры не существует. - + Successfully removed the custom game configuration. Пользовательская настройка игры успешно удалена. - + Failed to remove the custom game configuration. Не удалось удалить пользовательскую настройку игры. - - + + RomFS Extraction Failed! Не Удалось Извлечь RomFS! - + There was an error copying the RomFS files or the user cancelled the operation. Произошла ошибка при копировании файлов RomFS или пользователь отменил операцию. - + Full Полный - + Skeleton Структура - + Select RomFS Dump Mode Выберите Режим Дампа RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Пожалуйста, выберите, как вы хотите выполнить дамп RomFS. <br>Полный скопирует все файлы в новую папку, в то время как <br>структура создаст только структуру папок. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root В %1 недостаточно свободного места для извлечения RomFS. Пожалуйста, освободите место или выберите другую папку для дампа в Эмуляция > Настройка > Система > Файловая система > Корень Дампа - + Extracting RomFS... Извлечение RomFS... - - + + Cancel Отмена - + RomFS Extraction Succeeded! Извлечение RomFS Прошло Успешно! - + The operation completed successfully. Операция выполнена. - + Error Opening %1 Ошибка Открытия %1 - + Select Directory Выбрать папку - + Properties Свойства - + The game properties could not be loaded. Не удалось загрузить свойства игры. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Исполняемый файл Switch (%1);;Все файлы (*.*) - + Load File Загрузить файл - + Open Extracted ROM Directory Открыть папку извлечённого ROM'а - + Invalid Directory Selected Выбрана недопустимая папка - + The directory you have selected does not contain a 'main' file. Папка, которую вы выбрали, не содержит «основного» файла. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Устанавливаемый Файл Switch (*.nca, *.nsp, *.xci);;Архив Контента Nintendo (*.nca);;Пакет Подачи Nintendo (*.nsp);;Образ Картриджа NX (*.xci) - + Install Files Установить Файлы - + %n file(s) remaining Остался %n файлОсталось %n файл(ов)Осталось %n файл(ов)Осталось %n файл(ов) - + Installing file "%1"... Установка файла "%1"... - - + + Install Results Установить Результаты - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Чтобы избежать возможных конфликтов, мы не рекомендуем пользователям устанавливать базовые игры на NAND. Пожалуйста, используйте эту функцию только для установки обновлений и DLC. - + %n file(s) were newly installed %n файл был недавно установлен @@ -4140,7 +4202,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) were overwritten %n файл был перезаписан @@ -4150,7 +4212,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) failed to install %n файл(ов) не удалось установить @@ -4160,295 +4222,367 @@ Please, only use this feature to install updates and DLC. - + System Application Системное Приложение - + System Archive Системный Архив - + System Application Update Обновление Системного Приложения - + Firmware Package (Type A) Пакет Прошивки (Тип А) - + Firmware Package (Type B) Пакет Прошивки (Тип Б) - + Game Игра - + Game Update Обновление Игры - + Game DLC Загружаемый Контент Игры - + Delta Title Дельта-Титул - + Select NCA Install Type... Выберите Тип Установки NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Пожалуйста, выберите тип приложения, который вы хотите установить для этого NCA: (В большинстве случаев, подходит стандартный выбор «Игра».) - + Failed to Install Ошибка Установки - + The title type you selected for the NCA is invalid. Тип приложения, который вы выбрали для NCA, недействителен. - + File not found Файл не найден - + File "%1" not found Файл "%1" не найден - - - &Continue - &Продолжить - - - + OK ОК - + Missing yuzu Account Отсутствует Аккаунт yuzu - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Чтобы отправить отчет о совместимости игры, необходимо привязать свою учетную запись yuzu.<br><br/>Чтобы привязать свою учетную запись yuzu, перейдите в раздел Эмуляция &gt; Настройка &gt; Веб. - + Error opening URL Ошибка при открытии URL - + Unable to open the URL "%1". Не удалось открыть URL: "%1". - + + TAS Recording + Запись TAS + + + + Overwrite file of player 1? + Перезаписать файл игрока 1? + + + Amiibo File (%1);; All Files (*.*) Файл Amiibo (%1);; Все Файлы (*.*) - + Load Amiibo Загрузить Amiibo - + Error opening Amiibo data file Ошибка открытия файла данных Amiibo - + Unable to open Amiibo file "%1" for reading. Невозможно открыть файл Amiibo "%1" для чтения. - + Error reading Amiibo data file Ошибка чтения файла данных Amiibo - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Невозможно полностью прочитать данные Amiibo. Ожидалось прочитать %1 байт, но удалось прочитать только %2 байт. - + Error loading Amiibo data Ошибка загрузки данных Amiibo - + Unable to load Amiibo data. Невозможно загрузить данные Amiibo. - + Capture Screenshot Сделать Скриншот - + PNG Image (*.png) Изображение PNG (*.png) - + TAS state: Running %1/%2 Состояние TAS: Выполняется %1/%2 - + TAS state: Recording %1 Состояние TAS: Записывается %1 - + TAS state: Idle %1/%2 Состояние TAS: Простой %1/%2 - + TAS State: Invalid Состояние TAS: Неверный + + + &Stop Running + &Остановка + + + + &Start + &Начать + + + + Stop R&ecording + Закончить з&апись + + + + R&ecord + З&апись + - + Building: %n shader(s) Постройка: %n шейдер(ов)Постройка: %n шейдер(ов)Постройка: %n шейдер(ов)Постройка: %n шейдер(ов) - + + Scale: %1x + %1 is the resolution scaling factor + Масштаб: %1x + + + Speed: %1% / %2% Скорость: %1% / %2% - + Speed: %1% Скорость: %1% - + Game: %1 FPS (Unlocked) Игра: %1 FPS (Неограниченно) - + Game: %1 FPS Игра: %1 FPS - + Frame: %1 ms Кадр: %1 мс - + GPU NORMAL ГП НОРМАЛЬНО - + GPU HIGH ГП ВЫСОКО - + GPU EXTREME ГП ЭКСТРИМ - + GPU ERROR ГП ОШИБКА - + + NEAREST + БЛИЖАЙШИЙ + + + + + BILINEAR + БИЛИНЕЙНЫЙ + + + + BICUBIC + БИКУБИЧЕСКИЙ + + + + GAUSSIAN + ГАУСС + + + + SCALEFORCE + SCALEFORCE + + + + FSR + FSR + + + + + NO AA + БЕЗ СГЛАЖИВАНИЯ + + + + FXAA + FXAA + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Игра, которую вы пытаетесь загрузить, требует, чтобы дополнительные файлы были сдамплены с вашего Switch перед началом игры. <br/><br/>Для получения дополнительной информации о дампе этих файлов см. следующую вики: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Дамп Системных Архивов и Общих Шрифтов с консоли</a>. <br/><br/>Хотите вернуться к списку игр? Продолжение эмуляции может привести к сбоям, повреждению сохраненных данных или другим ошибкам. - + yuzu was unable to locate a Switch system archive. %1 yuzu не удалось найти системный архив Switch. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu не удалось найти системный архив Switch: %1. %2 - + System Archive Not Found Системный Архив Не Найден - + System Archive Missing Отсутствует Системный Архив - + yuzu was unable to locate the Switch shared fonts. %1 yuzu не удалось найти общие шрифты Switch. %1 - + Shared Fonts Not Found Общие Шрифты Не Найдены - + Shared Font Missing Общие Шрифты Отсутствуют - + Fatal Error Фатальная Ошибка - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu столкнулся с фатальной ошибкой, смотрите подробности в журнале. Информацию о доступе к журналу можно найти на этой странице: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Как Отправить Файл Журнала</a>.<br/><br/>Желаете вернуться к списку игр? Продолжение эмуляции может привести к сбоям, повреждению сохраненных данных или другим ошибкам. - + Fatal Error encountered Произошла Фатальная Ошибка - + Confirm Key Rederivation Подтвердите Перерасчет Ключа - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4465,37 +4599,37 @@ This will delete your autogenerated key files and re-run the key derivation modu Это удалит ваши автоматически сгенерированные файлы ключей и повторно запустит модуль расчета ключей. - + Missing fuses Отсутствуют предохранители - + - Missing BOOT0 - Отсутствует BOOT0 - + - Missing BCPKG2-1-Normal-Main - Отсутствует BCPKG2-1-Normal-Main - + - Missing PRODINFO - Отсутствует PRODINFO - + Derivation Components Missing Компоненты Расчета Отсутствуют - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Отсутствуют компоненты, что может помешать завершению процесса получения ключей. <br>Пожалуйста, следуйте <a href='https://yuzu-emu.org/help/quickstart/'>краткому руководство пользователя yuzu</a>, чтобы получить все ваши ключи и игры.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + Ключи шифрования отсутствуют. <br>Пожалуйста, следуйте <a href='https://yuzu-emu.org/help/quickstart/'>краткому руководству пользователя yuzu</a>, чтобы получить ключи, прошивку и игры.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4504,39 +4638,39 @@ on your system's performance. от производительности вашей системы. - + Deriving Keys Получение Ключей - + Select RomFS Dump Target Выберите Цель для Дампа RomFS - + Please select which RomFS you would like to dump. Пожалуйста, выберите, какой RomFS вы хотите сдампить. - + Are you sure you want to close yuzu? Вы уверены, что хотите закрыть yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Вы уверены, что хотите остановить эмуляцию? Любой несохраненный прогресс будет потерян. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4548,38 +4682,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! OpenGL не доступен! - + yuzu has not been compiled with OpenGL support. yuzu не был скомпилирован с поддержкой OpenGL. - - + + Error while initializing OpenGL! Ошибка при инициализации OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Ваш ГП может не поддерживать OpenGL, или у вас установлен устаревший графический драйвер. - + Error while initializing OpenGL 4.6! Ошибка при инициализации OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Ваш ГП может не поддерживать OpenGL 4.6, или у вас установлен устаревший графический драйвер.<br><br>Рендерер GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Ваш ГП может не поддерживать одно или несколько требуемых расширений OpenGL. Пожалуйста, убедитесь в том, что у вас установлен последний графический драйвер.<br><br>Рендерер GL:<br>%1<br><br>Неподдерживаемые расширения:<br>%2 @@ -4629,12 +4763,12 @@ Would you like to bypass this and exit anyway? Open Save Data Location - Открыть Папку для Сохранений + Открыть папку для сохранений Open Mod Data Location - Открыть Папку с Модами + Открыть папку для модов @@ -4941,190 +5075,205 @@ Screen. &Эмуляция - + &View &Вид - + &Reset Window Size &Сбросить Размер Окна - - Reset Window Size to &720p - Сбросить Размер Окна до &720p - - - - Reset Window Size to 720p - Сбросить Размер Окна до 720p - - - - Reset Window Size to &900p - Сбросить Размер Окна до &900p - - - - Reset Window Size to 900p - Сбросить Размер Окна до 900p - - - - Reset Window Size to &1080p - Сбросить Размер Окна до &1080p - - - - Reset Window Size to 1080p - Сбросить Размер Окна до 1080p - - - + &Debugging &Отладка - + + Reset Window Size to &720p + Сбросить Размер Окна до &720p + + + + Reset Window Size to 720p + Сбросить Размер Окна до 720p + + + + Reset Window Size to &900p + Сбросить Размер Окна до &900p + + + + Reset Window Size to 900p + Сбросить Размер Окна до 900p + + + + Reset Window Size to &1080p + Сбросить Размер Окна до &1080p + + + + Reset Window Size to 1080p + Сбросить Размер Окна до 1080p + + + &Tools &Инструменты - + + &TAS + &TAS + + + &Help &Помощь - + &Install Files to NAND... &Установить Файлы в NAND... - + L&oad File... З&агрузить Файл... - + Load &Folder... Загрузить &Папку... - + E&xit В&ыход - - &Start - &Начать - - - + &Pause &Пауза - + &Stop &Стоп - + &Reinitialize keys... &Переинициализировать ключи... - + &About yuzu &О yuzu - + Single &Window Mode Режим &Одного Окна - + Con&figure... Нас&троить... - + Display D&ock Widget Headers Отображать З&аголовки Виджетов Дока - + Show &Filter Bar Показать &Панель Поиска - + Show &Status Bar Показать &Панель Статуса - + Show Status Bar Показать Панель Статуса - + F&ullscreen П&олнокэранный - + &Restart &Перезапустить - + Load &Amiibo... Загрузить &Amiibo... - + &Report Compatibility &Сообщить о Совместимости - + Open &Mods Page Открыть &Страницу Модов - + Open &Quickstart Guide Открыть &Краткое Руководство Пользователя - + &FAQ &ЧАВО - + Open &yuzu Folder Открыть &Папку yuzu - + &Capture Screenshot &Сделать Скриншот - - Configure &TAS... - Настройка &TAS... + + &Configure TAS... + &Настройка TAS... - + Configure C&urrent Game... Настроить Т&екущую Игру... + + + &Start + &Начать + + + + &Reset + &Сброс + + + + R&ecord + З&апись + MicroProfileDialog @@ -5170,10 +5319,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE СТАРТ/ПАУЗА + + + Charging + Зарядка + QObject @@ -5204,142 +5358,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [не задано] - - Hat %1 %2 Крестовина %1 %2 - - - - - - + + + + Axis %1%2 Ось %1%2 - Button %1 Кнопка %1 - - - + + + [unknown] [неизвестно] - + + Left + Влево + + + + Right + Вправо + + - Click 0 - Клик 0 + Down + Вниз - - Click 1 - Клик 1 + Up + Вверх - - Click 2 - Клик 2 + Z + Z - - Click 3 - Клик 3 + R + R - - Click 4 - Клик 4 + L + L - + + A + A + + + + B + B + + + + X + X + + + + Y + Y + + + + Start + Start + + + + L1 + L1 + + + + L2 + L2 + + + + L3 + L3 + + + + R1 + R1 + + + + R2 + R2 + + + + R3 + R3 + + + + Circle + Круг + + + + Cross + Крестик + + + + Square + Квадрат + + + + Triangle + Треугольник + + + + Share + Share + + + + Options + Options + + + + [undefined] + [не определено] + + + %1%2 %1%2 - - GC Axis %1%2 - Ось GC %1%2 + + [invalid] + [недопустимо] - - GC Button %1 - Кнопка GC %1 + + + %1%2Hat %3 + %1%2Шляпа %3 - - TAS Axis %1 - Ось TAS %1 + + + + %1%2Axis %3 + %1%2Ось %3 - - TAS Btn %1 - TAS Кнопка %1 + + %1%2Axis %3,%4,%5 + %1%2Ось %3,%4,%5 - - Motion %1 - Движение %1 + + %1%2Motion %3 + %1%2Движение %3 - - %1Button %2 - %1Кнопка %2 + + + %1%2Button %3 + %1%2Кнопка %3 - - SDL Motion - Движение SDL - - - - %1Click %2 - %1Клик %2 - - - + [unused] [не используется] @@ -5380,7 +5614,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Контроллер Pro @@ -5393,7 +5627,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons Двойные Joycon'ы @@ -5406,7 +5640,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Левый Joycon @@ -5419,7 +5653,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Правый Joycon @@ -5447,7 +5681,7 @@ p, li { white-space: pre-wrap; } - + Handheld Портативный @@ -5568,7 +5802,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller Контроллер GameCube @@ -5662,13 +5896,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK ОК - + Cancel Отмена diff --git a/dist/languages/sv.ts b/dist/languages/sv.ts index 242a39fa5..9331f18ed 100644 --- a/dist/languages/sv.ts +++ b/dist/languages/sv.ts @@ -652,7 +652,12 @@ avgjord kod.</div> - + + Enable all Controller Types + + + + **This will be reset automatically when yuzu closes. @@ -932,67 +937,78 @@ avgjord kod.</div> Allmänt - - Framerate Cap + + + Use global framerate cap - + + Set framerate cap: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. - + + Framerate Cap + + + + x - + Limit Speed Percent Begränsa hastighetsprocent - + % % - + Multicore CPU Emulation Flerkärnig CPU-emulering - + Confirm exit while emulation is running Godkänn avslut medans emulering pågår - + Prompt for user on game boot Fråga efter användare vid spelstart - + Pause emulation when in background Pausa emulationen när fönstret är i bakgrunden - + Hide mouse on inactivity Göm mus när inaktiv - + Reset All Settings - + yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? @@ -1110,18 +1126,113 @@ avgjord kod.</div> Tänj över fönster - - + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + Use global background color Använd global bakgrundsfärg - + Set background color: Sätt backgrundsfärg: - + Background Color: Bakgrundsfärg: @@ -1190,27 +1301,32 @@ avgjord kod.</div> + Automatic + + + + Default Standard - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) + 2x - 8x (WILL BREAK THINGS) + 4x - 16x (WILL BREAK THINGS) + 8x + + + + + 16x @@ -1538,8 +1654,8 @@ avgjord kod.</div> - Other - Annat + Emulated Devices + @@ -1548,66 +1664,75 @@ avgjord kod.</div> - Emulate Analog with Keyboard Input - - - - - Enable mouse panning - - - - - Mouse sensitivity - - - - - % - - - - - - Advanced - Avancerat - - - - Touchscreen - Touchscreen - - - Mouse Mus - - Motion / Touch - Rörelse / Touch + + Touchscreen + Touchscreen - - - Configure - Konfigurera + + Advanced + Avancerat - + Debug Controller Debugkontroller - + + + Configure + Konfigurera + + + + Other + Annat + + + + Emulate Analog with Keyboard Input + + + + Requires restarting yuzu - + Enable XInput 8 player support (disables web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + + + + + % + + + + + Motion / Touch + Rörelse / Touch + ConfigureInputPlayer @@ -1622,424 +1747,440 @@ avgjord kod.</div> Koppla kontroller - - - - Pro Controller - Prokontroller - - - - - Dual Joycons - Dubbla Joycons - - - - - Left Joycon - Vänster Joycon - - - - - Right Joycon - Höger Joycon - - - - - Handheld - Handhållen - - - + Input Device Inmatningsenhet - - Any - Vilken som helst - - - - Keyboard/Mouse - Tangentbord/Mus - - - + Profile Profil - + Save Spara - + New Ny - + Delete Radera - - + + Left Stick Vänster Spak - - - - - - + + + + + + Up Upp - - - - - - - + + + + + + + Left Vänster - - - - - - - + + + + + + + Right Höger - - - - - - + + + + + + Down Ner - - - - + + + + Pressed Tryckt - - - - + + + + Modifier Modifierare - - + + Range Räckvidd - - + + % % - - + + Deadzone: 0% Dödzon: 0% - - + + Modifier Range: 0% Modifieringsräckvidd: 0% - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Minus - - + + Capture Fånga - - - + + + Plus Pluss - - + + Home Hem - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 - + Motion 2 - + Face Buttons Knappar - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Höger Spak - - - - + + + + Clear - - - - + + + + [not set] - - + + Toggle button - - + + Invert button + + + + + + Invert axis + + + + + Set threshold - + Choose a value between 0% and 100% - + Map Analog Stick - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. - - Invert axis - - - - - + + Deadzone: %1% Dödzon: %1% - - + + Modifier Range: %1% Modifieringsräckvidd: %1% - + + + Pro Controller + Prokontroller + + + + Dual Joycons + Dubbla Joycons + + + + Left Joycon + Vänster Joycon + + + + Right Joycon + Höger Joycon + + + + Handheld + Handhållen + + + GameCube Controller - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause - + Z - + Control Stick - + C-Stick - + Shake! - + [waiting] [väntar] - + New Profile - + Enter a profile name: - - + + Create Input Profile - + The given profile name is not valid! - + Failed to create the input profile "%1" - + Delete Input Profile - + Failed to delete the input profile "%1" - + Load Input Profile - + Failed to load the input profile "%1" - + Save Input Profile - + Failed to save the input profile "%1" @@ -2065,85 +2206,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch Konfigurera Rörelse / Touch - - Mouse Motion - - - - - Sensitivity: - Känslighet: - - - + Touch Touch - + UDP Calibration: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Konfigurera - - Use button mapping: - Använd knappkartläggning: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP-konfigurering - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Du kan använda Cemuhook-kompatibla UDP-inmatningskällor för att förse rörelse- och touchinmatning. - + Server: Server: - + Port: Port: - + Learn More Lär dig mer - - + + Test Test - + Add Server - + Remove Server @@ -2153,145 +2284,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Lär dig mer</span></a> - + %1:%2 - - - - - - + + + + + + yuzu - + Port number has invalid characters - + Port has to be in range 0 and 65353 - + IP address is not valid - + This UDP server already exists - + Unable to add more than 8 servers - + Testing Testar - + Configuring Konfigurerar - + Test Successful Test framgångsrikt - + Successfully received data from the server. Tog emot data från servern framgångsrikt - + Test Failed Test misslyckades - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Kunde inte ta emot giltig data från servern.<br>Var vänlig verifiera att servern är korrekt uppsatt och att adressen och porten är korrekta. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP Test eller kalibreringskonfiguration är igång.<br>Var vänlig vänta för dem att slutföras. - - ConfigureMouseAdvanced - - - Configure Mouse - Konfigurera Mus - - - - Mouse Buttons - Musknappar - - - - Forward: - Fram: - - - - Back: - Bak: - - - - Left: - Vänster: - - - - Middle: - Mitten: - - - - Right: - Höger: - - - - - Clear - Rensa - - - - Defaults - Standard - - - - [not set] - [ej angett] - - - - Restore Default - Återställ Standardvärden - - - - [press key] - [tryck knapp] - - ConfigureNetwork @@ -3075,31 +3142,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - - - - Loop script - + Pause execution during loads - + Script Directory - + Path - + ... @@ -3112,7 +3174,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - + Select TAS Load Directory... @@ -3174,37 +3236,37 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r Y - + New Profile Ny profil - + Enter the name for the new profile. Skriv in namn för den nya profilen. - + Delete Profile Radera profil - + Delete profile %1? Radera profil %1? - + Rename Profile Döp om profil - + New name: Nytt namn: - + [press key] [tryck på tangent] @@ -3624,12 +3686,12 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r ControllerDialog - + Controller P1 - + &Controller P1 @@ -3637,89 +3699,94 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonym data skickas </a>För att förbättra yuzu. <br/><br/>Vill du dela med dig av din användarstatistik med oss? - + Telemetry Telemetri - + Loading Web Applet... Laddar WebApplet... - - + + Disable Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? - + The amount of shaders currently being built Mängden shaders som just nu byggs - + + The current selected resolution scaling multiplier. + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Nuvarande emuleringshastighet. Värden över eller under 100% indikerar på att emulationen körs snabbare eller långsammare än en Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hur många bilder per sekund som spelet just nu visar. Detta varierar från spel till spel och scen till scen. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid det tar att emulera en Switch bild, utan att räkna med framelimiting eller v-sync. För emulering på full hastighet så ska det vara som mest 16.67 ms. - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - + DOCK DOCKAD - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files - - TAS Recording + + &Continue - - Overwrite file of player 1? + + &Pause @@ -3771,656 +3838,723 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r Ett okänt fel har uppstått. Se loggen för mer information. - + (64-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - - Start - Start - - - + Save Data Spardata - + Mod Data Mod-data - + Error Opening %1 Folder Fel Öppnar %1 Mappen - - + + Folder does not exist! Mappen finns inte! - + Error Opening Transferable Shader Cache Fel Under Öppning Av Överförbar Shadercache - + Failed to create the shader cache directory for this title. - + Contents Innehåll - + Update Uppdatera - + DLC DLC - + Remove Entry Ta bort katalog - + Remove Installed Game %1? Ta Bort Installerat Spel %1? - - - - - - + + + + + + Successfully Removed Framgångsrikt borttagen - + Successfully removed the installed base game. Tog bort det installerade basspelet framgångsrikt. - - - + + + Error Removing %1 Fel Under Borttagning Av %1 - + The base game is not installed in the NAND and cannot be removed. Basspelet är inte installerat i NAND och kan inte tas bort. - + Successfully removed the installed update. Tog bort den installerade uppdateringen framgångsrikt. - + There is no update installed for this title. Det finns ingen uppdatering installerad för denna titel. - + There are no DLC installed for this title. Det finns inga DLC installerade för denna titel. - + Successfully removed %1 installed DLC. Tog framgångsrikt bort den %1 installerade DLCn. - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? Ta Bort Anpassad Spelkonfiguration? - + Remove File Radera fil - - + + Error Removing Transferable Shader Cache Fel När Överförbar Shader Cache Raderades - - + + A shader cache for this title does not exist. En shader cache för denna titel existerar inte. - + Successfully removed the transferable shader cache. Raderade den överförbara shadercachen framgångsrikt. - + Failed to remove the transferable shader cache. Misslyckades att ta bort den överförbara shadercache - - + + Error Removing Transferable Shader Caches - + Successfully removed the transferable shader caches. - + Failed to remove the transferable shader cache directory. - - + + Error Removing Custom Configuration Fel När Anpassad Konfiguration Raderades - + A custom configuration for this title does not exist. En anpassad konfiguration för denna titel existerar inte. - + Successfully removed the custom game configuration. Tog bort den anpassade spelkonfigurationen framgångsrikt. - + Failed to remove the custom game configuration. Misslyckades att ta bort den anpassade spelkonfigurationen. - - + + RomFS Extraction Failed! RomFS Extraktion Misslyckades! - + There was an error copying the RomFS files or the user cancelled the operation. Det uppstod ett fel vid kopiering av RomFS filer eller användaren avbröt operationen. - + Full Full - + Skeleton Skelett - + Select RomFS Dump Mode Välj RomFS Dump-Läge - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Välj hur du vill att RomFS ska dumpas. <br>Full kommer att kopiera alla filer i den nya katalogen medan <br>skelett bara skapar katalogstrukturen. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Extraherar RomFS... - - + + Cancel Avbryt - + RomFS Extraction Succeeded! RomFS Extraktion Lyckades! - + The operation completed successfully. Operationen var lyckad. - + Error Opening %1 Fel under öppning av %1 - + Select Directory Välj Katalog - + Properties Egenskaper - + The game properties could not be loaded. Spelegenskaperna kunde inte laddas. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch Körbar (%1);;Alla Filer (*.*) - + Load File Ladda Fil - + Open Extracted ROM Directory Öppna Extraherad ROM-Katalog - + Invalid Directory Selected Ogiltig Katalog Vald - + The directory you have selected does not contain a 'main' file. Katalogen du har valt innehåller inte en 'main'-fil. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Installerbar Switch-fil (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Installera filer - + %n file(s) remaining - + Installing file "%1"... Installerar Fil "%1"... - - + + Install Results Installera resultat - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systemapplikation - + System Archive Systemarkiv - + System Application Update Systemapplikationsuppdatering - + Firmware Package (Type A) Firmwarepaket (Typ A) - + Firmware Package (Type B) Firmwarepaket (Typ B) - + Game Spel - + Game Update Speluppdatering - + Game DLC Spel DLC - + Delta Title Delta Titel - + Select NCA Install Type... Välj NCA-Installationsläge... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Välj vilken typ av titel du vill installera som: (I de flesta fallen, standard 'Spel' är bra.) - + Failed to Install Misslyckades med Installationen - + The title type you selected for the NCA is invalid. Den titeltyp du valt för NCA är ogiltig. - + File not found Filen hittades inte - + File "%1" not found Filen "%1" hittades inte - - - &Continue - - - - + OK - + Missing yuzu Account yuzu Konto hittades inte - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. För att skicka ett spelkompatibilitetstest, du måste länka ditt yuzu-konto.<br><br/>För att länka ditt yuzu-konto, gå till Emulering &gt, Konfigurering &gt, Web. - + Error opening URL Fel när URL öppnades - + Unable to open the URL "%1". Oförmögen att öppna URL:en "%1". - + + TAS Recording + + + + + Overwrite file of player 1? + + + + Amiibo File (%1);; All Files (*.*) Amiibo Fil (%1);; Alla Filer (*.*) - + Load Amiibo Ladda Amiibo - + Error opening Amiibo data file Fel öppnar Amiibo-datafilen - + Unable to open Amiibo file "%1" for reading. Kunde inte öppna Amiibo filen "%1" för läsning. - + Error reading Amiibo data file Fel vid läsning av Amiibo-datafil - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Kan inte läsa Amiibo-data helt. Förväntas läsa %1 byte, men kunde bara läsa %2 byte. - + Error loading Amiibo data Fel vid laddning av Amiibodata - + Unable to load Amiibo data. Kan inte ladda Amiibodata. - + Capture Screenshot Skärmdump - + PNG Image (*.png) PNG Bild (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + - + Building: %n shader(s) - + + Scale: %1x + %1 is the resolution scaling factor + + + + Speed: %1% / %2% Hastighet: %1% / %2% - + Speed: %1% Hastighet: %1% - + Game: %1 FPS (Unlocked) - + Game: %1 FPS Spel: %1 FPS - + Frame: %1 ms Ruta: %1 ms - + GPU NORMAL - + GPU HIGH - + GPU EXTREME - + GPU ERROR - + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Spelet du försöker ladda kräver att ytterligare filer dumpas från din Switch innan du spelar.<br/><br/>För mer information om dumpning av dessa filer, se följande wiki sida: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumpning System Arkiv och Delade Teckensnitt från en Switchkonsol</a>.<br/><br/>Vill du avsluta till spellistan? Fortsatt emulering kan leda till kraschar, skadad spara data och andra buggar. - + yuzu was unable to locate a Switch system archive. %1 yuzu kunde inte lokalisera ett Switchsystemarkiv. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 yuzu kunde inte lokalisera ett Switchsystemarkiv: %1. %2 - + System Archive Not Found Systemarkivet Hittades Inte - + System Archive Missing Systemarkiv Saknas - + yuzu was unable to locate the Switch shared fonts. %1 yuzu kunde inte lokalisera Switchens delade fonter. %1 - + Shared Fonts Not Found Delade Teckensnitt Hittades Inte - + Shared Font Missing Delad Font Saknas - + Fatal Error Dödligt Fel - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu stötte på ett dödligt fel, se loggen för mer information. För mer information om åtkomst till loggen, se följande sida: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Hur man Laddar upp Loggfilen</a>.<br/><br/>Vill du avsluta till spellistan? Fortsatt emulering kan leda till kraschar, skadad spara data och andra buggar. - + Fatal Error encountered Allvarligt fel påträffat - + Confirm Key Rederivation Bekräfta Nyckel Rederivering - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4437,37 +4571,37 @@ och eventuellt göra säkerhetskopior. Detta raderar dina autogenererade nyckelfiler och kör nyckelderivationsmodulen. - + Missing fuses Saknade säkringar - + - Missing BOOT0 - Saknar BOOT0 - + - Missing BCPKG2-1-Normal-Main - Saknar BCPKG2-1-Normal-Main - + - Missing PRODINFO - Saknar PRODINFO - + Derivation Components Missing Deriveringsdelar saknas - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Delar saknas som kan hindra nyckelderivering från att slutföras. <br>Var vänlig följ <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> för att få alla dina nycklar och spel.<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4476,39 +4610,39 @@ Detta kan ta upp till en minut beroende på systemets prestanda. - + Deriving Keys Härleda Nycklar - + Select RomFS Dump Target Välj RomFS Dumpa Mål - + Please select which RomFS you would like to dump. Välj vilken RomFS du vill dumpa. - + Are you sure you want to close yuzu? Är du säker på att du vill stänga yuzu? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Är du säker på att du vill stoppa emuleringen? Du kommer att förlora osparade framsteg. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4520,38 +4654,38 @@ Vill du strunta i detta och avsluta ändå? GRenderWindow - + OpenGL not available! OpenGL inte tillgängligt! - + yuzu has not been compiled with OpenGL support. yuzu har inte komilerats med OpenGL support. - - + + Error while initializing OpenGL! Fel under initialisering av OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 @@ -4912,190 +5046,205 @@ startskärmen. &Emulering - + &View &Vyn - + &Reset Window Size - - Reset Window Size to &720p - - - - - Reset Window Size to 720p - - - - - Reset Window Size to &900p - - - - - Reset Window Size to 900p - - - - - Reset Window Size to &1080p - - - - - Reset Window Size to 1080p - - - - + &Debugging - + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + &Tools - + + &TAS + + + + &Help &Hjälp - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit A&vsluta - - &Start - &Start - - - + &Pause &Paus - + &Stop &Sluta - + &Reinitialize keys... - + &About yuzu - + Single &Window Mode - + Con&figure... - + Display D&ock Widget Headers - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Visa Statusfält - + F&ullscreen - + &Restart - + Load &Amiibo... - + &Report Compatibility - + Open &Mods Page - + Open &Quickstart Guide - + &FAQ - + Open &yuzu Folder - + &Capture Screenshot - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... + + + &Start + &Start + + + + &Reset + + + + + R&ecord + + MicroProfileDialog @@ -5137,10 +5286,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE + + + Charging + + QObject @@ -5171,142 +5325,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [inte inställd] - - Hat %1 %2 Hatt %1 %2 - - - - - - + + + + Axis %1%2 Axel %1%2 - Button %1 Knapp %1 - - - + + + [unknown] [okänd] - + + Left + + + + + Right + + + - Click 0 - Klick 0 + Down + - - Click 1 - Klick 1 + Up + - - Click 2 - Klick 2 + Z + - - Click 3 - Klick 3 + R + - - Click 4 - Klick 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 - - GC Axis %1%2 - GC Axel %1%2 - - - - GC Button %1 - GC Knapp %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 + + + + %1%2Axis %3 - - %1Button %2 + + %1%2Axis %3,%4,%5 - - SDL Motion + + %1%2Motion %3 - - %1Click %2 + + + %1%2Button %3 - + [unused] [oanvänd] @@ -5347,7 +5581,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller @@ -5360,7 +5594,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons @@ -5373,7 +5607,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon @@ -5386,7 +5620,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon @@ -5414,7 +5648,7 @@ p, li { white-space: pre-wrap; } - + Handheld @@ -5535,7 +5769,7 @@ p, li { white-space: pre-wrap; } - + GameCube Controller @@ -5619,13 +5853,13 @@ p, li { white-space: pre-wrap; } - - + + OK - + Cancel diff --git a/dist/languages/tr_TR.ts b/dist/languages/tr_TR.ts index 76ed1f336..34e20064b 100644 --- a/dist/languages/tr_TR.ts +++ b/dist/languages/tr_TR.ts @@ -256,7 +256,7 @@ p, li { white-space: pre-wrap; } Accuracy: - Kesinlik: + Doğruluk: @@ -266,7 +266,7 @@ p, li { white-space: pre-wrap; } Accurate - Kesin + Doğru @@ -276,7 +276,7 @@ p, li { white-space: pre-wrap; } We recommend setting accuracy to "Auto". - Kesinlik ayarının "Otomatik" olmasını öneririz. + Doğruluk ayarının "Otomatik" olmasını öneririz. @@ -286,7 +286,7 @@ p, li { white-space: pre-wrap; } These settings reduce accuracy for speed. - Bu ayarlar daha hızlı bir deneyim için kesinliği azaltır. + Bu ayarlar daha hızlı bir deneyim için doğruluk oranını azaltır. @@ -294,8 +294,7 @@ p, li { white-space: pre-wrap; } <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> - <div>Bu seçenek FMA işlemlerinin kesinliğini azaltarak FMA desteklemeyen CPU'larda hızı artırır.</div> - + <div>Bu seçenek FMA işlemlerinin doğruluğunu azaltarak FMA desteklemeyen CPU'larda hızı artırır.</div> @@ -308,8 +307,7 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> - <div>Bu seçenek bazı tahmini FP fonksiyonlarını daha az kesin tahminlerle hızlandırır</div> - + <div>Bu seçenek bazı tahmini FP fonksiyonlarını daha az doğru tahminlerle hızlandırır. @@ -321,36 +319,39 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - + +Bu seçenek doğru olmayan yuvarlama fonksiyonları kullanarak 32 bit ASIMD FP fonksiyonlarını hızlandırır. Faster ASIMD instructions (32 bits only) - + Daha hızlı ASIMD komutları (yalnızca 32 bit) <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> - + +Bu seçenek NaN kontrolünü kaldırarak hızı arttırır. Aynı zamanda bazı FP komutlarının doğruluğunu azaltacağını da göz önünde bulundurun. Inaccurate NaN handling - + Uygunsuz NaN kullanımı <div>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.</div> - + +Bu seçenek belleğe yazma/okuma işlemlerindeki güvenlik kontrolünü kaldırarak hızı arttırır. Devre dışı bırakmak, oyunun emulatör belleğinde yazma/okuma yapmasına izin verir. Disable address space checks - + Adres boşluğu kontrolünü kapatır. @@ -390,8 +391,7 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Bu seçenek guest programın hafıza erişimini hızlandırır.</div> <div style="white-space: nowrap">Etkinleştirmek PageTable::pointer'larının yayılmış koda erişimlerini sıralar.</div> - <div style="white-space: nowrap">Devre dışı bırakmak bütün hafıza erişimlerini Memory::Read/Memory::Write fonksiyonlarından geçmeye zorlar.</div> - + <div style="white-space: nowrap">Devre dışı bırakmak bütün hafıza erişimlerini Memory::Read/Memory::Write fonksiyonlarından geçmeye zorlar.</div> @@ -505,12 +505,15 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> - + +<div style="white-space: nowrap">Bu seçenek guest programın hafıza erişimini hızlandırır.</div> +<div style="white-space: nowrap">Bunu etkinleştirmek guest bellek okuma/yazma işlemlerinin doğrudan belleğe işlenmesini sağlayıp, Host'un MMU'sundan yararlanır.</div> +<div style="white-space: nowrap">Devre dışı bırakmak tüm bellek erişimlerinin Yazılım MMU Emülasyonu kullanmasını zorlar</div> Enable Host MMU Emulation - + Host MMU Emülasyonunu Etkinleştir @@ -548,7 +551,7 @@ p, li { white-space: pre-wrap; } Enable Extended Logging** - + Uzatılmış Hata Kaydını Etkinleştir. @@ -578,17 +581,17 @@ p, li { white-space: pre-wrap; } When checked, it enables Nsight Aftermath crash dumps - + İşaretlendiğinde Nsight Aftermath çökme dökümlerini etkinleştirir. Enable Nsight Aftermath - + Nsight Aftermath'ı Etkinleştir When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower - + İşaretlendiğinde Makro JIT derleyicisini devre dışı bırakır. Bu seçeneği etkinleştirmek oyunların yavaş çalışmasına neden olur. @@ -603,17 +606,17 @@ p, li { white-space: pre-wrap; } Enable Shader Feedback - + Shader Geribildirimini Etkinleştir When checked, it executes shaders without loop logic changes - + İşaretlendiğinde shaderları döngü mantık değişimleri olmaksızın uygular Disable Loop safety checks - + Döngü güvenliği kontrolünü devre dışı bırak @@ -623,12 +626,12 @@ p, li { white-space: pre-wrap; } Enable FS Access Log - + FS Erişim Kaydını Etkinleştir Enable Verbose Reporting Services** - + Detaylı Raporlama Hizmetini Etkinleştir @@ -653,10 +656,15 @@ p, li { white-space: pre-wrap; } Enable Auto-Stub** + Auto-Stub'ı Etkinleştir + + + + Enable all Controller Types - + **This will be reset automatically when yuzu closes. **Bu yuzu kapandığında otomatik olarak eski haline dönecektir. @@ -936,69 +944,80 @@ p, li { white-space: pre-wrap; } Genel - + + + Use global framerate cap + + + + + Set framerate cap: + + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. + Etkili olması için FPS Kısıtlayıcı Geçiş Kısayolu kullanmanız gerekir. + + + Framerate Cap FPS Sınırı - - Requires the use of the FPS Limiter Toggle hotkey to take effect. - - - - + x x - + Limit Speed Percent Hız Yüzdesini Sınırlandır - + % % - + Multicore CPU Emulation Çok Çekirdekli CPU Emülasyonu - + Confirm exit while emulation is running Emülasyon devam ederken çıkışı onaylayın - + Prompt for user on game boot Oyun başlatılırken kullanıcı verisi iste - + Pause emulation when in background Arka plana alındığında emülasyonu durdur - + Hide mouse on inactivity Hareketsizlik durumunda imleci gizle - + Reset All Settings Tüm Ayarları Sıfırla - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? - + Bu seçenek tüm genel ve oyuna özgü ayarları silecektir. Oyun dizinleri, profiller ve giriş profilleri silinmeyecektir. Devam etmek istiyor musunuz? @@ -1021,7 +1040,7 @@ p, li { white-space: pre-wrap; } Shader Backend: - + Shader Backend: @@ -1051,7 +1070,7 @@ p, li { white-space: pre-wrap; } Accelerate ASTC texture decoding - + ASTC kaplama çözümünü hızlandır @@ -1086,7 +1105,7 @@ p, li { white-space: pre-wrap; } Exclusive Fullscreen - + Ayrılmış Tam Ekran @@ -1114,25 +1133,120 @@ p, li { white-space: pre-wrap; } Ekrana Sığdır - - + + Resolution: + Çözünürlük: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [DENEYSEL] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [DENEYSEL] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + Pencereye Uyarlı Filtre: + + + + Nearest Neighbor + En Yakın Komşu Algoritması + + + + Bilinear + Bilinear + + + + Bicubic + Bicubic + + + + Gaussian + Gausyen + + + + ScaleForce + ScaleForce + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + AMD's FidelityFX™️ Süper Çözünürlük [Yalnızca Vulkan için] + + + + Anti-Aliasing Method: + Kenar Yumuşatma Yöntemi: + + + + None + Yok + + + + FXAA + FXAA + + + + Use global background color Global arka plan rengini kullan - + Set background color: Arka plan rengini ayarla: - + Background Color: Arkaplan Rengi: GLASM (Assembly Shaders, NVIDIA Only) - + GLASM (Assembly Shaderları, Yalnızca NVIDIA için) @@ -1180,7 +1294,7 @@ p, li { white-space: pre-wrap; } Enables Fast GPU Time. This option will force most games to run at their highest native resolution. - + Hızlı GPU Saati'ni etkinleştir. Bu seçenek çoğu oyunu en yüksek gerçek çözünürlükte çalıştırır. @@ -1194,28 +1308,33 @@ p, li { white-space: pre-wrap; } + Automatic + Otomatik + + + Default Varsayılan - - - 2x (WILL BREAK THINGS) - 2x (BİR ŞEYLERİ BOZACAK) - - 4x (WILL BREAK THINGS) - 4x (BİR ŞEYLERİ BOZACAK) + 2x + 2x - 8x (WILL BREAK THINGS) - 8x (BİR ŞEYLERİ BOZACAK) + 4x + 4x - 16x (WILL BREAK THINGS) - 16x (BİR ŞEYLERİ BOZACAK) + 8x + 8x + + + + 16x + 16x @@ -1542,8 +1661,8 @@ p, li { white-space: pre-wrap; } - Other - Diğer + Emulated Devices + @@ -1552,66 +1671,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - Klavye Tuşlarıyla Analog Emülasyonu - - - - Enable mouse panning - Mouse ile kaydırmayı etkinleştir - - - - Mouse sensitivity - Fare hassasiyeti - - - - % - % - - - - - Advanced - Gelişmiş - - - - Touchscreen - Dokunmatik Ekran - - - Mouse Fare - - Motion / Touch - Hareket / Dokunmatik + + Touchscreen + Dokunmatik Ekran - - - Configure - Yapılandır + + Advanced + Gelişmiş - + Debug Controller Hata Ayıklama Kontrolcüsü - + + + Configure + Yapılandır + + + + Other + Diğer + + + + Emulate Analog with Keyboard Input + Klavye Tuşlarıyla Analog Emülasyonu + + + Requires restarting yuzu Yuzu'yu yeniden başlatmayı gerektirir - + Enable XInput 8 player support (disables web applet) XInput 8 oyuncu desteğini etkinleştir (web uygulamasını devre dışı bırakır) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + Mouse ile kaydırmayı etkinleştir + + + + Mouse sensitivity + Fare hassasiyeti + + + + % + % + + + + Motion / Touch + Hareket / Dokunmatik + ConfigureInputPlayer @@ -1626,425 +1754,441 @@ p, li { white-space: pre-wrap; } Kontrolcüyü Bağla - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - İkili Joyconlar - - - - - Left Joycon - Sol Joycon - - - - - Right Joycon - Sağ Joycon - - - - - Handheld - Handheld - - - + Input Device Giriş Cihazı - - Any - Herhangi - - - - Keyboard/Mouse - Klavye/Fare - - - + Profile Profil - + Save Kaydet - + New Yeni - + Delete Sil - - + + Left Stick Sol Analog - - - - - - + + + + + + Up Yukarı - - - - - - - + + + + + + + Left Sol - - - - - - - + + + + + + + Right Sağ - - - - - - + + + + + + Down Aşağı - - - - + + + + Pressed Basılı - - - - + + + + Modifier Düzenleyici: - - + + Range Aralık - - + + % % - - + + Deadzone: 0% Ölü Bölge: %0 - - + + Modifier Range: 0% Düzenleyici Aralığı: %0 - + D-Pad D-Pad - - - + + + L L - - - + + + ZL ZL - - + + Minus Eksi - - + + Capture Kaydet - - - + + + Plus Artı - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 Hareket 1 - + Motion 2 Hareket 2 - + Face Buttons Ön Tuşlar - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick Sağ Analog - - - - + + + + Clear Temizle - - - - + + + + [not set] [belirlenmedi] - - + + Toggle button Tuş ayarla - - + + Invert button + + + + + + Invert axis + Ekseni ters çevir + + + + Set threshold Alt sınır ayarla - + Choose a value between 0% and 100% %0 ve %100 arasında bir değer seçin - + Map Analog Stick Analog Çubuğu Ayarla - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. Tamama bastıktan sonra, joystikinizi önce yatay sonra dikey olarak hareket ettirin. Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak hareket ettirin. - - Invert axis - Ekseni ters çevir - - - - + + Deadzone: %1% Ölü Bölge: %1% - - + + Modifier Range: %1% Düzenleyici Aralığı: %1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + İkili Joyconlar + + + + Left Joycon + Sol Joycon + + + + Right Joycon + Sağ Joycon + + + + Handheld + Handheld + + + GameCube Controller GameCube Kontrolcüsü - + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause Başlat / Durdur - + Z Z - + Control Stick Kontrol Çubuğu - + C-Stick - + C-Çubuğu - + Shake! Salla! - + [waiting] [bekleniyor] - + New Profile Yeni Profil - + Enter a profile name: Bir profil ismi girin: - - + + Create Input Profile Kontrol Profili Oluştur - + The given profile name is not valid! Girilen profil ismi geçerli değil! - + Failed to create the input profile "%1" "%1" kontrol profili oluşturulamadı - + Delete Input Profile Kontrol Profilini Kaldır - + Failed to delete the input profile "%1" "%1" kontrol profili kaldırılamadı - + Load Input Profile Kontrol Profilini Yükle - + Failed to load the input profile "%1" "%1" kontrol profili yüklenemedi - + Save Input Profile Kontrol Profilini Kaydet - + Failed to save the input profile "%1" "%1" kontrol profili kaydedilemedi @@ -2070,85 +2214,75 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har ConfigureMotionTouch - + Configure Motion / Touch Hareket / Dokunmatik Kontrollerini Ayarla - - Mouse Motion - Fare Hareketi - - - - Sensitivity: - Hassasiyet: - - - + Touch Dokunmatik - + UDP Calibration: UDP Kalibrasyonu: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure Yapılandır - - Use button mapping: - Tuş ataması kullan: + + Touch from button profile: + - + CemuhookUDP Config CemuhookUDP Yapılandırması - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. Hareket ve dokunma girişi için Cemuhook'la uyumlu herhangi bir UDP giriş kaynağı kullanabilirsiniz. - + Server: Sunucu: - + Port: Port: - + Learn More Daha Fazla Bilgi Edinin - - + + Test Test - + Add Server Server Ekle - + Remove Server Server'ı Kaldır @@ -2158,145 +2292,81 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Daha Fazlası</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters Port numarasında geçersiz karakterler var - + Port has to be in range 0 and 65353 Port 0 ila 65353 aralığında olmalıdır - + IP address is not valid IP adresi geçerli değil - + This UDP server already exists Bu UDP sunucusu zaten var - + Unable to add more than 8 servers 8'den fazla server eklenemez - + Testing Test Ediliyor - + Configuring Yapılandırılıyor - + Test Successful Test Başarılı - + Successfully received data from the server. Bilgi başarıyla sunucudan kaldırıldı. - + Test Failed Test Başarısız - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. Serverdan geçerli veri alınamadı.<br>Lütfen sunucunun doğru ayarlandığını ya da adres ve portun doğru olduğunu kontrol edin. - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP testi ya da yapılandırılması devrede.<br>Lütfen bitmesini bekleyin. - - ConfigureMouseAdvanced - - - Configure Mouse - Fareyi Yapılandır - - - - Mouse Buttons - Fare Tuşları - - - - Forward: - İleri: - - - - Back: - Arka: - - - - Left: - Sol: - - - - Middle: - Orta: - - - - Right: - Sağ: - - - - - Clear - Temizle - - - - Defaults - Varsayılanlar - - - - [not set] - [belirlenmedi] - - - - Restore Default - Varsayılana Dön - - - - [press key] - [tuşa bas] - - ConfigureNetwork @@ -2400,7 +2470,7 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har Adv. Graphics - + Gelişmiş Grafikler @@ -2584,12 +2654,12 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har Error resizing user image - + Kullanıcı görüntüsünü yeniden boyutlandırma hatası Unable to resize image - + Görüntü yeniden boyutlandırılamıyor @@ -3051,22 +3121,22 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har TAS - + TAS <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - + <html><head/><body><p> Kontrolcü girdilerini TAS-nx scriptleri ile aynı formatta okur. <br/>Daha detaylı bilgi için lütfen yuzu web sitesindeki <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;"> yardım sayfasına</span></a>bakınız.</p></body></html> To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). - + Hangi kısayolların Yeniden Oynatma/Kayıt fonksiyonunu kontrol ettiğini öğrenmek için Kısayol Ayarlarına bakın. (Yapılandır -> Genel -> Kısayollar) WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method. - + UYARI: Bu deneysel bir özelliktir.<br/> Halihazırdaki kusurlu eşzamanlama yöntemi sebebiyle, scriptleri mükemmel olarak oynatmayacaktır. @@ -3076,35 +3146,30 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har Enable TAS features - + TAS özelliklerini Etkinleştir - Automatic controller profile swapping - Otomatik kontrolcü profili değiştirme - - - Loop script - + Döngü komut dosyası - + Pause execution during loads - + Yüklemeler sırasında yürütmeyi duraklat - + Script Directory Script Konumu - + Path Konum - + ... ... @@ -3114,12 +3179,12 @@ Eksenleri ters çevirmek için, önce joystickinizi dikey sonra yatay olarak har TAS Configuration - + TAS Yapılandırması - + Select TAS Load Directory... - + Tas Yükleme Dizini Seçin @@ -3179,37 +3244,37 @@ Noktanın konumunu değiştirmek için sürükleyin ya da sayıların üstüne Y - + New Profile Yeni Profil - + Enter the name for the new profile. Yeni profil için bir isim giriniz. - + Delete Profile Profili Sil - + Delete profile %1? %1 adlı profili silmek istediğinize emin misiniz? - + Rename Profile Profili Yeniden Adlandır - + New name: Yeni Ad: - + [press key] [tuşa basın] @@ -3487,7 +3552,7 @@ Noktanın konumunu değiştirmek için sürükleyin ya da sayıların üstüne Enable Accurate Vibration - + Doğru Titreşimi Etkinleştir @@ -3629,12 +3694,12 @@ Noktanın konumunu değiştirmek için sürükleyin ya da sayıların üstüne ControllerDialog - + Controller P1 Kontrolcü O1 - + &Controller P1 &Kontrolcü O1 @@ -3642,90 +3707,95 @@ Noktanın konumunu değiştirmek için sürükleyin ya da sayıların üstüne GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>Yuzuyu geliştirmeye yardımcı olmak için </a> anonim veri toplandı. <br/><br/>Kullanım verinizi bizimle paylaşmak ister misiniz? - + Telemetry Telemetri - + Loading Web Applet... Web Uygulaması Yükleniyor... - - + + Disable Web Applet Web Uygulamasını Devre Dışı Bırak - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? Web uygulamasını devre dışı bırakmak emülasyon seansının sonuna kadar bir daha gösterilmemesine sebep olur. Bu, belirsiz davranışlara sebep olabilir ve sadece Super Mario 3D All-Stars'da kullanılmalıdır. Web uygulamasını devre dışı bırakmak istediğinize emin misiniz? - + The amount of shaders currently being built Şu anda derlenen shader miktarı - + + The current selected resolution scaling multiplier. + Geçerli seçili çözünürlük ölçekleme çarpanı. + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Geçerli emülasyon hızı. %100'den yüksek veya düşük değerler emülasyonun bir Switch'den daha hızlı veya daha yavaş çalıştığını gösterir. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Oyunun şuanda saniye başına kaç kare gösterdiği. Bu oyundan oyuna ve sahneden sahneye değişiklik gösterir. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Bir Switch karesini emüle etmekte geçen zaman, karelimitleme ve v-sync hariç. Tam hız emülasyon için bu en çok 16,67 ms olmalı. - + Invalid config detected Geçersiz yapılandırma tespit edildi - + Handheld controller can't be used on docked mode. Pro controller will be selected. Handheld kontrolcü dock modunda kullanılamaz. Pro kontrolcü seçilecek. - + DOCK DOCK - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files &Son Dosyaları Temizle - - TAS Recording - + + &Continue + &Devam Et - - Overwrite file of player 1? - Oyuncu 1'in dosyasının üstüne yazılsın mı? + + &Pause + @@ -3776,351 +3846,346 @@ Noktanın konumunu değiştirmek için sürükleyin ya da sayıların üstüne Bilinmeyen bir hata oluştu. Lütfen daha fazla detay için kütüğe göz atınız. - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - Başlat - - - + Save Data Kayıt Verisi - + Mod Data Mod Verisi - + Error Opening %1 Folder %1 klasörü açılırken hata - - + + Folder does not exist! Klasör mevcut değil! - + Error Opening Transferable Shader Cache Transfer Edilebilir Shader Cache'ini Açarken Bir Hata Oluştu - + Failed to create the shader cache directory for this title. Bu oyun için shader cache konumu oluşturulamadı. - + Contents İçerikler - + Update Güncelleme - + DLC DLC - + Remove Entry Girdiyi Kaldır - + Remove Installed Game %1? %1 Adlı Oyunu Kaldırmak İstediğinize Emin Misiniz? - - - - - - + + + + + + Successfully Removed Başarıyla Kaldırıldı - + Successfully removed the installed base game. Yüklenmiş oyun başarıyla kaldırıldı. - - - + + + Error Removing %1 %1 Adlı Oyun Kaldırılırken Bir Hata Oluştu - + The base game is not installed in the NAND and cannot be removed. Asıl oyun NAND'de kurulu değil ve kaldırılamaz. - + Successfully removed the installed update. Yüklenmiş güncelleme başarıyla kaldırıldı. - + There is no update installed for this title. Bu oyun için yüklenmiş bir güncelleme yok. - + There are no DLC installed for this title. Bu oyun için yüklenmiş bir DLC yok. - + Successfully removed %1 installed DLC. %1 yüklenmiş DLC başarıyla kaldırıldı. - + Delete OpenGL Transferable Shader Cache? OpenGL Transfer Edilebilir Shader Cache'ini Kaldırmak İstediğinize Emin Misiniz? - + Delete Vulkan Transferable Shader Cache? Vulkan Transfer Edilebilir Shader Cache'ini Kaldırmak İstediğinize Emin Misiniz? - + Delete All Transferable Shader Caches? Tüm Transfer Edilebilir Shader Cache'leri Kaldırmak İstediğinize Emin Misiniz? - + Remove Custom Game Configuration? Oyuna Özel Yapılandırmayı Kaldırmak İstediğinize Emin Misiniz? - + Remove File Dosyayı Sil - - + + Error Removing Transferable Shader Cache Transfer Edilebilir Shader Cache Kaldırılırken Bir Hata Oluştu - - + + A shader cache for this title does not exist. Bu oyun için oluşturulmuş bir shader cache yok. - + Successfully removed the transferable shader cache. Transfer edilebilir shader cache başarıyla kaldırıldı. - + Failed to remove the transferable shader cache. Transfer edilebilir shader cache kaldırılamadı. - - + + Error Removing Transferable Shader Caches Transfer Edilebilir Shader Cache'ler Kaldırılırken Bir Hata Oluştu - + Successfully removed the transferable shader caches. Transfer edilebilir shader cacheler başarıyla kaldırıldı. - + Failed to remove the transferable shader cache directory. Transfer edilebilir shader cache konumu kaldırılamadı. - - + + Error Removing Custom Configuration Oyuna Özel Yapılandırma Kaldırılırken Bir Hata Oluştu. - + A custom configuration for this title does not exist. Bu oyun için bir özel yapılandırma yok. - + Successfully removed the custom game configuration. Oyuna özel yapılandırma başarıyla kaldırıldı. - + Failed to remove the custom game configuration. Oyuna özel yapılandırma kaldırılamadı. - - + + RomFS Extraction Failed! RomFS Çıkartımı Başarısız! - + There was an error copying the RomFS files or the user cancelled the operation. RomFS dosyaları kopyalanırken bir hata oluştu veya kullanıcı işlemi iptal etti. - + Full Full - + Skeleton Gövde - + Select RomFS Dump Mode RomFS Dump Modunu Seçiniz - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Lütfen RomFS'in nasıl dump edilmesini istediğinizi seçin.<br>"Full" tüm dosyaları yeni bir klasöre kopyalarken <br>"skeleton" sadece klasör yapısını oluşturur. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + %1 konumunda RomFS çıkarmaya yetecek alan yok. Lütfen yer açın ya da Emülasyon > Yapılandırma > Sistem > Dosya Sistemi > Dump konumu kısmından farklı bir çıktı konumu belirleyin. - + Extracting RomFS... RomFS çıkartılıyor... - - + + Cancel İptal - + RomFS Extraction Succeeded! RomFS Çıkartımı Başarılı! - + The operation completed successfully. İşlem başarıyla tamamlandı. - + Error Opening %1 %1 Açılırken Bir Hata Oluştu - + Select Directory Klasör Seç - + Properties Özellikler - + The game properties could not be loaded. Oyun özellikleri yüklenemedi. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch Çalıştırılabilir Dosyası (%1);;Tüm Dosyalar (*.*) - + Load File Dosya Aç - + Open Extracted ROM Directory Çıkartılmış ROM klasörünü aç - + Invalid Directory Selected Geçersiz Klasör Seçildi - + The directory you have selected does not contain a 'main' file. Seçtiğiniz klasör bir "main" dosyası içermiyor. - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) Yüklenilebilir Switch Dosyası (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge Image (*.xci) - + Install Files Dosya Kur - + %n file(s) remaining %n dosya kaldı%n dosya kaldı - + Installing file "%1"... "%1" dosyası kuruluyor... - - + + Install Results Kurulum Sonuçları - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Olası çakışmaları önlemek için oyunları NAND'e yüklememenizi tavsiye ediyoruz. Lütfen bu özelliği sadece güncelleme ve DLC yüklemek için kullanın. - + %n file(s) were newly installed %n dosya güncel olarak yüklendi @@ -4128,7 +4193,7 @@ Lütfen bu özelliği sadece güncelleme ve DLC yüklemek için kullanın. - + %n file(s) were overwritten %n dosyanın üstüne yazıldı @@ -4136,7 +4201,7 @@ Lütfen bu özelliği sadece güncelleme ve DLC yüklemek için kullanın. - + %n file(s) failed to install %n dosya yüklenemedi @@ -4144,295 +4209,367 @@ Lütfen bu özelliği sadece güncelleme ve DLC yüklemek için kullanın. - + System Application Sistem Uygulaması - + System Archive Sistem Arşivi - + System Application Update Sistem Uygulama Güncellemesi - + Firmware Package (Type A) Yazılım Paketi (Tür A) - + Firmware Package (Type B) Yazılım Paketi (Tür B) - + Game Oyun - + Game Update Oyun Güncellemesi - + Game DLC Oyun DLC'si - + Delta Title Delta Başlık - + Select NCA Install Type... NCA Kurulum Tipi Seçin... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Lütfen bu NCA dosyası için belirlemek istediğiniz başlık türünü seçiniz: (Çoğu durumda, varsayılan olan 'Oyun' kullanılabilir.) - + Failed to Install Kurulum Başarısız Oldu - + The title type you selected for the NCA is invalid. NCA için seçtiğiniz başlık türü geçersiz - + File not found Dosya Bulunamadı - + File "%1" not found Dosya "%1" Bulunamadı - - - &Continue - &Devam Et - - - + OK Tamam - + Missing yuzu Account Kayıp yuzu Hesabı - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. Oyun uyumluluk test çalışması göndermek için öncelikle yuzu hesabınla giriş yapmanız gerekiyor.<br><br/>Yuzu hesabınızla giriş yapmak için, Emülasyon &gt; Yapılandırma &gt; Web'e gidiniz. - + Error opening URL URL açılırken bir hata oluştu - + Unable to open the URL "%1". URL "%1" açılamıyor. - + + TAS Recording + TAS kayıtta + + + + Overwrite file of player 1? + Oyuncu 1'in dosyasının üstüne yazılsın mı? + + + Amiibo File (%1);; All Files (*.*) Amiibo Dosyası (%1);; Tüm Dosyalar (*.*) - + Load Amiibo Amiibo Yükle - + Error opening Amiibo data file Amiibo veri dosyasını açarken hata - + Unable to open Amiibo file "%1" for reading. "%1" Amiibo dosyası okunamadı - + Error reading Amiibo data file Amiibo veri dosyasını okurken hata - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. Amiibo verisi tamamen okunamadı. %1 byte okunması bekleniyordu, fakat bunun sadece %2'si okunabildi. - + Error loading Amiibo data Amiibo verisi yüklenirken hata - + Unable to load Amiibo data. Amiibo verisi yüklenemedi - + Capture Screenshot Ekran Görüntüsü Al - + PNG Image (*.png) PNG görüntüsü (*.png) - + TAS state: Running %1/%2 - + TAS durumu: %1%2 çalışıyor - + TAS state: Recording %1 - + TAS durumu: %1 kaydediliyor - + TAS state: Idle %1/%2 + TAS durumu: %1%2 boşta + + + + TAS State: Invalid + TAS durumu: Geçersiz + + + + &Stop Running - - TAS State: Invalid + + &Start + + + + + Stop R&ecording + + + + + R&ecord - + Building: %n shader(s) Oluşturuluyor: %n shaderOluşturuluyor: %n shader - + + Scale: %1x + %1 is the resolution scaling factor + Ölçek: %1x + + + Speed: %1% / %2% Hız %1% / %2% - + Speed: %1% Hız: %1% - + Game: %1 FPS (Unlocked) Oyun: %1 FPS (Sınırsız) - + Game: %1 FPS Oyun: %1 FPS - + Frame: %1 ms Kare: %1 ms - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU YÜKSEK - + GPU EXTREME GPU EKSTREM - + GPU ERROR GPU HATASI - + + NEAREST + EN YAKIN + + + + + BILINEAR + BILINEAR + + + + BICUBIC + BICUBIC + + + + GAUSSIAN + GAUSYEN + + + + SCALEFORCE + SCALEFORCE + + + + FSR + FSR + + + + + NO AA + NO AA + + + + FXAA + FXAA + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Yüklemeye çalıştığınız oyun oynanmadan önce Switch'inizden ek dosyaların alınmasını gerektiriyor.<br/><br/>Bu dosyaları nasıl alacağınız hakkında daha fazla bilgi için, lütfen bu wiki sayfasına göz atınız: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Konsolunuzdan Sistem Arşivleri ve Shared Fontları Almak</a>.<br/><br/>oyun listesine geri dönmek ister misiniz? Emülasyona devam etmek çökmelere, kayıt dosyalarının bozulmasına veya başka hatalara sebep verebilir. - + yuzu was unable to locate a Switch system archive. %1 Yuzu bir Switch sistem arşivi bulamadı. %1 - + yuzu was unable to locate a Switch system archive: %1. %2 Yuzu bir Switch sistem arşivi bulamadı: %1. %2 - + System Archive Not Found Sistem Arşivi Bulunamadı - + System Archive Missing Sistem Arşivi Kayıp - + yuzu was unable to locate the Switch shared fonts. %1 Yuzu Switch shared fontlarını bulamadı. %1 - + Shared Fonts Not Found Shared Font'lar Bulunamadı - + Shared Font Missing Shared Font Kayıp - + Fatal Error Önemli Hata - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. Yuzu önemli bir hatayla karşılaştı, lütfen daha fazla detay için kütüğe bakınız. Kütüğe erişmek hakkında daha fazla bilgi için, lütfen bu sayfaya göz atınız: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Log Dosyası Nasıl Yüklenir</a>.<br/><br/>Oyun listesine geri dönmek ister misiniz? Emülasyona devam etmek çökmelere, kayıt dosyalarının bozulmasına veya başka hatalara sebep olabilir. - + Fatal Error encountered Önemli Bir Hatayla Karşılaşıldı - + Confirm Key Rederivation Anahtar Yeniden Türetimini Onayla - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4449,37 +4586,37 @@ ve opsiyonel olarak yedekler alın. Bu sizin otomatik oluşturulmuş anahtar dosyalarınızı silecek ve anahtar türetme modülünü tekrar çalıştıracak. - + Missing fuses Anahtarlar Kayıp - + - Missing BOOT0 - BOOT0 Kayıp - + - Missing BCPKG2-1-Normal-Main - BCPKG2-1-Normal-Main Kayıp - + - Missing PRODINFO - PRODINFO Kayıp - + Derivation Components Missing Türeten Bileşenleri Kayıp - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - Bazı bileşenler kayıp, bu anahtar türetimini yarıda bırakabilir.<br>Lütfen tüm anahtar ve oyunlarınıza erişmek için<a href='https://yuzu-emu.org/help/quickstart/'>Yuzu Hızlı Başlangıç Kılavuzu</a>'nu takip edin<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + Şifreleme anahtarları eksik. <br>Lütfen takip edin<a href='https://yuzu-emu.org/help/quickstart/'>yuzu hızlı başlangıç kılavuzunu</a>tüm anahtarlarınızı, aygıt yazılımınızı ve oyunlarınızı almada.<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4488,39 +4625,39 @@ Bu sistem performansınıza bağlı olarak bir dakika kadar zaman alabilir. - + Deriving Keys Anahtarlar Türetiliyor - + Select RomFS Dump Target RomFS Dump Hedefini Seçiniz - + Please select which RomFS you would like to dump. Lütfen dump etmek istediğiniz RomFS'i seçiniz. - + Are you sure you want to close yuzu? yuzu'yu kapatmak istediğinizden emin misiniz? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Emülasyonu durdurmak istediğinizden emin misiniz? Kaydedilmemiş veriler kaybolur. - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4532,38 +4669,38 @@ Görmezden gelip kapatmak ister misiniz? GRenderWindow - + OpenGL not available! OpenGL kullanıma uygun değil! - + yuzu has not been compiled with OpenGL support. Yuzu OpenGL desteklememektedir. - - + + Error while initializing OpenGL! OpenGl başlatılırken bir hata oluştu! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU'nuz OpenGL desteklemiyor veya güncel bir grafik sürücüsüne sahip değilsiniz. - + Error while initializing OpenGL 4.6! OpenGl 4.6 başlatılırken bir hata oluştu! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPU'nuz OpenGL 4.6'yı desteklemiyor veya güncel bir grafik sürücüsüne sahip değilsiniz.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPU'nuz gereken bir yada daha fazla OpenGL eklentisini desteklemiyor Lütfen güncel bir grafik sürücüsüne sahip olduğunuzdan emin olun.<br><br>GL Renderer:<br>%1<br><br> Desteklenmeyen Eklentiler:<br>%2 @@ -4674,7 +4811,7 @@ Görmezden gelip kapatmak ister misiniz? Dump RomFS to SDMC - + RomFS'i SDMC'ye çıkar. @@ -4928,197 +5065,212 @@ Screen. &Emülasyon - + &View &Görünüm - + &Reset Window Size &Pencere Boyutunu Sıfırla - - Reset Window Size to &720p - Pencere Boyutunu &720p'ye Sıfırla - - - - Reset Window Size to 720p - Pencere Boyutunu 720p'ye Sıfırla - - - - Reset Window Size to &900p - Pencere Boyutunu &900p'ye Sıfırla - - - - Reset Window Size to 900p - Pencere Boyutunu 900p'ye Sıfırla - - - - Reset Window Size to &1080p - Pencere Boyutunu &1080p'ye Sıfırla - - - - Reset Window Size to 1080p - Pencere Boyutunu 1080p'ye Sıfırla - - - + &Debugging &Hata Ayıklama - + + Reset Window Size to &720p + Pencere Boyutunu &720p'ye Sıfırla + + + + Reset Window Size to 720p + Pencere Boyutunu 720p'ye Sıfırla + + + + Reset Window Size to &900p + Pencere Boyutunu &900p'ye Sıfırla + + + + Reset Window Size to 900p + Pencere Boyutunu 900p'ye Sıfırla + + + + Reset Window Size to &1080p + Pencere Boyutunu &1080p'ye Sıfırla + + + + Reset Window Size to 1080p + Pencere Boyutunu 1080p'ye Sıfırla + + + &Tools &Aletler - + + &TAS + + + + &Help &Yardım - + &Install Files to NAND... &NAND'e Dosya Kur... - + L&oad File... &Dosyayı Yükle... - + Load &Folder... &Klasörü Yükle... - + E&xit &Çıkış - - &Start - B&aşlat - - - + &Pause &Duraklat - + &Stop Du&rdur - + &Reinitialize keys... &Anahtarları Yeniden Kur... - + &About yuzu &Yuzu Hakkında - + Single &Window Mode &Tek Pencere Modu - + Con&figure... &Yapılandır... - + Display D&ock Widget Headers - + D&ock Widget Başlıkları'nı Göster - + Show &Filter Bar - + &Filtre Çubuğu'nu Göster - + Show &Status Bar - + &Durum Çubuğu'nu Göster - + Show Status Bar Durum Çubuğunu Göster - + F&ullscreen &Tam Ekran - + &Restart &Yeniden Başlat - + Load &Amiibo... &Amiibo Yükle... - + &Report Compatibility &Uyumluluk Bildir - + Open &Mods Page &Mod Sayfasını Aç - + Open &Quickstart Guide &Hızlı Başlangıç Kılavuzunu Aç - + &FAQ &SSS - + Open &yuzu Folder &yuzu Klasörünü Aç - + &Capture Screenshot &Ekran Görüntüsü Al - - Configure &TAS... + + &Configure TAS... - + Configure C&urrent Game... &Geçerli Oyunu Yapılandır... + + + &Start + B&aşlat + + + + &Reset + + + + + R&ecord + + MicroProfileDialog &MicroProfile - + &MicroProfile @@ -5157,10 +5309,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE BAŞLAT/DURDUR + + + Charging + + QObject @@ -5191,142 +5348,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [belirlenmedi] - - Hat %1 %2 Hat %1 %2 - - - - - - + + + + Axis %1%2 Eksen %1%2 - Button %1 Tuş %1 - - - + + + [unknown] [bilinmeyen] - + + Left + + + + + Right + + + - Click 0 - Tıklama 0 + Down + - - Click 1 - Tıklama 1 + Up + - - Click 2 - Tıklama 2 + Z + - - Click 3 - Tıklama 3 + R + - - Click 4 - Tıklama 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - OK Eksen %1%2 - - - - GC Button %1 - OK Tuş %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - Hareket %1 - - - - %1Button %2 - %1Tuş %2 - - - - SDL Motion + + + + %1%2Axis %3 - - %1Click %2 - %1Tıklama %2 + + %1%2Axis %3,%4,%5 + - + + %1%2Motion %3 + + + + + + %1%2Button %3 + + + + [unused] [kullanılmayan] @@ -5367,7 +5604,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5380,7 +5617,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons İkili Joyconlar @@ -5393,7 +5630,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon Sol Joycon @@ -5406,7 +5643,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon Sağ Joycon @@ -5434,7 +5671,7 @@ p, li { white-space: pre-wrap; } - + Handheld Handheld @@ -5555,7 +5792,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller GameCube Kontrolcüsü @@ -5649,13 +5886,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK Tamam - + Cancel İptal @@ -5725,7 +5962,7 @@ p, li { white-space: pre-wrap; } runnable - + çalışabilir @@ -5760,7 +5997,7 @@ p, li { white-space: pre-wrap; } waiting for suspend resume - + askıdaki işlemin sürdürülmesi bekleniyor @@ -5846,7 +6083,7 @@ p, li { white-space: pre-wrap; } &Wait Tree - + &Wait Tree \ No newline at end of file diff --git a/dist/languages/vi_VN.ts b/dist/languages/vi_VN.ts new file mode 100644 index 000000000..2f6213e1d --- /dev/null +++ b/dist/languages/vi_VN.ts @@ -0,0 +1,6044 @@ + + + AboutDialog + + + About yuzu + Thông tin về yuzu + + + + <html><head/><body><p><img src=":/icons/yuzu.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/yuzu.png"/></p></body></html> + + + + <html><head/><body><p><span style=" font-size:28pt;">yuzu</span></p></body></html> + <html><head/><body><p><span style=" font-size:28pt;">yuzu</span></p></body></html> + + + + <html><head/><body><p>%1 (%2)</p></body></html> + <html><head/><body><p>%1 (%2)</p></body></html> + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">This software should not be used to play games you have not legally obtained.</span></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu là một phần mềm giả lập thử nghiệm dưới dạng mã nguồn mở cho máy Nintendo Switch, được cấp phép theo giấy phép GPLv2.0.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Bạn không được phép sử dụng phần mềm này để chơi những trò chơi mà bạn sở hữu một cách bất hợp pháp.</span></p></body></html> + + + + <html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Trang web</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Mã nguồn</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Đóng góp</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Giấy phép</span></a></p></body></html> + + + + <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.</span></p></body></html> + <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; là thương hiệu của Nintendo. yuzu không hề liên kết với Nintendo dưới bất kỳ hình thức nào.</span></p></body></html> + + + + CalibrationConfigurationDialog + + + Communicating with the server... + Đang giao tiếp với máy chủ... + + + + Cancel + Huỷ + + + + Touch the top left corner <br>of your touchpad. + Hãy chạm vào góc trên cùng<br>bên trái trên touchpad của bạn. + + + + Now touch the bottom right corner <br>of your touchpad. + Giờ hãy chạm vào góc dưới cùng<br>bên phải trên touchpad của bạn. + + + + Configuration completed! + Đã hoàn thành quá trình thiết lập! + + + + OK + OK + + + + CompatDB + + + Report Compatibility + Báo cáo tương thích + + + + + Report Game Compatibility + Báo cáo trò chơi tương thích + + + + <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;">Nếu bạn chọn gửi bản kiểm tra vào </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">danh sách tương thích yuzu</span></a><span style=" font-size:10pt;">, Thông tin sau sẽ được thu thập và hiển thị lên trang web:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thông tin phần cứng (CPU / GPU / Hệ điều hành)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Phiên bản yuzu bạn đang chạy</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tài khoản yuzu đang kết nối</li></ul></body></html> + + + + Perfect + Tốt nhất + + + + <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> + <html><head/><body><p>Có thể chơi một cách mượt mà mà không có lỗi âm thanh hoặc đồ họa nào.</p></body></html> + + + + Great + Tốt + + + + <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> + <html><head/><body><p>Có thể chơi từ đầu đến cuối nhưng vẫn có một số lỗi nhỏ về đồ họa hoặc âm thanh. Có thể sẽ cần tới một vài tinh chỉnh nào đó.</p></body></html> + + + + Okay + Tạm ổn + + + + <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> + <html><head/><body><p>Tạm chơi được nhưng có lỗi đồ họa hoặc âm thanh một cách đáng kể, tuy vậy vẫn có thể chơi hết từ đầu đến cuối với một số tinh chỉnh.</p></body></html> + + + + Bad + Không tốt + + + + <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> + <html><head/><body><p>Chơi được nhưng có nhiều lỗi đồ họa hoặc âm thanh. Không thể chơi tiếp ở một số nơi nào đó do lỗi dù có tinh chỉnh thế nào đi nữa.</p></body></html> + + + + Intro/Menu + Phần mở đầu/Menu + + + + <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> + <html><head/><body><p>Hoàn toàn không thể chơi được do có nhiều lỗi đồ họa hoặc âm thanh. Không thể chơi tiếp sau khi bấm nút bắt đầu trò chơi.</p></body></html> + + + + Won't Boot + Không hoạt động + + + + <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> + <html><head/><body><p>Trò chơi sẽ thoát đột ngột khi khởi động.</p></body></html> + + + + <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html> + <html><head/><body><p>Không phụ thuộc vào tốc độ hay hiệu suất, trò chơi này chơi như thế nào từ đầu đến cuối trên phiên bản này của yuzu?</p></body></html> + + + + Thank you for your submission! + Cảm ơn bạn đã gửi đến cho chúng tôi! + + + + Submitting + Đang gửi + + + + Communication error + Đã xảy ra lỗi giao tiếp với máy chủ + + + + An error occurred while sending the Testcase + Có lỗi xảy ra khi gửi Testcase + + + + Next + Tiếp theo + + + + ConfigureAudio + + + + Audio + Âm thanh + + + + Output Engine: + Đầu ra hệ thống: + + + + Audio Device: + Thiết bị âm thanh: + + + + Use global volume + Sử dụng âm lượng trong cài đặt + + + + Set volume: + Âm lượng tuỳ chỉnh: + + + + Volume: + Âm lượng: + + + + 0 % + 0 % + + + + %1% + Volume percentage (e.g. 50%) + %1% + + + + ConfigureCpu + + + Form + Mẫu + + + + CPU + CPU + + + + General + Chung + + + + Accuracy: + Độ chính xác + + + + Auto + Tự động + + + + Accurate + Tuyệt đối + + + + Unsafe + Tương đối + + + + We recommend setting accuracy to "Auto". + Chúng tôi khuyến khích sử dụng chế độ "Tự động" + + + + Unsafe CPU Optimization Settings + Cài đặt tối ưu cho CPU ở chế độ tương đối + + + + These settings reduce accuracy for speed. + Những cài đặt sau giảm độ chính xác của giả lập để đổi lấy tốc độ. + + + + + <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> + + + <div>Chức năng này tăng tốc độ giả lập bằng cách giảm độ chính xác của tập lệnh phép tính gộp cộng và nhân (FMA) trên các dòng CPU không hỗ trợ nó.</div> + + + + + Unfuse FMA (improve performance on CPUs without FMA) + Không dùng FMA (tăng hiệu suất cho các dòng CPU không hỗ trợ FMA) + + + + + <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> + + + <div>Chức năng này cải thiện tốc độ của một số chức năng dấu phẩy động tương đối bằng cách sử dụng tính năng làm tròn kém chính xác hơn.</div> + + + + + Faster FRSQRTE and FRECPE + Chạy FRSQRTE và FRECPE nhanh hơn + + + + + <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> + + + <div>Tùy chọn này cải thiện tốc độ của các hàm dấu phẩy động ASIMD 32 bit bằng cách chạy với các chế độ làm tròn không chính xác.</div> + + + + + Faster ASIMD instructions (32 bits only) + Các lệnh ASIMD nhanh hơn (chỉ áp dụng cho 32 bit) + + + + + <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> + + +<div>Tùy chọn này sẽ cải thiện tốc độ bằng việc gỡ bỏ Kiểm tra NaN. Hãy nhớ là tùy chọn cũng sẽ giảm độ chính xác cho các dòng lệnh floating-point.</div> + + + + + Inaccurate NaN handling + Xử lí NaN gặp lỗi + + + + + <div>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.</div> + + + + + + Disable address space checks + + + + + CPU settings are available only when game is not running. + Cài đặt CPU chỉ có sẵn khi không chạy trò chơi. + + + + ConfigureCpuDebug + + + Form + Mẫu + + + + CPU + CPU + + + + Toggle CPU Optimizations + Tuỳ chọn cho tối ưu CPU + + + + <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Chỉ dành cho việc gỡ lỗi.</span><br/>Nếu bạn không biết những sự lựa chọn này làm gì, hãy bật tất cả.<br/>Những cài đặt này, khi tắt, chỉ hiệu quả khi bật "Gỡ lỗi CPU". </p></body></html> + + + + + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> + + + <div style="white-space: nowrap">Sự tối ưu hóa này làm cho việc truy cập bộ nhớ của chương trình khách nhanh hơn.</div> + <div style="white-space: nowrap">Bật nó giúp PageTable::pointers có thể được truy cập trong mã được phát ra.</div> + <div style="white-space: nowrap">Tắt nó làm cho mọi truy cập vào bộ nhớ bắt buộc phải qua các function Memory::Read/Memory::Write.</div> + + + + + Enable inline page tables + + + + + + <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> + + + + + + Enable block linking + + + + + + <div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div> + + + + + + Enable return stack buffer + + + + + + <div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div> + + + + + + Enable fast dispatcher + + + + + + <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> + + + + + + Enable context elimination + + + + + + <div>Enables IR optimizations that involve constant propagation.</div> + + + + + + Enable constant propagation + + + + + + <div>Enables miscellaneous IR optimizations.</div> + + + + + + Enable miscellaneous optimizations + + + + + + <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> + <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> + + + + + + Enable misalignment check reduction + + + + + + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> + + + + + + Enable Host MMU Emulation + + + + + CPU settings are available only when game is not running. + Cài đặt CPU chỉ có sẵn khi không chạy trò chơi. + + + + ConfigureDebug + + + Logging + Sổ ghi chép + + + + Global Log Filter + Bộ lọc sổ ghi chép + + + + Show Log in Console + + + + + Open Log Location + Mở vị trí sổ ghi chép + + + + When checked, the max size of the log increases from 100 MB to 1 GB + Khi tích vào, dung lượng tối đa cho file log chuyển từ 100 MB lên 1 GB + + + + Enable Extended Logging** + + + + + Homebrew + Homebrew + + + + Arguments String + Chuỗi đối số + + + + Graphics + Đồ hoạ + + + + When checked, the graphics API enters a slower debugging mode + + + + + Enable Graphics Debugging + Kích hoạt chế độ gỡ lỗi đồ hoạ + + + + When checked, it enables Nsight Aftermath crash dumps + + + + + Enable Nsight Aftermath + + + + + When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower + + + + + Disable Macro JIT + Không dùng Macro JIT + + + + When checked, yuzu will log statistics about the compiled pipeline cache + + + + + Enable Shader Feedback + + + + + When checked, it executes shaders without loop logic changes + + + + + Disable Loop safety checks + + + + + Debugging + Vá lỗi + + + + Enable FS Access Log + + + + + Enable Verbose Reporting Services** + + + + + Advanced + Nâng Cao + + + + Kiosk (Quest) Mode + + + + + Enable CPU Debugging + Bật Vá Lỗi CPU + + + + Enable Debug Asserts + + + + + Enable Auto-Stub** + + + + + Enable all Controller Types + + + + + **This will be reset automatically when yuzu closes. + **Sẽ tự động thiết lập lại khi tắt yuzu. + + + + ConfigureDebugController + + + Configure Debug Controller + Thiết lập bộ điều khiển vá lỗi + + + + Clear + Làm trống + + + + Defaults + Quay về mặc định + + + + ConfigureDebugTab + + + Form + + + + + + Debug + Vá lỗi + + + + CPU + CPU + + + + ConfigureDialog + + + yuzu Configuration + Thiết lập yuzu + + + + + Audio + Âm thanh + + + + + CPU + CPU + + + + Debug + Gỡ lỗi + + + + Filesystem + Hệ thống tệp tin + + + + + General + Chung + + + + + Graphics + Đồ hoạ + + + + GraphicsAdvanced + Đồ họa Nâng cao + + + + Hotkeys + Phím tắt + + + + + Controls + Phím + + + + Profiles + Hồ sơ + + + + Network + Mạng + + + + + System + Hệ thống + + + + Game List + Danh sách trò chơi + + + + Web + Web + + + + ConfigureFilesystem + + + Form + + + + + Filesystem + File hệ thống + + + + Storage Directories + Thư mục lưu trữ + + + + NAND + NAND + + + + + + + + ... + ... + + + + SD Card + Thẻ nhớ SD + + + + Gamecard + Thẻ nhớ trò chơi + + + + Path + Đường dẫn + + + + Inserted + Đã chèn vào + + + + Current Game + Game hiện tại + + + + Patch Manager + + + + + Dump Decompressed NSOs + Sao chép NSO đã giải nén + + + + Dump ExeFS + Sao chép ExeFS + + + + Mod Load Root + + + + + Dump Root + + + + + Caching + Bộ nhớ đệm + + + + Cache Game List Metadata + Lưu bộ nhớ đệm của danh sách trò chơi + + + + + + + Reset Metadata Cache + Khôi phục bộ nhớ đệm của metadata + + + + Select Emulated NAND Directory... + Chọn Thư Mục Giả Lập NAND... + + + + Select Emulated SD Directory... + Chọn Thư Mục Giả Lập SD... + + + + Select Gamecard Path... + + + + + Select Dump Directory... + + + + + Select Mod Load Directory... + Chọn Thư Mục Chứa Mod... + + + + The metadata cache is already empty. + + + + + The operation completed successfully. + + + + + The metadata cache couldn't be deleted. It might be in use or non-existent. + + + + + ConfigureGeneral + + + Form + Mẫu + + + + + General + Chung + + + + + Use global framerate cap + + + + + Set framerate cap: + + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. + + + + + Framerate Cap + Giới hạn Tốc độ khung hình + + + + x + x + + + + Limit Speed Percent + Giới hạn phần trăm tốc độ + + + + % + % + + + + Multicore CPU Emulation + Giả lập CPU đa nhân + + + + Confirm exit while emulation is running + Xác nhận thoát trong khi đang chạy giả lập + + + + Prompt for user on game boot + Hiển thị cửa sổ chọn người dùng khi bắt đầu trò chơi + + + + Pause emulation when in background + Tạm dừng giả lập khi chạy nền + + + + Hide mouse on inactivity + Ẩn con trỏ chuột khi không dùng + + + + Reset All Settings + Đặt lại mọi tùy chỉnh + + + + yuzu + yuzu + + + + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? + Quá trình này sẽ thiết lập lại toàn bộ tùy chỉnh và gỡ hết mọi cài đặt cho từng game riêng lẻ. Quá trình này không xóa đường dẫn tới thư mục game, hồ sơ, hay hồ sơ của thiết lập phím. Tiếp tục? + + + + ConfigureGraphics + + + Form + Mẫu + + + + Graphics + Đồ họa + + + + API Settings + Cài đặt API + + + + Shader Backend: + + + + + Device: + Thiết bị đồ hoạ: + + + + API: + API đồ hoạ: + + + + Graphics Settings + Cài đặt đồ hoạ + + + + Use disk pipeline cache + + + + + Use asynchronous GPU emulation + Dùng giả lập GPU không đồng bộ + + + + Accelerate ASTC texture decoding + + + + + NVDEC emulation: + Giả lập NVDEC + + + + No Video Output + Không Video Đầu Ra + + + + CPU Video Decoding + + + + + GPU Video Decoding (Default) + + + + + Fullscreen Mode: + Chế độ Toàn màn hình: + + + + Borderless Windowed + Cửa sổ không viền + + + + Exclusive Fullscreen + Toàn màn hình + + + + Aspect Ratio: + Tỉ lệ khung hình: + + + + Default (16:9) + Mặc định (16:9) + + + + Force 4:3 + Dùng 4:3 + + + + Force 21:9 + Dùng 21:9 + + + + Stretch to Window + Kéo dãn đến cửa sổ phần mềm + + + + Resolution: + + + + + 0.5X (360p/540p) [EXPERIMENTAL] + + + + + 0.75X (540p/810p) [EXPERIMENTAL] + + + + + 1X (720p/1080p) + + + + + 2X (1440p/2160p) + + + + + 3X (2160p/3240p) + + + + + 4X (2880p/4320p) + + + + + 5X (3600p/5400p) + + + + + 6X (4320p/6480p) + + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + + + + + None + + + + + FXAA + + + + + + Use global background color + Dùng màu nền theo cài đặt + + + + Set background color: + Chọn màu nền: + + + + Background Color: + Màu nền: + + + + GLASM (Assembly Shaders, NVIDIA Only) + GLASM (Assembly Shaders, Chỉ Cho NVIDIA) + + + + ConfigureGraphicsAdvanced + + + Form + + + + + Advanced + Nâng cao + + + + Advanced Graphics Settings + Cài đặt đồ hoạ nâng cao + + + + Accuracy Level: + Độ chính xác: + + + + VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + VSync tránh cho màn hình bị "xước", tuy nhiên một số cạc đồ hoạ có hiệu năng chậm hơn khi VSync được kích hoạt. Bật chức năng này nếu nó không ảnh hưởng gì đến hiệu năng. + + + + Use VSync (OpenGL only) + Dùng VSync (chỉ dành cho OpenGL) + + + + Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental. + Kích hoạt tính năng tạo shader không đồng bộ nhằm tránh cho trò chơi bị giật khi tạo shader. Tính năng này vẫn đang thử nghiệm. + + + + Use asynchronous shader building (Hack) + + + + + Enables Fast GPU Time. This option will force most games to run at their highest native resolution. + + + + + Use Fast GPU Time (Hack) + Tăng Tốc Thời Gian GPU (Hack) + + + + Anisotropic Filtering: + Bộ lọc góc nghiêng: + + + + Automatic + + + + + Default + Mặc định + + + + 2x + + + + + 4x + + + + + 8x + + + + + 16x + + + + + ConfigureHotkeys + + + Hotkey Settings + Cài đặt phím nóng + + + + Hotkeys + Phím tắt + + + + Double-click on a binding to change it. + Đúp chuột vào phím đã được thiết lập để thay đổi. + + + + Clear All + Bỏ Trống Hết + + + + Restore Defaults + Khôi phục về mặc định + + + + Action + + + + + Hotkey + Phím tắt + + + + Context + Bối cảnh + + + + + Conflicting Key Sequence + Tổ hợp phím bị xung đột + + + + The entered key sequence is already assigned to: %1 + Tổ hợp phím này đã gán với: %1 + + + + Restore Default + Khôi phục về mặc định + + + + Clear + Xóa + + + + The default key sequence is already assigned to: %1 + Tổ hợp phím này đã gán với: %1 + + + + ConfigureInput + + + ConfigureInput + + + + + + Player 1 + Người chơi 1 + + + + + Player 2 + Người chơi 2 + + + + + Player 3 + Người chơi 3 + + + + + Player 4 + Người chơi 4 + + + + + Player 5 + Người chơi 5 + + + + + Player 6 + Người chơi 6 + + + + + Player 7 + Người chơi 7 + + + + + Player 8 + Người chơi 8 + + + + + Advanced + Nâng cao + + + + Console Mode + Console Mode + + + + Docked + Chế độ cắm TV + + + + Undocked + Chế độ cầm tay + + + + Vibration + Độ rung + + + + + Configure + Thiết lập + + + + Motion + + + + + Controllers + + + + + 1 + 1 + + + + 2 + 2 + + + + 3 + 3 + + + + 4 + 4 + + + + 5 + 5 + + + + 6 + 6 + + + + 7 + 7 + + + + 8 + 8 + + + + Connected + Đã kết nối + + + + Defaults + Quay về mặc định + + + + Clear + Xóa + + + + ConfigureInputAdvanced + + + Configure Input + Thiết lập đầu vào + + + + Joycon Colors + Màu tay cầm Joycon + + + + Player 1 + Người chơi 1 + + + + + + + + + + + L Body + + + + + + + + + + + + L Button + Phím L + + + + + + + + + + + R Body + + + + + + + + + + + + R Button + Phím R + + + + Player 2 + Người chơi 2 + + + + Player 3 + Người chơi 3 + + + + Player 4 + Người chơi 4 + + + + Player 5 + Người chơi 5 + + + + Player 6 + Người chơi 6 + + + + Player 7 + Người chơi 7 + + + + Player 8 + Người chơi 8 + + + + Emulated Devices + + + + + Keyboard + Bàn phím + + + + Mouse + Chuột + + + + Touchscreen + Màn hình cảm ứng + + + + Advanced + Nâng cao + + + + Debug Controller + + + + + + Configure + Thiết lập + + + + Other + Khác + + + + Emulate Analog with Keyboard Input + + + + + Requires restarting yuzu + Phải khởi động lại yuzu + + + + Enable XInput 8 player support (disables web applet) + Bật hỗ trợ XInput cho 8 người (tắt web applet) + + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + + + + + Mouse sensitivity + Độ nhạy chuột + + + + % + % + + + + Motion / Touch + Chuyển động / Cảm ứng + + + + ConfigureInputPlayer + + + Configure Input + Thiết lập đầu vào + + + + Connect Controller + Kết nối Tay cầm + + + + Input Device + Thiết bị Nhập + + + + Profile + Hồ sơ + + + + Save + Lưu + + + + New + Mới + + + + Delete + Xoá + + + + + Left Stick + Cần trái + + + + + + + + + Up + Lên + + + + + + + + + + Left + Trái + + + + + + + + + + Right + Phải + + + + + + + + + Down + Xuống + + + + + + + Pressed + Nhấn + + + + + + + Modifier + + + + + + Range + + + + + + % + % + + + + + Deadzone: 0% + + + + + + Modifier Range: 0% + + + + + D-Pad + D-Pad + + + + + + L + L + + + + + + ZL + ZL + + + + + Minus + Trừ + + + + + Capture + + + + + + + Plus + Cộng + + + + + Home + Home + + + + + + + R + R + + + + + + ZR + ZR + + + + + SL + SL + + + + + SR + SR + + + + Motion 1 + + + + + Motion 2 + + + + + Face Buttons + Nút chức năng + + + + + X + X + + + + + Y + Y + + + + + A + A + + + + + B + B + + + + + Right Stick + Cần phải + + + + + + + Clear + Bỏ trống + + + + + + + [not set] + [không đặt] + + + + + Toggle button + + + + + Invert button + + + + + + Invert axis + + + + + + Set threshold + + + + + Choose a value between 0% and 100% + Chọn một giá trị giữa 0% và 100% + + + + Map Analog Stick + Thiết lập Cần Điều Khiển + + + + After pressing OK, first move your joystick horizontally, and then vertically. +To invert the axes, first move your joystick vertically, and then horizontally. + Sau khi bấm OK, di chuyển cần sang ngang, rồi sau đó sang dọc. +Nếu muốn đảo ngược hướng cần điều khiển, di chuyển cần sang dọc trước, rồi sang ngang. + + + + + Deadzone: %1% + + + + + + Modifier Range: %1% + + + + + + Pro Controller + Tay cầm Pro Controller + + + + Dual Joycons + Joycon đôi + + + + Left Joycon + Joycon Trái + + + + Right Joycon + Joycon Phải + + + + Handheld + + + + + GameCube Controller + Tay cầm GameCube + + + + Poke Ball Plus + + + + + NES Controller + + + + + SNES Controller + + + + + N64 Controller + + + + + Sega Genesis + + + + + Start / Pause + Bắt đầu / Tạm ngưng + + + + Z + Z + + + + Control Stick + + + + + C-Stick + C-Stick + + + + Shake! + Lắc! + + + + [waiting] + [Chờ] + + + + New Profile + Hồ sơ mới + + + + Enter a profile name: + Nhập tên hồ sơ: + + + + + Create Input Profile + Tạo Hồ Sơ Phím + + + + The given profile name is not valid! + Tên hồ sơ không hợp lệ! + + + + Failed to create the input profile "%1" + Quá trình tạo hồ sơ phím "%1" thất bại + + + + Delete Input Profile + Xóa Hồ Sơ Phím + + + + Failed to delete the input profile "%1" + Quá trình xóa hồ sơ phím "%1" thất bại + + + + Load Input Profile + Nạp Hồ Sơ Phím + + + + Failed to load the input profile "%1" + Quá trình nạp hồ sơ phím "%1" thất bại + + + + Save Input Profile + Lưu Hồ Sơ Phím + + + + Failed to save the input profile "%1" + Quá trình lưu hồ sơ phím "%1" thất bại + + + + ConfigureInputProfileDialog + + + Create Input Profile + Tạo Hồ Sơ Phím + + + + Clear + Bỏ trống + + + + Defaults + Mặc định + + + + ConfigureMotionTouch + + + Configure Motion / Touch + Tùy chỉnh Chuột / Cảm Ứng + + + + Touch + Cảm Ứng + + + + UDP Calibration: + + + + + (100, 50) - (1800, 850) + + + + + + + Configure + Cài đặt + + + + Touch from button profile: + + + + + CemuhookUDP Config + + + + + You may use any Cemuhook compatible UDP input source to provide motion and touch input. + + + + + Server: + Server: + + + + Port: + Cổng: + + + + Learn More + + + + + + Test + Thử nghiệm + + + + Add Server + Thêm Server + + + + Remove Server + Xóa Server + + + + <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Tìm hiểu thêm</span></a> + + + + %1:%2 + %1:%2 + + + + + + + + + yuzu + yuzu + + + + Port number has invalid characters + Cổng có kí tự không hợp lệ + + + + Port has to be in range 0 and 65353 + Cổng phải từ 0 đến 65353 + + + + IP address is not valid + Địa chỉ IP không hợp lệ + + + + This UDP server already exists + Server UDP đã tồn tại + + + + Unable to add more than 8 servers + Không thể vượt quá 8 server + + + + Testing + Thử nghiệm + + + + Configuring + Cài đặt + + + + Test Successful + Thử Nghiệm Thành Công + + + + Successfully received data from the server. + Nhận được dữ liệu từ server! + + + + Test Failed + Thử Nghiệm Thất Bại + + + + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. + Không thể nhận được dữ liệu hợp lệ từ server. <br>Hãy chắc chắn server được thiết lập chính xác, từ địa chỉ lẫn cổng phải được thiết lập đúng. + + + + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. + + + + + ConfigureNetwork + + + Form + + + + + Network + Mạng + + + + General + Tổng Quan + + + + Network Interface + + + + + None + Trống + + + + ConfigurePerGame + + + Dialog + + + + + Info + Thông Tin + + + + Name + Tên + + + + Title ID + + + + + Filename + + + + + Format + + + + + Version + Phiên Bản + + + + Size + Dung Lượng + + + + Developer + Nhà Phát Hành + + + + Add-Ons + Bổ Sung + + + + General + Tổng Quan + + + + System + Hệ Thống + + + + CPU + CPU + + + + Graphics + Đồ Họa + + + + Adv. Graphics + Đồ Họa Nâng Cao + + + + Audio + Âm Thanh + + + + Properties + + + + + Use global configuration (%1) + + + + + ConfigurePerGameAddons + + + Form + + + + + Add-Ons + + + + + Patch Name + + + + + Version + Phiên Bản + + + + ConfigureProfileManager + + + Form + + + + + Profiles + Hồ Sơ + + + + Profile Manager + Quản Lý Hồ Sơ + + + + Current User + Người Dùng Hiện Tại + + + + Username + Tên + + + + Set Image + Đặt Hình Ảnh + + + + Add + Thêm + + + + Rename + Đổi Tên + + + + Remove + Gỡ Bỏ + + + + Profile management is available only when game is not running. + Chỉ có thể quản lí hồ sơ khi game không chạy. + + + + %1 +%2 + %1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF)) + %1 +%2 + + + + Enter Username + Điền Tên + + + + Users + Người Dùng + + + + Enter a username for the new user: + Chọn tên cho người dùng mới + + + + Enter a new username: + Chọn một tên mới: + + + + Confirm Delete + Xác nhận xóa + + + + You are about to delete user with name "%1". Are you sure? + Bạn đang xóa người dùng "%1". Bạn chắc chứ? + + + + Select User Image + Chọn Ảnh cho Người Dùng + + + + JPEG Images (*.jpg *.jpeg) + Ảnh JPEG (*.jpg *.jpeg) + + + + Error deleting image + Lỗi khi xóa ảnh + + + + Error occurred attempting to overwrite previous image at: %1. + Có lỗi khi ghi đè ảnh trước tại: %1. + + + + Error deleting file + Lỗi xóa ảnh + + + + Unable to delete existing file: %1. + Không thể xóa ảnh hiện tại: %1. + + + + Error creating user image directory + Lỗi khi tạo thư mục chứa ảnh người dùng + + + + Unable to create directory %1 for storing user images. + Không thể tạo thư mục %1 để chứa ảnh người dùng + + + + Error copying user image + Lỗi chép ảnh người dùng + + + + Unable to copy image from %1 to %2 + Không thể chép ảnh từ %1 sang %2 + + + + Error resizing user image + Lỗi thu phóng ảnh + + + + Unable to resize image + Không thể thu phóng ảnh + + + + ConfigureSystem + + + Form + Mẫu + + + + System + Hệ thống + + + + System Settings + Cài đặt hệ thống + + + + Region: + Vùng: + + + + Auto + Tự động + + + + Default + Mặc định + + + + CET + CET + + + + CST6CDT + CST6CDT + + + + Cuba + + + + + EET + + + + + Egypt + + + + + Eire + + + + + EST + + + + + EST5EDT + + + + + GB + + + + + GB-Eire + + + + + GMT + + + + + GMT+0 + + + + + GMT-0 + + + + + GMT0 + + + + + Greenwich + + + + + Hongkong + + + + + HST + + + + + Iceland + + + + + Iran + + + + + Israel + + + + + Jamaica + + + + + + Japan + + + + + Kwajalein + + + + + Libya + + + + + MET + + + + + MST + + + + + MST7MDT + + + + + Navajo + + + + + NZ + + + + + NZ-CHAT + + + + + Poland + + + + + Portugal + + + + + PRC + + + + + PST8PDT + + + + + ROC + + + + + ROK + + + + + Singapore + + + + + Turkey + + + + + UCT + + + + + Universal + + + + + UTC + + + + + W-SU + + + + + WET + + + + + Zulu + + + + + USA + + + + + Europe + + + + + Australia + + + + + China + + + + + Korea + + + + + Taiwan + + + + + Time Zone: + + + + + Note: this can be overridden when region setting is auto-select + Chú ý: cái này có thể ghi đè khi cài đặt quốc gia là chọn tự động + + + + Japanese (日本語) + Tiếng Nhật (日本語) + + + + English + Tiếng Anh + + + + French (français) + Tiếng Pháp (French) + + + + German (Deutsch) + Tiếng Đức (German) + + + + Italian (italiano) + Tiếng Ý (Italian) + + + + Spanish (español) + Tiếng Tây Ban Nha (Spanish) + + + + Chinese + Tiếng Trung + + + + Korean (한국어) + Tiếng Hàn (Korean) + + + + Dutch (Nederlands) + Tiếng Hà Lan (Dutch) + + + + Portuguese (português) + Tiếng Bồ Đào Nha (Portuguese) + + + + Russian (Русский) + Tiếng Nga (Russian) + + + + Taiwanese + Tiếng Đài Loan + + + + British English + Tiếng Anh UK + + + + Canadian French + Tiếng Pháp Canada + + + + Latin American Spanish + Tiếng Mỹ La-tinh + + + + Simplified Chinese + Tiếng Trung giản thể + + + + Traditional Chinese (正體中文) + Tiếng Trung phồn thể (Traditional Chinese) + + + + Brazilian Portuguese (português do Brasil) + + + + + Custom RTC + + + + + Language + Ngôn ngữ + + + + RNG Seed + Hạt giống RNG + + + + Mono + Mono + + + + Stereo + Stereo + + + + Surround + Surround + + + + Console ID: + ID bàn giao tiếp: + + + + Sound output mode + Chế độ đầu ra âm thanh + + + + d MMM yyyy h:mm:ss AP + + + + + Regenerate + Tạo mới + + + + System settings are available only when game is not running. + Cài đặt hệ thống chỉ khả dụng khi trò chơi không chạy. + + + + This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? + Điều này sẽ thay thế Switch ảo hiện tại của bạn sang một cái mới. Switch ảo hiện tại của bạn sẽ không thể hồi phục lại. Điều này có thể gây ra tác dụng không mong muốn trong trò chơi. Điều này có thể gây thất bại, nếu bạn đang sử dụng thiết lập lưu trữ đã lỗi thời. Tiếp tục? + + + + Warning + Chú ý + + + + Console ID: 0x%1 + ID của máy: 0x%1 + + + + ConfigureTas + + + TAS + + + + + <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> + + + + + To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). + + + + + WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method. + + + + + Settings + + + + + Enable TAS features + + + + + Loop script + + + + + Pause execution during loads + + + + + Script Directory + + + + + Path + + + + + ... + + + + + ConfigureTasDialog + + + TAS Configuration + + + + + Select TAS Load Directory... + + + + + ConfigureTouchFromButton + + + Configure Touchscreen Mappings + + + + + Mapping: + + + + + New + + + + + Delete + + + + + Rename + + + + + Click the bottom area to add a point, then press a button to bind. +Drag points to change position, or double-click table cells to edit values. + + + + + Delete Point + + + + + Button + + + + + X + X axis + X + + + + Y + Y axis + Y + + + + New Profile + + + + + Enter the name for the new profile. + + + + + Delete Profile + + + + + Delete profile %1? + + + + + Rename Profile + + + + + New name: + + + + + [press key] + + + + + ConfigureTouchscreenAdvanced + + + Configure Touchscreen + Thiết lập màn hình cảm ứng + + + + Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing. + Chú ý: Cài đặt trong trang này có thể ảnh hưởng đến hoạt động bên trong giả lập màn hình cảm ứng của yuzu's. Thay đổi chúng có thể dẫn đến hành vi không mong muốn, chẳng hạn như một phần của màn hình cảm ứng sẽ không hoạt động. Bạn chỉ nên sử dụng trang này nếu bạn biết bạn đang làm gì. + + + + Touch Parameters + Thông số cảm ứng + + + + Touch Diameter Y + Đường kính cảm ứng Y + + + + Touch Diameter X + Đường kính cảm ứng X + + + + Rotational Angle + Góc quay + + + + Restore Defaults + Khôi phục về mặc định + + + + ConfigureUI + + + + + None + + + + + Small (32x32) + + + + + Standard (64x64) + + + + + Large (128x128) + + + + + Full Size (256x256) + + + + + Small (24x24) + + + + + Standard (48x48) + + + + + Large (72x72) + + + + + Filename + + + + + Filetype + + + + + Title ID + + + + + Title Name + + + + + ConfigureUi + + + Form + + + + + UI + + + + + General + + + + + Note: Changing language will apply your configuration. + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Show Add-Ons Column + + + + + Game Icon Size: + + + + + Folder Icon Size: + + + + + Row 1 Text: + + + + + Row 2 Text: + + + + + Screenshots + + + + + Ask Where To Save Screenshots (Windows Only) + + + + + Screenshots Path: + + + + + ... + + + + + Select Screenshots Path... + + + + + <System> + <System> + + + + English + Tiếng Anh + + + + ConfigureVibration + + + Configure Vibration + + + + + Vibration + + + + + Player 1 + + + + + + + + + + + + % + + + + + Player 2 + + + + + Player 3 + + + + + Player 4 + + + + + Player 5 + + + + + Player 6 + + + + + Player 7 + + + + + Player 8 + + + + + Settings + + + + + Enable Accurate Vibration + + + + + ConfigureWeb + + + Form + Mẫu + + + + Web + + + + + yuzu Web Service + Dịch vụ Web yuzu + + + + By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information. + Bằng cách cung cấp tên đăng nhập và mã thông báo của bạn, bạn đã chấp thuận sẽ cho phép yuzu thu thập dữ liệu đã sử dụng, trong đó có thể có thông tin nhận dạng người dùng. + + + + + Verify + Xác nhận + + + + Sign up + Đăng ký + + + + Token: + Mã thông báo: + + + + Username: + Tên người dùng: + + + + What is my token? + Mã thông báo của tôi là gì? + + + + Telemetry + Viễn trắc + + + + Share anonymous usage data with the yuzu team + Chia sẽ dữ liệu sử dụng ẩn danh với nhóm yuzu + + + + Learn more + Tìm hiểu thêm + + + + Telemetry ID: + ID Viễn trắc: + + + + Regenerate + Tạo mới + + + + Discord Presence + Hiện diện trên Discord + + + + Show Current Game in your Discord Status + Hiển thị trò chơi hiện tại lên thông tin Discord của bạn + + + + <a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> + <a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Tìm hiểu thêm</span></a> + + + + <a href='https://profile.yuzu-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.yuzu-emu.org/'><span style="text-decoration: underline; color:#039be5;">Đăng ký</span></a> + + + + <a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> + <a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style="text-decoration: underline; color:#039be5;">Mã thông báo của tôi là gì?</span></a> + + + + + Telemetry ID: 0x%1 + ID Viễn trắc: 0x%1 + + + + + Unspecified + + + + + Token not verified + + + + + Token was not verified. The change to your token has not been saved. + + + + + Verifying... + + + + + Verification failed + Xác nhận không thành công + + + + Verification failed. Check that you have entered your token correctly, and that your internet connection is working. + + + + + ControllerDialog + + + Controller P1 + + + + + &Controller P1 + + + + + GMainWindow + + + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Dữ liệu ẩn danh được thu thập</a>để hỗ trợ cải thiện yuzu. <br/><br/>Bạn có muốn chia sẽ dữ liệu sử dụng cho chúng tôi? + + + + Telemetry + Viễn trắc + + + + Loading Web Applet... + + + + + + Disable Web Applet + + + + + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? + + + + + The amount of shaders currently being built + + + + + The current selected resolution scaling multiplier. + + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. + Tốc độ giả lập hiện tại. Giá trị cao hơn hoặc thấp hơn 100% chỉ ra giả lập sẽ chạy nhanh hơn hoặc chậm hơn trên máy Switch + + + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. + Có bao nhiêu khung hình trên mỗi giây mà trò chơi đang hiển thị. Điều này sẽ thay đổi từ trò chơi này đến trò chơi kia và khung cảnh này đến khung cảnh kia. + + + + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. + Thời gian mà giả lập lấy từ khung hình Switch, sẽ không kể đến giới hạn khung hình hoặc v-sync. Đối với tốc độ tối đa mà giả lập nhận được nhiều nhất là ở độ khoảng 16.67 ms. + + + + Invalid config detected + + + + + Handheld controller can't be used on docked mode. Pro controller will be selected. + + + + + DOCK + + + + + VULKAN + VULKAN + + + + OPENGL + OPENGL + + + + &Clear Recent Files + + + + + &Continue + + + + + &Pause + + + + + Warning Outdated Game Format + Chú ý định dạng trò chơi đã lỗi thời + + + + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br><br>For an explanation of the various Switch formats yuzu supports, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our wiki</a>. This message will not be shown again. + Bạn đang sử dụng định dạng danh mục ROM giải mã cho trò chơi này, và đó là một định dạng lỗi thời đã được thay thế bởi những thứ khác như NCA, NAX, XCI, hoặc NSP. Danh mục ROM giải mã có thể thiếu biểu tượng, metadata, và hỗ trợ cập nhật.<br><br>Để giải thích về các định dạng khác nhau của Switch mà yuzu hỗ trợ, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>vui lòng kiểm tra trên wiki của chúng tôi</a>. Thông báo này sẽ không hiển thị lại lần sau. + + + + + Error while loading ROM! + Xảy ra lỗi khi đang nạp ROM! + + + + The ROM format is not supported. + Định dạng ROM này không hỗ trợ. + + + + An error occurred initializing the video core. + Đã xảy ra lỗi khi khởi tạo lõi video. + + + + yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.Ensure that you have the latest graphics drivers for your GPU. + yuzu đã gặp lỗi trong quá trình đang chạy lõi video, vui lòng kiểm tra sổ ghi chép để biết thêm chi tiết. Để biết thêm thông tin về cách truy cập sổ ghi chép, vui lòng xem trang sau: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Làm sao để tải tệp tin sổ ghi chép lên</a>.Hãy chắc rằng bạn đang sử dụng trình điều khiển đồ họa GPU mới nhất. + + + + Error while loading ROM! %1 + %1 signifies a numeric error code. + + + + + %1<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to redump your files.<br>You can refer to the yuzu wiki</a> or the yuzu Discord</a> for help. + %1 signifies an error string. + + + + + An unknown error occurred. Please see the log for more details. + Đã xảy ra lỗi không xác định. Vui lòng kiểm tra sổ ghi chép để biết thêm chi tiết. + + + + (64-bit) + + + + + (32-bit) + + + + + %1 %2 + %1 is the title name. %2 indicates if the title is 64-bit or 32-bit + + + + + Save Data + + + + + Mod Data + + + + + Error Opening %1 Folder + Xảy ra lỗi khi mở %1 thư mục + + + + + Folder does not exist! + Thư mục này không tồn tại! + + + + Error Opening Transferable Shader Cache + + + + + Failed to create the shader cache directory for this title. + + + + + Contents + + + + + Update + + + + + DLC + + + + + Remove Entry + + + + + Remove Installed Game %1? + + + + + + + + + + Successfully Removed + + + + + Successfully removed the installed base game. + + + + + + + Error Removing %1 + + + + + The base game is not installed in the NAND and cannot be removed. + + + + + Successfully removed the installed update. + + + + + There is no update installed for this title. + + + + + There are no DLC installed for this title. + + + + + Successfully removed %1 installed DLC. + + + + + Delete OpenGL Transferable Shader Cache? + + + + + Delete Vulkan Transferable Shader Cache? + + + + + Delete All Transferable Shader Caches? + + + + + Remove Custom Game Configuration? + + + + + Remove File + + + + + + Error Removing Transferable Shader Cache + + + + + + A shader cache for this title does not exist. + + + + + Successfully removed the transferable shader cache. + + + + + Failed to remove the transferable shader cache. + + + + + + Error Removing Transferable Shader Caches + + + + + Successfully removed the transferable shader caches. + + + + + Failed to remove the transferable shader cache directory. + + + + + + Error Removing Custom Configuration + + + + + A custom configuration for this title does not exist. + + + + + Successfully removed the custom game configuration. + + + + + Failed to remove the custom game configuration. + + + + + + RomFS Extraction Failed! + Khai thác RomFS không thành công! + + + + There was an error copying the RomFS files or the user cancelled the operation. + Đã xảy ra lỗi khi sao chép tệp tin RomFS hoặc người dùng đã hủy bỏ hoạt động này. + + + + Full + + + + + Skeleton + + + + + Select RomFS Dump Mode + Chọn chế độ kết xuất RomFS + + + + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. + Vui lòng chọn RomFS mà bạn muốn kết xuất như thế nào.<br>Đầy đủ sẽ sao chép toàn bộ tệp tin vào một danh mục mới trong khi <br>bộ xương chỉ tạo kết cấu danh mục. + + + + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root + + + + + Extracting RomFS... + Khai thác RomFS... + + + + + Cancel + Hủy bỏ + + + + RomFS Extraction Succeeded! + Khai thác RomFS thành công! + + + + The operation completed successfully. + Các hoạt động đã hoàn tất thành công. + + + + Error Opening %1 + + + + + Select Directory + Chọn danh mục + + + + Properties + Thuộc tính + + + + The game properties could not be loaded. + Thuộc tính của trò chơi không thể nạp được. + + + + Switch Executable (%1);;All Files (*.*) + %1 is an identifier for the Switch executable file extensions. + Thực thi Switch (%1);;Tất cả tệp tin (*.*) + + + + Load File + Nạp tệp tin + + + + Open Extracted ROM Directory + Mở danh mục ROM đã trích xuất + + + + Invalid Directory Selected + Danh mục đã chọn không hợp lệ + + + + The directory you have selected does not contain a 'main' file. + Danh mục mà bạn đã chọn không có chứa tệp tin 'main'. + + + + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + Những tệp tin Switch cài được (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + + + Install Files + + + + + %n file(s) remaining + + + + + Installing file "%1"... + Đang cài đặt tệp tin "%1"... + + + + + Install Results + + + + + To avoid possible conflicts, we discourage users from installing base games to the NAND. +Please, only use this feature to install updates and DLC. + + + + + %n file(s) were newly installed + + + + + + %n file(s) were overwritten + + + + + + %n file(s) failed to install + + + + + + System Application + Hệ thống ứng dụng + + + + System Archive + Hệ thống lưu trữ + + + + System Application Update + Cập nhật hệ thống ứng dụng + + + + Firmware Package (Type A) + Gói phần mềm (Loại A) + + + + Firmware Package (Type B) + Gói phần mềm (Loại B) + + + + Game + Trò chơi + + + + Game Update + Cập nhật trò chơi + + + + Game DLC + Nội dung trò chơi có thể tải xuống + + + + Delta Title + Tiêu đề Delta + + + + Select NCA Install Type... + Chọn loại NCA để cài đặt... + + + + Please select the type of title you would like to install this NCA as: +(In most instances, the default 'Game' is fine.) + Vui lòng chọn loại tiêu đề mà bạn muốn cài đặt NCA này: +(Trong hầu hết trường hợp, chọn mặc định 'Game' là tốt nhất.) + + + + Failed to Install + Cài đặt đã không thành công + + + + The title type you selected for the NCA is invalid. + Loại tiêu đề NCA mà bạn chọn nó không hợp lệ. + + + + File not found + Không tìm thấy tệp tin + + + + File "%1" not found + Không tìm thấy "%1" tệp tin + + + + OK + + + + + Missing yuzu Account + Thiếu tài khoản yuzu + + + + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. + Để gửi trường hợp thử nghiệm trò chơi tương thích, bạn phải liên kết tài khoản yuzu.<br><br/>Để liên kết tải khoản yuzu của bạn, hãy đến Giả lập &gt; Thiết lập &gt; Web. + + + + Error opening URL + + + + + Unable to open the URL "%1". + + + + + TAS Recording + + + + + Overwrite file of player 1? + + + + + Amiibo File (%1);; All Files (*.*) + Tệp tin Amiibo (%1);; Tất cả tệp tin (*.*) + + + + Load Amiibo + Nạp dữ liệu Amiibo + + + + Error opening Amiibo data file + Xảy ra lỗi khi mở dữ liệu tệp tin Amiibo + + + + Unable to open Amiibo file "%1" for reading. + Không thể mở tệp tin Amiibo "%1" để đọc. + + + + Error reading Amiibo data file + Xảy ra lỗi khi đọc dữ liệu tệp tin Amiibo + + + + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. + Hoàn toàn không thể đọc được dữ liệu Amiibo. Dự kiến byte sẽ đọc là %1, nhưng byte chỉ có thể đọc là %2. + + + + Error loading Amiibo data + Xảy ra lỗi khi nạp dữ liệu Amiibo + + + + Unable to load Amiibo data. + Không thể nạp dữ liệu Amiibo. + + + + Capture Screenshot + Chụp ảnh màn hình + + + + PNG Image (*.png) + Hình ảnh PNG (*.png) + + + + TAS state: Running %1/%2 + + + + + TAS state: Recording %1 + + + + + TAS state: Idle %1/%2 + + + + + TAS State: Invalid + + + + + &Stop Running + + + + + &Start + + + + + Stop R&ecording + + + + + R&ecord + + + + + Building: %n shader(s) + + + + + Scale: %1x + %1 is the resolution scaling factor + + + + + Speed: %1% / %2% + Tốc độ: %1% / %2% + + + + Speed: %1% + Tốc độ: %1% + + + + Game: %1 FPS (Unlocked) + + + + + Game: %1 FPS + Trò chơi: %1 FPS + + + + Frame: %1 ms + Khung hình: %1 ms + + + + GPU NORMAL + + + + + GPU HIGH + + + + + GPU EXTREME + + + + + GPU ERROR + + + + + NEAREST + + + + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + + + + + FXAA + + + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. + Trò chơi bạn muốn chạy yêu cầu một số tệp tin được sao chép từ thiết từ máy Switch của bạn trước khi bắt đầu chơi.<br/><br/>Để biết thêm thông tin về cách sao chép những tệp tin đó, vui lòng tham khảo những wiki sau: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Sao chép dữ liệu hệ thống và font dùng chung từ máy Switch</a>.<br/><br/>Bạn có muốn trở về danh sách trò chơi? Nếu bạn vẫn tiếp tục thì trò chơi có thể gặp sự cố, dữ liệu lưu tiến trình có thể bị lỗi, hoặc bạn sẽ gặp những lỗi khác. + + + + yuzu was unable to locate a Switch system archive. %1 + + + + + yuzu was unable to locate a Switch system archive: %1. %2 + + + + + System Archive Not Found + Không tìm thấy tệp tin hệ thống + + + + System Archive Missing + Bị thiếu tệp tin hệ thống + + + + yuzu was unable to locate the Switch shared fonts. %1 + yuzu không thể tìm thấy vị trí font dùng chung của Switch. %1 + + + + Shared Fonts Not Found + Không tìm thấy font dùng chung + + + + Shared Font Missing + Bị thiếu font dùng chung + + + + Fatal Error + Lỗi nghiêm trọng + + + + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. + yuzu đã xảy ra lỗi nghiêm trọng, vui lòng kiểm tra sổ ghi chép để biết thêm chi tiết. Để biết thêm thông tin về cách truy cập sổ ghi chép, vui lòng xem trang sau: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Làm sao để tải tệp tin sổ ghi chép lên</a>.<br/><br/>Bạn có muốn trở về danh sách game? Tiếp tục có thể khiến giả lập gặp sự cố, gây hỏng dữ liệu đã lưu, hoặc gây các lỗi khác. + + + + Fatal Error encountered + + + + + Confirm Key Rederivation + Xác nhận mã khóa Rederivation + + + + You are about to force rederive all of your keys. +If you do not know what this means or what you are doing, +this is a potentially destructive action. +Please make sure this is what you want +and optionally make backups. + +This will delete your autogenerated key files and re-run the key derivation module. + Bạn đang muốn bắt buộc làm lại trích dẫn toàn bộ mã khóa của bạn. +Nếu bạn không biết cái này là gì hay bạn đang làm gì, +đây là hành động có khả năng phá hoại. +Hãy chắc rằng đây là điều bạn muốn +và phải tạo ra một bản sao lưu lại. + +Điều này sẽ xóa mã khóa tự động tạo trên tệp tin của bạn và chạy lại mô-đun mã khóa derivation. + + + + Missing fuses + + + + + - Missing BOOT0 + + + + + - Missing BCPKG2-1-Normal-Main + + + + + - Missing PRODINFO + + + + + Derivation Components Missing + + + + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + + + + + Deriving keys... +This may take up to a minute depending +on your system's performance. + Mã khóa xuất phát... +Điều này có thể mất hơn vài phút tùy thuộc +vào hiệu suất hệ thống của bạn. + + + + Deriving Keys + Mã khóa xuất phát + + + + Select RomFS Dump Target + Chọn thư mục để sao chép RomFS + + + + Please select which RomFS you would like to dump. + Vui lòng chọn RomFS mà bạn muốn sao chép. + + + + Are you sure you want to close yuzu? + Bạn có chắc chắn muốn đóng yuzu? + + + + + + yuzu + yuzu + + + + Are you sure you want to stop the emulation? Any unsaved progress will be lost. + Bạn có chắc rằng muốn dừng giả lập? Bất kì tiến trình nào chưa được lưu sẽ bị mất. + + + + The currently running application has requested yuzu to not exit. + +Would you like to bypass this and exit anyway? + Chương trình đang chạy đã yêu cầu yuzu không được thoát. + +Bạn có muốn bỏ qua yêu cầu đó và thoát luôn không? + + + + GRenderWindow + + + OpenGL not available! + Không có sẵn OpenGL! + + + + yuzu has not been compiled with OpenGL support. + + + + + + Error while initializing OpenGL! + Đã xảy ra lỗi khi khởi tạo OpenGL! + + + + Your GPU may not support OpenGL, or you do not have the latest graphics driver. + + + + + Error while initializing OpenGL 4.6! + + + + + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 + + + + + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 + + + + + GameList + + + Name + Tên + + + + Compatibility + Tương thích + + + + Add-ons + Tiện ích ngoài + + + + File type + Loại tệp tin + + + + Size + Kích cỡ + + + + Favorite + + + + + Start Game + + + + + Start Game without Custom Configuration + + + + + Open Save Data Location + Mở vị trí lưu dữ liệu + + + + Open Mod Data Location + Mở vị trí chỉnh sửa dữ liệu + + + + Open Transferable Pipeline Cache + + + + + Remove + + + + + Remove Installed Update + + + + + Remove All Installed DLC + + + + + Remove Custom Configuration + + + + + Remove OpenGL Pipeline Cache + + + + + Remove Vulkan Pipeline Cache + + + + + Remove All Pipeline Caches + + + + + Remove All Installed Contents + + + + + + Dump RomFS + Kết xuất RomFS + + + + Dump RomFS to SDMC + + + + + Copy Title ID to Clipboard + Sao chép ID tiêu đề vào bộ nhớ tạm + + + + Navigate to GameDB entry + Điều hướng đến mục cơ sở dữ liệu trò chơi + + + + Properties + Thuộc tính + + + + Scan Subfolders + + + + + Remove Game Directory + + + + + ▲ Move Up + + + + + ▼ Move Down + + + + + Open Directory Location + + + + + Clear + + + + + GameListItemCompat + + + Perfect + Tốt nhất + + + + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without +any workarounds needed. + Có thể chơi một cách mượt mà mà không có lỗi âm thanh hoặc đồ họa nào, tất cả các chức năng đều hoạt động như ý mà không cần bất kì tinh chỉnh nào. + + + + Great + Tốt + + + + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some +workarounds. + Có thể chơi từ đầu đến cuối nhưng vẫn có một số lỗi nhỏ về đồ họa hoặc âm thanh. Có thể sẽ cần tới một vài tinh chỉnh nào đó. + + + + Okay + Tạm ổn + + + + Game functions with major graphical or audio glitches, but game is playable from start to finish with +workarounds. + Tạm chơi được nhưng có lỗi đồ họa hoặc âm thanh một cách đáng kể, tuy vậy vẫn có thể chơi hết từ đầu đến cuối với một số tinh chỉnh. + + + + Bad + Không tốt + + + + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches +even with workarounds. + Chơi được nhưng có nhiều lỗi đồ họa hoặc âm thanh. Không thể chơi tiếp ở một số nơi nào đó do lỗi dù có tinh chỉnh thế nào đi nữa. + + + + Intro/Menu + Phần mở đầu/Menu + + + + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start +Screen. + Hoàn toàn không thể chơi được do có nhiều lỗi đồ họa hoặc âm thanh. Không thể chơi tiếp sau khi bấm nút bắt đầu trò chơi. + + + + Won't Boot + Không hoạt động + + + + The game crashes when attempting to startup. + Trò chơi sẽ thoát đột ngột khi khởi động. + + + + Not Tested + Chưa ai thử + + + + The game has not yet been tested. + Trò chơi này chưa có ai thử cả. + + + + GameListPlaceholder + + + Double-click to add a new folder to the game list + + + + + GameListSearchField + + + %1 of %n result(s) + + + + + Filter: + Bộ lọc: + + + + Enter pattern to filter + Nhập khuôn để lọc + + + + InstallDialog + + + Please confirm these are the files you wish to install. + Xin hãy xác nhận đây là những tệp tin bạn muốn cài. + + + + Installing an Update or DLC will overwrite the previously installed one. + Cài đặt một tệp tin cập nhật hoặc DLC mới sẽ thay thế những tệp cũ đã cài trước đó. + + + + Install + Cài đặt + + + + Install Files to NAND + + + + + LimitableInputDialog + + + The text can't contain any of the following characters: +%1 + + + + + LoadingScreen + + + Loading Shaders 387 / 1628 + + + + + Loading Shaders %v out of %m + + + + + Estimated Time 5m 4s + + + + + Loading... + Đang tải... + + + + Loading Shaders %1 / %2 + Đang nạp shader %1 / %2 + + + + Launching... + Đang mở... + + + + Estimated Time %1 + Ước tính thời gian %1 + + + + MainWindow + + + yuzu + yuzu + + + + &File + &Tệp tin + + + + &Recent Files + + + + + &Emulation + &Giả lập + + + + &View + &Xem + + + + &Reset Window Size + + + + + &Debugging + + + + + Reset Window Size to &720p + + + + + Reset Window Size to 720p + + + + + Reset Window Size to &900p + + + + + Reset Window Size to 900p + + + + + Reset Window Size to &1080p + + + + + Reset Window Size to 1080p + + + + + &Tools + + + + + &TAS + + + + + &Help + &Trợ giúp + + + + &Install Files to NAND... + + + + + L&oad File... + + + + + Load &Folder... + + + + + E&xit + Th&oát + + + + &Pause + &Tạm dừng + + + + &Stop + &Dừng + + + + &Reinitialize keys... + + + + + &About yuzu + + + + + Single &Window Mode + + + + + Con&figure... + + + + + Display D&ock Widget Headers + + + + + Show &Filter Bar + + + + + Show &Status Bar + + + + + Show Status Bar + Hiển thị thanh trạng thái + + + + F&ullscreen + + + + + &Restart + + + + + Load &Amiibo... + + + + + &Report Compatibility + + + + + Open &Mods Page + + + + + Open &Quickstart Guide + + + + + &FAQ + + + + + Open &yuzu Folder + + + + + &Capture Screenshot + + + + + &Configure TAS... + + + + + Configure C&urrent Game... + + + + + &Start + &Bắt đầu + + + + &Reset + + + + + R&ecord + + + + + MicroProfileDialog + + + &MicroProfile + + + + + OverlayDialog + + + Dialog + + + + + + Cancel + + + + + + OK + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + PlayerControlPreview + + + START/PAUSE + + + + + Charging + + + + + QObject + + + Installed SD Titles + + + + + Installed NAND Titles + + + + + System Titles + + + + + Add New Game Directory + + + + + Favorites + + + + + + Shift + Shift + + + + + Ctrl + Ctrl + + + + + Alt + Alt + + + + + + [not set] + [chưa đặt nút] + + + + Hat %1 %2 + Mũ %1 %2 + + + + + + + + Axis %1%2 + Trục %1%2 + + + + Button %1 + Nút %1 + + + + + + + [unknown] + [không xác định] + + + + Left + + + + + Right + + + + + Down + + + + + Up + + + + + Z + + + + + R + + + + + L + + + + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + + + + + [undefined] + + + + + %1%2 + + + + + [invalid] + + + + + + %1%2Hat %3 + + + + + + + %1%2Axis %3 + + + + + %1%2Axis %3,%4,%5 + + + + + %1%2Motion %3 + + + + + + %1%2Button %3 + + + + + [unused] + [không sử dụng] + + + + QtControllerSelectorDialog + + + Controller Applet + + + + + Supported Controller Types: + + + + + Players: + + + + + 1 - 8 + + + + + P4 + + + + + + + + + + + + + Pro Controller + + + + + + + + + + + + + Dual Joycons + + + + + + + + + + + + + Left Joycon + + + + + + + + + + + + + Right Joycon + + + + + + + + + + + + Use Current Config + + + + + P2 + + + + + P1 + + + + + + Handheld + + + + + P3 + + + + + P7 + + + + + P8 + + + + + P5 + + + + + P6 + + + + + Console Mode + + + + + Docked + + + + + Undocked + + + + + Vibration + + + + + + Configure + + + + + Motion + + + + + Profiles + + + + + Create + + + + + Controllers + + + + + 1 + + + + + 2 + + + + + 4 + + + + + 3 + + + + + Connected + + + + + 5 + + + + + 7 + + + + + 6 + + + + + 8 + + + + + GameCube Controller + + + + + QtErrorDisplay + + + + + Error Code: %1-%2 (0x%3) + + + + + An error has occurred. +Please try again or contact the developer of the software. + + + + + An error occurred on %1 at %2. +Please try again or contact the developer of the software. + + + + + An error has occurred. + +%1 + +%2 + + + + + QtProfileSelectionDialog + + + %1 +%2 + %1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF)) + %1 +%2 + + + + Select a user: + Chọn một người dùng: + + + + Users + + + + + Profile Selector + Chọn hồ sơ + + + + QtSoftwareKeyboardDialog + + + Software Keyboard + Phần mềm bàn phím + + + + Enter Text + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + OK + + + + + Cancel + + + + + SequenceDialog + + + Enter a hotkey + + + + + WaitTreeCallstack + + + Call stack + Chùm cuộc gọi + + + + WaitTreeMutexInfo + + + waiting for mutex 0x%1 + chờ đợi loại trừ lẫn nhau 0x%1 + + + + has waiters: %1 + đã chờ đợi: %1 + + + + owner handle: 0x%1 + chủ điều khiển: 0x%1 + + + + WaitTreeObjectList + + + waiting for all objects + chờ đợi toàn bộ đối tượng + + + + waiting for one of the following objects + chờ đợi một đối tượng đang theo dõi + + + + WaitTreeSynchronizationObject + + + [%1] %2 %3 + + + + + waited by no thread + + + + + WaitTreeThread + + + runnable + + + + + paused + tạm dừng + + + + sleeping + ngủ + + + + waiting for IPC reply + chờ đợi IPC phản hồi + + + + waiting for objects + chờ đợi đối tượng + + + + waiting for condition variable + + + + + waiting for address arbiter + chờ đợi địa chỉ người đứng giữa + + + + waiting for suspend resume + + + + + waiting + + + + + initialized + + + + + terminated + + + + + unknown + + + + + PC = 0x%1 LR = 0x%2 + PC = 0x%1 LR = 0x%2 + + + + ideal + + + + + core %1 + lõi %1 + + + + processor = %1 + bộ xử lý = %1 + + + + ideal core = %1 + lõi lý tưởng = %1 + + + + affinity mask = %1 + che đậy tánh giống nhau = %1 + + + + thread id = %1 + id luồng = %1 + + + + priority = %1(current) / %2(normal) + quyền ưu tiên = %1(hiện tại) / %2(bình thường) + + + + last running ticks = %1 + lần chạy cuối cùng = %1 + + + + not waiting for mutex + không có chờ đợi loại trừ lẫn nhau + + + + WaitTreeThreadList + + + waited by thread + chờ đợi bởi vì có luồng + + + + WaitTreeWidget + + + &Wait Tree + + + + \ No newline at end of file diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts index 488ca8dce..164cfbe14 100644 --- a/dist/languages/zh_CN.ts +++ b/dist/languages/zh_CN.ts @@ -663,7 +663,12 @@ p, li { white-space: pre-wrap; } 启用自动函数打桩(Auto-Stub)** - + + Enable all Controller Types + 启用其他控制器 + + + **This will be reset automatically when yuzu closes. **该选项将在 yuzu 关闭时自动重置。 @@ -943,67 +948,78 @@ p, li { white-space: pre-wrap; } 通用 - - Framerate Cap - 帧率限制 + + + Use global framerate cap + 使用全局帧率限制 - + + Set framerate cap: + 设置帧率限制: + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. 使用 FPS 限制器的热键才能进行运行速度的切换。 - + + Framerate Cap + 帧率限制 + + + x x - + Limit Speed Percent 运行速度限制 - + % % - + Multicore CPU Emulation 多核 CPU 仿真 - + Confirm exit while emulation is running 在游戏运行时退出需要确认 - + Prompt for user on game boot 游戏启动时提示选择用户 - + Pause emulation when in background 模拟器位于后台时暂停模拟 - + Hide mouse on inactivity 自动隐藏鼠标光标 - + Reset All Settings 重置所有设置项 - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? 将重置模拟器所有设置并删除所有游戏的单独设置。这不会删除游戏目录、个人文件及输入配置文件。是否继续? @@ -1121,18 +1137,113 @@ p, li { white-space: pre-wrap; } 拉伸窗口 - - + + Resolution: + 画面分辨率: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [实验性] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [实验性] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + 窗口滤镜: + + + + Nearest Neighbor + 近邻取样 + + + + Bilinear + 双线性过滤 + + + + Bicubic + 双三线过滤 + + + + Gaussian + 高斯模糊 + + + + ScaleForce + 强制缩放 + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + AMD FidelityFX™️ 超高清技术 [仅限 Vulkan 模式] + + + + Anti-Aliasing Method: + 抗锯齿方式: + + + + None + + + + + FXAA + 快速近似抗锯齿 + + + + Use global background color 使用全局背景颜色 - + Set background color: 设置背景颜色: - + Background Color: 背景颜色: @@ -1201,28 +1312,33 @@ p, li { white-space: pre-wrap; } + Automatic + 自动 + + + Default 系统默认 - - - 2x (WILL BREAK THINGS) - 2x (可能有问题) - - 4x (WILL BREAK THINGS) - 4x (可能有问题) + 2x + 2x - 8x (WILL BREAK THINGS) - 8x (可能有问题) + 4x + 4x - 16x (WILL BREAK THINGS) - 16x (可能有问题) + 8x + 8x + + + + 16x + 16x @@ -1549,8 +1665,8 @@ p, li { white-space: pre-wrap; } - Other - 其他 + Emulated Devices + 模拟设备 @@ -1559,66 +1675,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - 使用键盘输入映射模拟摇杆 - - - - Enable mouse panning - 启用鼠标平移 - - - - Mouse sensitivity - 鼠标灵敏度 - - - - % - % - - - - - Advanced - 高级选项 - - - - Touchscreen - 触摸屏 - - - Mouse 鼠标 - - Motion / Touch - 体感/触摸 + + Touchscreen + 触摸屏 - - - Configure - 设置 + + Advanced + 高级选项 - + Debug Controller 控制器调试 - + + + Configure + 设置 + + + + Other + 其他 + + + + Emulate Analog with Keyboard Input + 使用键盘输入映射模拟摇杆 + + + Requires restarting yuzu 需要重启 yuzu - + Enable XInput 8 player support (disables web applet) 启用 XInput 8 输入支持 (禁用 web 应用程序) + + + Enable UDP controllers (not needed for motion) + 启用 UDP 控制器 (无需运动) + + + + Enable mouse panning + 启用鼠标平移 + + + + Mouse sensitivity + 鼠标灵敏度 + + + + % + % + + + + Motion / Touch + 体感/触摸 + ConfigureInputPlayer @@ -1633,425 +1758,441 @@ p, li { white-space: pre-wrap; } 连接控制器 - - - - Pro Controller - Pro Controller - - - - - Dual Joycons - 双 Joycons 手柄 - - - - - Left Joycon - 左 Joycon 手柄 - - - - - Right Joycon - 右 Joycon 手柄 - - - - - Handheld - 掌机模式 - - - + Input Device 输入设备 - - Any - 任意 - - - - Keyboard/Mouse - 键盘/鼠标 - - - + Profile 用户配置 - + Save 保存 - + New 新建 - + Delete 删除 - - + + Left Stick 左摇杆 - - - - - - + + + + + + Up - - - - - - - + + + + + + + Left - - - - - - - + + + + + + + Right - - - - - - + + + + + + Down - - - - + + + + Pressed 按下 - - - - + + + + Modifier 轻推 - - + + Range 灵敏度 - - + + % % - - + + Deadzone: 0% 摇杆死区:0% - - + + Modifier Range: 0% 摇杆灵敏度:0% - + D-Pad 十字方向键 - - - + + + L L - - - + + + ZL ZL - - + + Minus - - + + Capture 截图 - - - + + + Plus - - + + Home Home - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 体感 1 - + Motion 2 体感 2 - + Face Buttons 主要按键 - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick 右摇杆 - - - - + + + + Clear 清除 - - - - + + + + [not set] [未设置] - - + + Toggle button 切换按键 - - + + Invert button + 反转按钮 + + + + + Invert axis + 体感方向倒置 + + + + Set threshold 阈值设定 - + Choose a value between 0% and 100% 选择一个介于 0% 和 100% 之间的值 - + Map Analog Stick 映射摇杆 - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. 在按下确定后,首先水平移动你的手柄,然后垂直移动它。 如果要使体感方向倒置,首先垂直移动你的手柄,然后水平移动它。 - - Invert axis - 体感方向倒置 - - - - + + Deadzone: %1% 摇杆死区:%1% - - + + Modifier Range: %1% 摇杆灵敏度:%1% - + + + Pro Controller + Pro Controller + + + + Dual Joycons + 双 Joycons 手柄 + + + + Left Joycon + 左 Joycon 手柄 + + + + Right Joycon + 右 Joycon 手柄 + + + + Handheld + 掌机模式 + + + GameCube Controller GameCube 控制器 - + + Poke Ball Plus + 精灵球 PLUS + + + + NES Controller + NES 控制器 + + + + SNES Controller + SNES 控制器 + + + + N64 Controller + N64 控制器 + + + + Sega Genesis + 世嘉创世纪 + + + Start / Pause 开始 / 暂停 - + Z Z - + Control Stick 控制摇杆 - + C-Stick C 摇杆 - + Shake! 摇动! - + [waiting] [等待中] - + New Profile 保存自定义设置 - + Enter a profile name: 输入配置文件名称: - - + + Create Input Profile 新建输入配置文件 - + The given profile name is not valid! 输入的配置文件名称无效! - + Failed to create the input profile "%1" 新建输入配置文件 "%1" 失败 - + Delete Input Profile 删除输入配置文件 - + Failed to delete the input profile "%1" 删除输入配置文件 "%1" 失败 - + Load Input Profile 加载输入配置文件 - + Failed to load the input profile "%1" 加载输入配置文件 "%1" 失败 - + Save Input Profile 保存输入配置文件 - + Failed to save the input profile "%1" 保存输入配置文件 "%1" 失败 @@ -2077,85 +2218,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch 体感/触摸设置 - - Mouse Motion - 鼠标体感 - - - - Sensitivity: - 灵敏度: - - - + Touch 触摸 - + UDP Calibration: UDP 校准: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure 设置 - - Use button mapping: - 使用按键映射: + + Touch from button profile: + 触摸屏映射配置文件: - + CemuhookUDP Config CemuhookUDP 设置 - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. 您可以使用任何与 Cemuhook 兼容的 UDP 输入源来提供体感和触摸输入。 - + Server: 服务器: - + Port: 端口: - + Learn More 了解更多 - - + + Test 测试 - + Add Server 添加服务器 - + Remove Server 移除服务器 @@ -2165,145 +2296,81 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters 端口号中包含无效字符 - + Port has to be in range 0 and 65353 端口必须为 0 到 65353 之间 - + IP address is not valid 无效的 IP 地址 - + This UDP server already exists 此 UDP 服务器已存在 - + Unable to add more than 8 servers 最多只能添加 8 个服务器 - + Testing 测试中 - + Configuring 配置中 - + Test Successful 测试成功 - + Successfully received data from the server. 已成功地从服务器获取数据。 - + Test Failed 测试失败 - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. 无法从服务器获取数据。<br>请验证服务器是否正在运行,以及地址和端口是否配置正确。 - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP 测试或触摸校准正在进行中。<br>请耐心等待。 - - ConfigureMouseAdvanced - - - Configure Mouse - 鼠标设置 - - - - Mouse Buttons - 鼠标按键 - - - - Forward: - 前: - - - - Back: - 后: - - - - Left: - 左: - - - - Middle: - 中: - - - - Right: - 右: - - - - - Clear - 清除 - - - - Defaults - 系统默认 - - - - [not set] - [未设置] - - - - Restore Default - 恢复默认 - - - - [press key] - [请按一个键] - - ConfigureNetwork @@ -3087,31 +3154,26 @@ To invert the axes, first move your joystick vertically, and then horizontally.< - Automatic controller profile swapping - 自动切换手柄配置文件 - - - Loop script 循环脚本 - + Pause execution during loads 遇到载入画面时暂停执行 - + Script Directory 脚本目录 - + Path 路径 - + ... ... @@ -3124,7 +3186,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< TAS 设置 - + Select TAS Load Directory... 选择 TAS 载入目录... @@ -3186,37 +3248,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile 保存自定义设置 - + Enter the name for the new profile. 为新的自定义设置命名。 - + Delete Profile 删除自定义设置 - + Delete profile %1? 真的要删除自定义设置 %1 吗? - + Rename Profile 重命名自定义设置 - + New name: 新名称: - + [press key] [请按一个键] @@ -3636,12 +3698,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 控制器 P1 - + &Controller P1 控制器 P1 (&C) @@ -3649,90 +3711,95 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? <a href='https://yuzu-emu.org/help/feature/telemetry/'>我们收集匿名数据</a>来帮助改进 yuzu 。<br/><br/>您愿意和我们分享您的使用数据吗? - + Telemetry 使用数据共享 - + Loading Web Applet... 正在加载 Web 应用程序... - - + + Disable Web Applet 禁用 Web 应用程序 - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? 禁用 web 程序将导致它在模拟窗口中不再显示。这可能导致未知的后果,且只能用于《超级马里奥 3D 全明星》中。您确定要禁用 web 程序吗? - + The amount of shaders currently being built - 当前正在构建的着色器的数量 + 当前正在构建的着色器数量 - + + The current selected resolution scaling multiplier. + 当前选定的分辨率缩放比例。 + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 当前的模拟速度。高于或低于 100% 的值表示模拟正在运行得比实际 Switch 更快或更慢。 - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 游戏当前运行的帧率。这将因游戏和场景的不同而有所变化。 - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 在不计算速度限制和垂直同步的情况下,模拟一个 Switch 帧的实际时间。若要进行全速模拟,这个数值不应超过 16.67 毫秒。 - + Invalid config detected 检测到无效配置 - + Handheld controller can't be used on docked mode. Pro controller will be selected. 掌机手柄无法在主机模式中使用。将会选择 Pro controller。 - + DOCK 主机模式 - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files 清除最近文件 (&C) - - TAS Recording - TAS 录制 + + &Continue + 继续 (&C) - - Overwrite file of player 1? - 覆盖玩家 1 的文件? + + &Pause + 暂停 (&P) @@ -3783,660 +3850,727 @@ Drag points to change position, or double-click table cells to edit values.发生了未知错误。请查看日志了解详情。 - + (64-bit) (64-bit) - + (32-bit) (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - 开始 - - - + Save Data 保存数据 - + Mod Data Mod 数据 - + Error Opening %1 Folder 打开 %1 文件夹时出错 - - + + Folder does not exist! 文件夹不存在! - + Error Opening Transferable Shader Cache 打开可转移着色器缓存时出错 - + Failed to create the shader cache directory for this title. 为该游戏创建着色器缓存目录时失败。 - + Contents 目录 - + Update 游戏更新 - + DLC DLC - + Remove Entry 删除项目 - + Remove Installed Game %1? 删除已安装的游戏 %1 ? - - - - - - + + + + + + Successfully Removed 删除成功 - + Successfully removed the installed base game. 成功删除已安装的游戏。 - - - + + + Error Removing %1 删除 %1 时出错 - + The base game is not installed in the NAND and cannot be removed. 该游戏未安装于 NAND 中,无法删除。 - + Successfully removed the installed update. 成功删除已安装的游戏更新。 - + There is no update installed for this title. 这个游戏没有任何已安装的更新。 - + There are no DLC installed for this title. 这个游戏没有任何已安装的 DLC 。 - + Successfully removed %1 installed DLC. 成功删除游戏 %1 安装的 DLC 。 - + Delete OpenGL Transferable Shader Cache? 删除 OpenGL 模式的着色器缓存? - + Delete Vulkan Transferable Shader Cache? 删除 Vulkan 模式的着色器缓存? - + Delete All Transferable Shader Caches? 删除所有的着色器缓存? - + Remove Custom Game Configuration? 移除自定义游戏设置? - + Remove File 删除文件 - - + + Error Removing Transferable Shader Cache 删除着色器缓存时出错 - - + + A shader cache for this title does not exist. 这个游戏的着色器缓存不存在。 - + Successfully removed the transferable shader cache. 成功删除着色器缓存。 - + Failed to remove the transferable shader cache. 删除着色器缓存失败。 - - + + Error Removing Transferable Shader Caches 删除着色器缓存时出错 - + Successfully removed the transferable shader caches. 着色器缓存删除成功。 - + Failed to remove the transferable shader cache directory. 删除着色器缓存目录失败。 - - + + Error Removing Custom Configuration 移除自定义游戏设置时出错 - + A custom configuration for this title does not exist. 这个游戏的自定义设置不存在。 - + Successfully removed the custom game configuration. 成功移除自定义游戏设置。 - + Failed to remove the custom game configuration. 移除自定义游戏设置失败。 - - + + RomFS Extraction Failed! RomFS 提取失败! - + There was an error copying the RomFS files or the user cancelled the operation. 复制 RomFS 文件时出错,或用户取消了操作。 - + Full 完整 - + Skeleton 框架 - + Select RomFS Dump Mode 选择 RomFS 转储模式 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. 请选择希望 RomFS 转储的方式。<br>“Full” 会将所有文件复制到新目录中,而<br>“Skeleton” 只会创建目录结构。 - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root %1 没有足够的空间用于提取 RomFS。请保持足够的空间或于模拟—>设置—>系统—>文件系统—>转储根目录中选择一个其他目录。 - + Extracting RomFS... 正在提取 RomFS... - - + + Cancel 取消 - + RomFS Extraction Succeeded! RomFS 提取成功! - + The operation completed successfully. 操作成功完成。 - + Error Opening %1 打开 %1 时出错 - + Select Directory 选择目录 - + Properties 属性 - + The game properties could not be loaded. 无法加载该游戏的属性信息。 - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch 可执行文件 (%1);;所有文件 (*.*) - + Load File 加载文件 - + Open Extracted ROM Directory 打开提取的 ROM 目录 - + Invalid Directory Selected 选择的目录无效 - + The directory you have selected does not contain a 'main' file. 选择的目录不包含 “main” 文件。 - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) 可安装的 Switch 文件 (*.nca *.nsp *.xci);;任天堂内容档案 (*.nca);;任天堂应用包 (*.nsp);;NX 卡带镜像 (*.xci) - + Install Files 安装文件 - + %n file(s) remaining 剩余 %n 个文件 - + Installing file "%1"... 正在安装文件 "%1"... - - + + Install Results 安装结果 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. 为了避免可能存在的冲突,我们不建议将游戏本体安装到 NAND 中。 此功能仅用于安装游戏更新和 DLC 。 - + %n file(s) were newly installed 最近安装了 %n 个文件 - + %n file(s) were overwritten %n 个文件被覆盖 - + %n file(s) failed to install %n 个文件安装失败 - + System Application 系统应用 - + System Archive 系统档案 - + System Application Update 系统应用更新 - + Firmware Package (Type A) 固件包 (A型) - + Firmware Package (Type B) 固件包 (B型) - + Game 游戏 - + Game Update 游戏更新 - + Game DLC 游戏 DLC - + Delta Title 差量程序 - + Select NCA Install Type... 选择 NCA 安装类型... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) 请选择此 NCA 的程序类型: (在大多数情况下,选择默认的“游戏”即可。) - + Failed to Install 安装失败 - + The title type you selected for the NCA is invalid. 选择的 NCA 程序类型无效。 - + File not found 找不到文件 - + File "%1" not found 文件 "%1" 未找到 - - - &Continue - 继续 (&C) - - - + OK 确定 - + Missing yuzu Account 未设置 yuzu 账户 - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. 要提交游戏兼容性测试用例,您必须设置您的 yuzu 帐户。<br><br/>要设置您的 yuzu 帐户,请转到模拟 &gt; 设置 &gt; 网络。 - + Error opening URL 打开 URL 时出错 - + Unable to open the URL "%1". 无法打开 URL : "%1" 。 - + + TAS Recording + TAS 录制 + + + + Overwrite file of player 1? + 覆盖玩家 1 的文件? + + + Amiibo File (%1);; All Files (*.*) Amiibo 文件 (%1);; 全部文件 (*.*) - + Load Amiibo 加载 Amiibo - + Error opening Amiibo data file 打开 Amiibo 数据文件时出错 - + Unable to open Amiibo file "%1" for reading. 无法打开 Amiibo 文件 %1。 - + Error reading Amiibo data file 读取 Amiibo 数据文件时出错 - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. 无法完全读取 Amiibo 数据。应读取 %1 个字节,但实际仅能读取 %2 个字节。 - + Error loading Amiibo data 加载 Amiibo 数据时出错 - + Unable to load Amiibo data. 无法加载 Amiibo 数据。 - + Capture Screenshot 捕获截图 - + PNG Image (*.png) PNG 图像 (*.png) - + TAS state: Running %1/%2 TAS 状态:正在运行 %1/%2 - + TAS state: Recording %1 TAS 状态:正在录制 %1 - + TAS state: Idle %1/%2 TAS 状态:空闲 %1/%2 - + TAS State: Invalid TAS 状态:无效 + + + &Stop Running + 停止运行 (&S) + + + + &Start + 开始 (&S) + + + + Stop R&ecording + 停止录制 (&E) + + + + R&ecord + 录制 (&E) + - + Building: %n shader(s) 正在编译 %n 个着色器文件 - + + Scale: %1x + %1 is the resolution scaling factor + 缩放比例: %1x + + + Speed: %1% / %2% 速度: %1% / %2% - + Speed: %1% 速度: %1% - + Game: %1 FPS (Unlocked) 游戏: %1 FPS (未锁定) - + Game: %1 FPS FPS: %1 - + Frame: %1 ms 帧延迟:%1 毫秒 - + GPU NORMAL GPU NORMAL - + GPU HIGH GPU HIGH - + GPU EXTREME GPU EXTREME - + GPU ERROR GPU ERROR - + + NEAREST + 邻近取样 + + + + + BILINEAR + 双线性过滤 + + + + BICUBIC + 双三线过滤 + + + + GAUSSIAN + 高斯模糊 + + + + SCALEFORCE + 强制缩放 + + + + FSR + FSR + + + + + NO AA + 抗锯齿关 + + + + FXAA + FXAA + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. 您正尝试启动的游戏需要从 Switch 转储的其他文件。<br/><br/>有关转储这些文件的更多信息,请参阅以下 wiki 页面:<a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>。<br/><br/>您要退出并返回至游戏列表吗?继续模拟可能会导致崩溃,存档损坏或其他错误。 - + yuzu was unable to locate a Switch system archive. %1 Yuzu 找不到 Switch 系统档案 %1 - + yuzu was unable to locate a Switch system archive: %1. %2 Yuzu 找不到 Switch 系统档案: %1, %2 - + System Archive Not Found 未找到系统档案 - + System Archive Missing 系统档案缺失 - + yuzu was unable to locate the Switch shared fonts. %1 Yuzu 找不到 Swtich 共享字体 %1 - + Shared Fonts Not Found 未找到共享字体 - + Shared Font Missing 共享字体文件缺失 - + Fatal Error 致命错误 - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu 遇到了致命错误,请查看日志了解详情。有关查找日志的更多信息,请参阅以下页面:<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>。<br/><br/>您要退出并返回至游戏列表吗?继续模拟可能会导致崩溃,存档损坏或其他错误。 - + Fatal Error encountered 发生致命错误 - + Confirm Key Rederivation 确认重新生成密钥 - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4452,37 +4586,37 @@ This will delete your autogenerated key files and re-run the key derivation modu 这将删除您自动生成的密钥文件并重新运行密钥生成模块。 - + Missing fuses 项目丢失 - + - Missing BOOT0 - 丢失 BOOT0 - + - Missing BCPKG2-1-Normal-Main - 丢失 BCPKG2-1-Normal-Main - + - Missing PRODINFO - 丢失 PRODINFO - + Derivation Components Missing 组件丢失 - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - 缺少组件可能会影响游戏的正常运行。<br>请查看<a href='https://yuzu-emu.org/help/quickstart/'>yuzu 快速导航</a>以获得你的密钥和游戏。<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + 密钥缺失。<br>请查看<a href='https://yuzu-emu.org/help/quickstart/'>yuzu 快速导航</a>以获得你的密钥、固件和游戏。<br><br><small>(%1)</small> - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4491,39 +4625,39 @@ on your system's performance. 您的系统性能。 - + Deriving Keys 生成密钥 - + Select RomFS Dump Target 选择 RomFS 转储目标 - + Please select which RomFS you would like to dump. 请选择希望转储的 RomFS。 - + Are you sure you want to close yuzu? 您确定要关闭 yuzu 吗? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. 您确定要停止模拟吗?未保存的进度将会丢失。 - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4535,38 +4669,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! OpenGL 模式不可用! - + yuzu has not been compiled with OpenGL support. yuzu 没有使用 OpenGL 进行编译。 - - + + Error while initializing OpenGL! 初始化 OpenGL 时出错! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 您的 GPU 可能不支持 OpenGL ,或者您没有安装最新的显卡驱动。 - + Error while initializing OpenGL 4.6! 初始化 OpenGL 4.6 时出错! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支持 OpenGL 4.6 ,或者您没有安装最新的显卡驱动。<br><br>GL 渲染器:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 您的 GPU 可能不支持某些必需的 OpenGL 扩展。请确保您已经安装最新的显卡驱动。<br><br>GL 渲染器:<br>%1<br><br>不支持的扩展:<br>%2 @@ -4923,190 +5057,205 @@ Screen. 模拟 (&E) - + &View 视图 (&V) - + &Reset Window Size 重置窗口大小 (&R) - - Reset Window Size to &720p - 重置窗口大小为720p (&7) - - - - Reset Window Size to 720p - 重置窗口大小为720p - - - - Reset Window Size to &900p - 重置窗口大小为900p (&9) - - - - Reset Window Size to 900p - 重置窗口大小为900p - - - - Reset Window Size to &1080p - 重置窗口大小为1080p (&1) - - - - Reset Window Size to 1080p - 重置窗口大小为1080p - - - + &Debugging 调试 (&D) - + + Reset Window Size to &720p + 重置窗口大小为720p (&7) + + + + Reset Window Size to 720p + 重置窗口大小为720p + + + + Reset Window Size to &900p + 重置窗口大小为900p (&9) + + + + Reset Window Size to 900p + 重置窗口大小为900p + + + + Reset Window Size to &1080p + 重置窗口大小为1080p (&1) + + + + Reset Window Size to 1080p + 重置窗口大小为1080p + + + &Tools 工具 (&T) - + + &TAS + TAS (&T) + + + &Help 帮助 (&H) - + &Install Files to NAND... 安装文件到 NAND... (&I) - + L&oad File... 加载文件... (&O) - + Load &Folder... 加载文件夹... (&F) - + E&xit 退出 (&X) - - &Start - 开始 (&S) - - - + &Pause 暂停 (&P) - + &Stop 停止 (&S) - + &Reinitialize keys... 重新生成密钥... (&R) - + &About yuzu 关于 yuzu (&A) - + Single &Window Mode 单窗口模式 (&W) - + Con&figure... 设置... (&F) - + Display D&ock Widget Headers 显示停靠小部件的标题 (&O) - + Show &Filter Bar 显示搜索栏 (&F) - + Show &Status Bar 显示状态栏 (&S) - + Show Status Bar 显示状态栏 - + F&ullscreen 全屏 (&U) - + &Restart 重新启动 (&R) - + Load &Amiibo... 加载 Amiibo... (&A) - + &Report Compatibility 报告兼容性 (&R) - + Open &Mods Page 打开 Mod 页面 (&M) - + Open &Quickstart Guide 查看快速导航 (&Q) - + &FAQ FAQ (&F) - + Open &yuzu Folder 打开 yuzu 文件夹 (&Y) - + &Capture Screenshot 捕获截图 (&C) - - Configure &TAS... - 配置 TAS… (&T) + + &Configure TAS... + 配置 TAS... (&C) - + Configure C&urrent Game... 配置当前游戏... (&U) + + + &Start + 开始 (&S) + + + + &Reset + 重置 (&R) + + + + R&ecord + 录制 (&E) + MicroProfileDialog @@ -5152,10 +5301,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE 开始/暂停 + + + Charging + 充电中 + QObject @@ -5186,142 +5340,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [未设置] - - Hat %1 %2 方向键 %1 %2 - - - - - - + + + + Axis %1%2 轴 %1%2 - Button %1 按键 %1 - - - + + + [unknown] [未知] - + + Left + + + + + Right + + + - Click 0 - 点击 0 + Down + - - Click 1 - 点击 1 + Up + - - Click 2 - 点击 2 + Z + Z - - Click 3 - 点击 3 + R + R - - Click 4 - 点击 4 + L + L - + + A + A + + + + B + B + + + + X + X + + + + Y + Y + + + + Start + 开始 + + + + L1 + L1 + + + + L2 + L2 + + + + L3 + L3 + + + + R1 + R1 + + + + R2 + R2 + + + + R3 + R3 + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + Δ + + + + Share + 分享 + + + + Options + 选项 + + + + [undefined] + [未指定] + + + %1%2 %1%2 - - GC Axis %1%2 - GC 轴 %1%2 + + [invalid] + [无效] - - GC Button %1 - GC 按键 %1 + + + %1%2Hat %3 + %1%2Hat 控制器 %3 - - TAS Axis %1 - TAS 轴 %1 + + + + %1%2Axis %3 + %1%2轴 %3 - - TAS Btn %1 - TAS 按钮 %1 + + %1%2Axis %3,%4,%5 + %1%2轴 %3,%4,%5 - - Motion %1 - 体感 %1 + + %1%2Motion %3 + %1%2体感 %3 - - %1Button %2 - %1按钮 %2 + + + %1%2Button %3 + %1%2按键 %3 - - SDL Motion - SDL 体感 - - - - %1Click %2 - %1点击 %2 - - - + [unused] [未使用] @@ -5362,7 +5596,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro Controller @@ -5375,7 +5609,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons 双 Joycons 手柄 @@ -5388,7 +5622,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon 左 Joycon 手柄 @@ -5401,7 +5635,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon 右 Joycon 手柄 @@ -5429,7 +5663,7 @@ p, li { white-space: pre-wrap; } - + Handheld 掌机模式 @@ -5550,7 +5784,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller GameCube 控制器 @@ -5644,13 +5878,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK 确定 - + Cancel 取消 diff --git a/dist/languages/zh_TW.ts b/dist/languages/zh_TW.ts index f7ddf1843..bcb12064b 100644 --- a/dist/languages/zh_TW.ts +++ b/dist/languages/zh_TW.ts @@ -36,7 +36,7 @@ p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu是一個實驗性的開源Nintendo Switch模擬器,使用GPLv2.0+授權。</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">本軟體不得用於執行非法取得的遊戲。</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">此軟體不得用於執行非法取得的遊戲。</span></p></body></html> @@ -321,12 +321,14 @@ p, li { white-space: pre-wrap; } <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> - + +<div>此選項使用不精確的四捨五入,能提高 32 位元 ASIMD 浮點數函式的速度。</div> + Faster ASIMD instructions (32 bits only) - + 快速 ASIMD 指令(僅限 32 位元) @@ -347,17 +349,19 @@ p, li { white-space: pre-wrap; } <div>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.</div> - + + <div>此選項不執行每次模擬記憶體讀寫前的安全檢查以提高速度。停用此選項可能會允許遊戲讀寫模擬器記憶體。</div> + Disable address space checks - + 停用位址空間檢查 CPU settings are available only when game is not running. - 僅當遊戲未執行時才可修改 CPU 設定 + 僅在遊戲未執行時才能調整 CPU 設定 @@ -380,7 +384,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">僅供偵錯。</span><br/>如果您不確定這些選項的功能,請保持它們的啟用狀態。<br/>這些選項僅在啟用 CPU 偵錯模式時生效。</p></body></html> @@ -506,17 +510,21 @@ p, li { white-space: pre-wrap; } <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> - + + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> + Enable Host MMU Emulation - + Enable Host MMU Emulation CPU settings are available only when game is not running. - 僅當遊戲未執行時才可調整 CPU 設定 + 僅在遊戲未執行時才能調整 CPU 設定 @@ -549,7 +557,7 @@ p, li { white-space: pre-wrap; } Enable Extended Logging** - 啟用紀錄擴充** + 啟用延伸紀錄** @@ -569,7 +577,7 @@ p, li { white-space: pre-wrap; } When checked, the graphics API enters a slower debugging mode - 啟用時圖形 API 會進入較慢的偵錯模式 + 啟用時圖形 API 會進入較慢的偵錯模式。 @@ -579,17 +587,17 @@ p, li { white-space: pre-wrap; } When checked, it enables Nsight Aftermath crash dumps - + 啟用時 yuzu 將會儲存 Nsight Aftermath 格式的錯誤傾印檔案。 Enable Nsight Aftermath - + 啟用 Nsight Aftermath When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower - 啟用後將停用批次 Just In Time 編譯器,會使得效能降低。 + 啟用時將停用 Macro Just In Time 編譯器,會使得效能降低。 @@ -599,7 +607,7 @@ p, li { white-space: pre-wrap; } When checked, yuzu will log statistics about the compiled pipeline cache - + 啟用時 yuzu 將記錄有關編譯著色器快取的統計資訊。 @@ -609,12 +617,12 @@ p, li { white-space: pre-wrap; } When checked, it executes shaders without loop logic changes - + 啟用時 yuzu 在執行著色器時,不會修改循環結構的條件判斷。 Disable Loop safety checks - + 停用循環安全檢查 @@ -624,12 +632,12 @@ p, li { white-space: pre-wrap; } Enable FS Access Log - + 啟用檔案系統存取記錄 Enable Verbose Reporting Services** - + 啟用詳細報告服務 @@ -654,10 +662,15 @@ p, li { white-space: pre-wrap; } Enable Auto-Stub** - + 啟用自動偵錯** - + + Enable all Controller Types + 啟用所有控制器類型 + + + **This will be reset automatically when yuzu closes. **當 yuzu 關閉時會自動重設。 @@ -685,7 +698,7 @@ p, li { white-space: pre-wrap; } Form - + Form @@ -842,7 +855,7 @@ p, li { white-space: pre-wrap; } Patch Manager - 擴充功能管理 + 延伸模組管理 @@ -937,67 +950,78 @@ p, li { white-space: pre-wrap; } 一般 - + + + Use global framerate cap + 使用全域畫面速率限制 + + + + Set framerate cap: + 設定畫面速率限制: + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. + 需要使用 FPS 限制器的快速鍵才能切換執行速度。 + + + Framerate Cap 畫面速率限制 - - Requires the use of the FPS Limiter Toggle hotkey to take effect. - - - - + x x - + Limit Speed Percent 執行速度限制 - + % % - + Multicore CPU Emulation 多核心 CPU 模擬 - + Confirm exit while emulation is running 退出遊戲時需要確認 - + Prompt for user on game boot 啟動遊戲時提示選擇使用者 - + Pause emulation when in background 模擬器在背景執行時暫停 - + Hide mouse on inactivity 滑鼠閒置時自動隱藏 - + Reset All Settings 重設所有設定 - + yuzu yuzu - + This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed? 這將重設所有遊戲的額外設定,但不會刪除遊戲資料夾、使用者設定檔、輸入設定檔,是否繼續? @@ -1042,7 +1066,7 @@ p, li { white-space: pre-wrap; } Use disk pipeline cache - 使用硬碟流水線快取 + 使用硬碟管線快取 @@ -1115,18 +1139,113 @@ p, li { white-space: pre-wrap; } 延伸視窗 - - + + Resolution: + 解析度: + + + + 0.5X (360p/540p) [EXPERIMENTAL] + 0.5X (360p/540p) [實驗性] + + + + 0.75X (540p/810p) [EXPERIMENTAL] + 0.75X (540p/810p) [實驗性] + + + + 1X (720p/1080p) + 1X (720p/1080p) + + + + 2X (1440p/2160p) + 2X (1440p/2160p) + + + + 3X (2160p/3240p) + 3X (2160p/3240p) + + + + 4X (2880p/4320p) + 4X (2880p/4320p) + + + + 5X (3600p/5400p) + 5X (3600p/5400p) + + + + 6X (4320p/6480p) + 6X (4320p/6480p) + + + + Window Adapting Filter: + + + + + Nearest Neighbor + + + + + Bilinear + + + + + Bicubic + + + + + Gaussian + + + + + ScaleForce + 強制縮放 + + + + AMD FidelityFX™️ Super Resolution [Vulkan Only] + + + + + Anti-Aliasing Method: + 抗鋸齒方式: + + + + None + + + + + FXAA + FXAA + + + + Use global background color 使用全域背景顏色 - + Set background color: 設定背景顏色: - + Background Color: 背景顏色: @@ -1181,7 +1300,7 @@ p, li { white-space: pre-wrap; } Enables Fast GPU Time. This option will force most games to run at their highest native resolution. - + 啟用快速 GPU 時間。此選項將強制大多數遊戲以其最高解析度執行。 @@ -1195,28 +1314,33 @@ p, li { white-space: pre-wrap; } + Automatic + 自動 + + + Default 預設 - - - 2x (WILL BREAK THINGS) - - - 4x (WILL BREAK THINGS) - + 2x + 2x - 8x (WILL BREAK THINGS) - + 4x + 4x - 16x (WILL BREAK THINGS) - + 8x + 8x + + + + 16x + 16x @@ -1468,7 +1592,7 @@ p, li { white-space: pre-wrap; } L Body - 左側主體 + 左側搖桿 @@ -1492,7 +1616,7 @@ p, li { white-space: pre-wrap; } R Body - 右側主體 + 右側搖桿 @@ -1543,8 +1667,8 @@ p, li { white-space: pre-wrap; } - Other - 其他 + Emulated Devices + 模擬設備 @@ -1553,66 +1677,75 @@ p, li { white-space: pre-wrap; } - Emulate Analog with Keyboard Input - 使用鍵盤模擬搖桿 - - - - Enable mouse panning - 啟用滑鼠平移 - - - - Mouse sensitivity - 滑鼠靈敏度 - - - - % - % - - - - - Advanced - 進階 - - - - Touchscreen - 觸控螢幕 - - - Mouse 滑鼠 - - Motion / Touch - 體感/觸控 + + Touchscreen + 觸控螢幕 - - - Configure - 設定 + + Advanced + 進階 - + Debug Controller 控制器偵錯 - + + + Configure + 設定 + + + + Other + 其他 + + + + Emulate Analog with Keyboard Input + 使用鍵盤模擬搖桿 + + + Requires restarting yuzu 需要重新啟動 yuzu - + Enable XInput 8 player support (disables web applet) 啟用 XInput 8 輸入支援(停用 web applet) + + + Enable UDP controllers (not needed for motion) + + + + + Enable mouse panning + 啟用滑鼠平移 + + + + Mouse sensitivity + 滑鼠靈敏度 + + + + % + % + + + + Motion / Touch + 體感/觸控 + ConfigureInputPlayer @@ -1627,425 +1760,441 @@ p, li { white-space: pre-wrap; } 控制器連線 - - - - Pro Controller - Pro 手把 - - - - - Dual Joycons - 雙 Joycon 手把 - - - - - Left Joycon - 左 Joycon 手把 - - - - - Right Joycon - 右 Joycon 手把 - - - - - Handheld - 掌機模式 - - - + Input Device 輸入裝置: - - Any - 任意 - - - - Keyboard/Mouse - 鍵盤/滑鼠 - - - + Profile 設定檔 - + Save 儲存 - + New 新增 - + Delete 刪除 - - + + Left Stick 左搖桿 - - - - - - + + + + + + Up - - - - - - - + + + + + + + Left - - - - - - - + + + + + + + Right - - - - - - + + + + + + Down - - - - + + + + Pressed - 按下 + 按壓 - - - - + + + + Modifier 輕推 - - + + Range 靈敏度 - - + + % % - - + + Deadzone: 0% 無感帶:0% - - + + Modifier Range: 0% 輕推靈敏度:0% - + D-Pad 十字鍵 - - - + + + L L - - - + + + ZL ZL - - + + Minus - - + + Capture 截圖 - - - + + + Plus - - + + Home HOME - - - - + + + + R R - - - + + + ZR ZR - - + + SL SL - - + + SR SR - + Motion 1 體感 1 - + Motion 2 體感 2 - + Face Buttons 主要按鍵 - - + + X X - - + + Y Y - - + + A A - - + + B B - - + + Right Stick 右搖桿 - - - - + + + + Clear 清除 - - - - + + + + [not set] [未設定] - - + + Toggle button 切換按鍵 - - + + Invert button + 無效按鈕 + + + + + Invert axis + 方向反轉 + + + + Set threshold 設定閾值 - + Choose a value between 0% and 100% 選擇介於 0% 和 100% 之間的值 - + Map Analog Stick 搖桿映射 - + After pressing OK, first move your joystick horizontally, and then vertically. To invert the axes, first move your joystick vertically, and then horizontally. 按下確定後,先水平再上下移動您的搖桿。 要反轉方向,則先上下再水平移動您的搖桿。 - - Invert axis - 方向反轉 - - - - + + Deadzone: %1% 無感帶:%1% - - + + Modifier Range: %1% 輕推靈敏度:%1% - + + + Pro Controller + Pro 手把 + + + + Dual Joycons + 雙 Joycon 手把 + + + + Left Joycon + 左 Joycon 手把 + + + + Right Joycon + 右 Joycon 手把 + + + + Handheld + 掌機模式 + + + GameCube Controller GameCube 手把 - + + Poke Ball Plus + + + + + NES Controller + NES 控制器 + + + + SNES Controller + SNES 控制器 + + + + N64 Controller + + + + + Sega Genesis + + + + Start / Pause 開始 / 暫停 - + Z Z - + Control Stick 控制搖桿 - + C-Stick C 搖桿 - + Shake! 搖動! - + [waiting] [等待中] - + New Profile 新增設定檔 - + Enter a profile name: 輸入設定檔名稱: - - + + Create Input Profile 建立輸入設定檔 - + The given profile name is not valid! 輸入的設定檔名稱無效! - + Failed to create the input profile "%1" 建立輸入設定檔「%1」失敗 - + Delete Input Profile 刪除輸入設定檔 - + Failed to delete the input profile "%1" 刪除輸入設定檔「%1」失敗 - + Load Input Profile 載入輸入設定檔 - + Failed to load the input profile "%1" 載入輸入設定檔「%1」失敗 - + Save Input Profile 儲存輸入設定檔 - + Failed to save the input profile "%1" 儲存輸入設定檔「%1」失敗 @@ -2071,85 +2220,75 @@ To invert the axes, first move your joystick vertically, and then horizontally.< ConfigureMotionTouch - + Configure Motion / Touch 體感/觸控設定 - - Mouse Motion - 滑鼠體感 - - - - Sensitivity: - 靈敏度: - - - + Touch 觸控 - + UDP Calibration: UDP 校正: - + (100, 50) - (1800, 850) (100, 50) - (1800, 850) - - - + + + Configure 設定 - - Use button mapping: - 使用按鍵映射: + + Touch from button profile: + 觸控螢幕配置: - + CemuhookUDP Config CemuhookUDP 設定 - + You may use any Cemuhook compatible UDP input source to provide motion and touch input. 您可使用與 Cemuhook 相容的 UDP 輸入裝置以使用體感和觸控功能。 - + Server: 伺服器: - + Port: 連線埠: - + Learn More 了解更多 - - + + Test 測試 - + Add Server 新增伺服器 - + Remove Server 移除伺服器 @@ -2159,151 +2298,87 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> - + %1:%2 %1:%2 - - - - - - + + + + + + yuzu yuzu - + Port number has invalid characters 連線埠中包含無效字元 - + Port has to be in range 0 and 65353 連線埠必須為 0 到 65353 之間 - + IP address is not valid 無效的 IP 位址 - + This UDP server already exists 此 UDP 伺服器已存在 - + Unable to add more than 8 servers 最多只能新增 8 個伺服器 - + Testing 測試中 - + Configuring 設定中 - + Test Successful 測試成功 - + Successfully received data from the server. 已成功從伺服器取得資料 - + Test Failed 測試失敗 - + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. 無法從伺服器取得有效的資料。<br>請檢查伺服器是否正確設定以及位址和連接埠是否正確。 - + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. UDP 測試或觸控校正進行中。<br>請耐心等候。 - - ConfigureMouseAdvanced - - - Configure Mouse - 滑鼠設定 - - - - Mouse Buttons - 滑鼠按鍵 - - - - Forward: - 下一頁: - - - - Back: - 上一頁: - - - - Left: - 左鍵: - - - - Middle: - 中鍵: - - - - Right: - 右鍵: - - - - - Clear - 清除 - - - - Defaults - 預設 - - - - [not set] - [未設定] - - - - Restore Default - 還原預設值 - - - - [press key] - [按下按鍵] - - ConfigureNetwork Form - + Form @@ -2318,7 +2393,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Network Interface - 網路介面 + 網路卡 @@ -2376,7 +2451,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Add-Ons - 擴充功能 + 延伸模組 @@ -2401,7 +2476,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Adv. Graphics - + 進階圖形 @@ -2429,12 +2504,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Add-Ons - 擴充功能 + 延伸模組 Patch Name - 擴充功能名稱 + 延伸模組名稱 @@ -2472,7 +2547,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Set Image - 設定圖片 + 選擇圖片 @@ -2492,7 +2567,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Profile management is available only when game is not running. - 僅當遊戲未執行時才可修改使用者設定檔 + 僅在遊戲未執行時才能修改使用者設定檔 @@ -2585,12 +2660,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Error resizing user image - + 調整使用者圖片大小時發生錯誤 Unable to resize image - + 無法調整圖片大小 @@ -3014,7 +3089,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Sound output mode - 聲音輸出模式 + 聲道 @@ -3029,7 +3104,7 @@ To invert the axes, first move your joystick vertically, and then horizontally.< System settings are available only when game is not running. - 僅當遊戲未執行時才可調整系統設定 + 僅在遊戲未執行時才能修改使用者設定檔 @@ -3057,17 +3132,17 @@ To invert the axes, first move your joystick vertically, and then horizontally.< <html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html> - + <html><head/><body><p>通過讀取與 TAS-nx 腳本具有相同格式的腳本來讀取控制器的輸入。<br/>有關詳細資訊,請參閱 yuzu 官方網站的<a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">說明網頁</span></a>。</p></body></html> To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys). - + 要確認是哪些快速鍵控制播放/錄製,請參閱快速鍵設定。(設定 > 一般 > 快速鍵) WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method. - + 警告:這是實驗性功能。<br/>由於不完善的同步方式,可能無法完整的重現。 @@ -3077,35 +3152,30 @@ To invert the axes, first move your joystick vertically, and then horizontally.< Enable TAS features - + 啟用 TAS 功能 - Automatic controller profile swapping - - - - Loop script - + 循環腳本 - + Pause execution during loads - + 載入畫面時暫停執行 - + Script Directory - + 腳本資料夾 - + Path 路徑 - + ... ... @@ -3115,12 +3185,12 @@ To invert the axes, first move your joystick vertically, and then horizontally.< TAS Configuration - + TAS 設定 - + Select TAS Load Directory... - + 選擇 TAS 載入資料夾... @@ -3180,37 +3250,37 @@ Drag points to change position, or double-click table cells to edit values.Y - + New Profile 新增設定檔 - + Enter the name for the new profile. 輸入新設定檔的名稱 - + Delete Profile 刪除設定檔 - + Delete profile %1? 是否刪除設定檔 %1? - + Rename Profile 重新命名設定檔 - + New name: 新名稱: - + [press key] [按下按鍵] @@ -3225,7 +3295,7 @@ Drag points to change position, or double-click table cells to edit values. Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing. - 警告:本頁設定會影響 yuzu 模擬觸控螢幕的內部運作。修改設定可能會導致非預期結果,例如觸控螢幕完全或部分失效。若您不知道自己在做甚麼,請不要使用此頁面。 + 警告:此處設定會影響 yuzu 模擬觸控螢幕的內部運作。修改設定可能會導致非預期結果,例如觸控螢幕完全或部分失效。請在充分了解的情況下修改此處設定。 @@ -3358,7 +3428,7 @@ Drag points to change position, or double-click table cells to edit values. Show Add-Ons Column - 顯示擴充功能欄位 + 顯示延伸模組欄位 @@ -3537,7 +3607,7 @@ Drag points to change position, or double-click table cells to edit values. What is my token? - 我的 Token 是什麼? + Token 說明 @@ -3630,12 +3700,12 @@ Drag points to change position, or double-click table cells to edit values. ControllerDialog - + Controller P1 Controller P1 - + &Controller P1 &Controller P1 @@ -3643,90 +3713,95 @@ Drag points to change position, or double-click table cells to edit values. GMainWindow - + <a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us? 我們<a href='https://yuzu-emu.org/help/feature/telemetry/'>蒐集匿名的資料</a>以幫助改善 yuzu。<br/><br/>您願意和我們分享您的使用資料嗎? - + Telemetry 遙測 - + Loading Web Applet... 載入 Web Applet... - - + + Disable Web Applet 停用 Web Applet - + Disabling the web applet will cause it to not be shown again for the rest of the emulated session. This can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? 停用 web applet 會導致不再顯示於模擬視窗。可能導致非預期後果,且只能用於《超級瑪利歐 3D 收藏輯》。您確定要停用 web applet? - + The amount of shaders currently being built 目前正在建構的著色器數量 - + + The current selected resolution scaling multiplier. + 目前選擇的解析度縮放比例。 + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 目前的模擬速度。高於或低於 100% 表示比實際 Switch 執行速度更快或更慢。 - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 遊戲即時 FPS。會因遊戲和場景的不同而改變。 - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 在不考慮幀數限制和垂直同步的情況下模擬一個 Switch 畫格的實際時間,若要全速模擬,此數值不得超過 16.67 毫秒。 - + Invalid config detected 偵測到無效設定 - + Handheld controller can't be used on docked mode. Pro controller will be selected. 掌機手把無法在主機模式中使用。將會選擇 Pro 手把。 - + DOCK TV 模式 - + VULKAN VULKAN - + OPENGL OPENGL - + &Clear Recent Files 清除最近的檔案(&C) - - TAS Recording - + + &Continue + 繼續(&C) - - Overwrite file of player 1? - + + &Pause + &暫停 @@ -3777,659 +3852,726 @@ Drag points to change position, or double-click table cells to edit values.發生未知錯誤,請檢視紀錄了解細節。 - + (64-bit) - + (64-bit) - + (32-bit) - + (32-bit) - + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - - Start - 開始 - - - + Save Data 儲存資料 - + Mod Data 模組資料 - + Error Opening %1 Folder 開啟資料夾 %1 時發生錯誤 - - + + Folder does not exist! 資料夾不存在 - + Error Opening Transferable Shader Cache 開啟通用著色器快取位置時發生錯誤 - + Failed to create the shader cache directory for this title. - + 無法新增此遊戲的著色器快取資料夾。 - + Contents 內容 - + Update 遊戲更新 - + DLC DLC - + Remove Entry 移除項目 - + Remove Installed Game %1? 移除已安裝的遊戲「%1」? - - - - - - + + + + + + Successfully Removed 移除成功 - + Successfully removed the installed base game. 成功移除已安裝的遊戲。 - - - + + + Error Removing %1 移除 %1 失敗 - + The base game is not installed in the NAND and cannot be removed. 此遊戲並非安裝在內部儲存空間,因此無法移除。 - + Successfully removed the installed update. 成功移除已安裝的遊戲更新。 - + There is no update installed for this title. 此遊戲沒有已安裝的更新。 - + There are no DLC installed for this title. 此遊戲沒有已安裝的 DLC。 - + Successfully removed %1 installed DLC. 成功移除遊戲 %1 已安裝的 DLC。 - + Delete OpenGL Transferable Shader Cache? - + 刪除 OpenGL 模式的著色器快取? - + Delete Vulkan Transferable Shader Cache? - + 刪除 Vulkan 模式的著色器快取? - + Delete All Transferable Shader Caches? - + 刪除所有的著色器快取? - + Remove Custom Game Configuration? 移除額外遊戲設定? - + Remove File 刪除檔案 - - + + Error Removing Transferable Shader Cache 刪除通用著色器快取時發生錯誤 - - + + A shader cache for this title does not exist. 此遊戲沒有著色器快取 - + Successfully removed the transferable shader cache. 成功刪除著色器快取。 - + Failed to remove the transferable shader cache. 刪除通用著色器快取失敗。 - - + + Error Removing Transferable Shader Caches - + 刪除通用著色器快取時發生錯誤 - + Successfully removed the transferable shader caches. - + 成功刪除通用著色器快取。 - + Failed to remove the transferable shader cache directory. - + 無法刪除著色器快取資料夾。 - - + + Error Removing Custom Configuration 移除額外遊戲設定時發生錯誤 - + A custom configuration for this title does not exist. 此遊戲沒有額外設定。 - + Successfully removed the custom game configuration. 成功移除額外遊戲設定。 - + Failed to remove the custom game configuration. 移除額外遊戲設定失敗。 - - + + RomFS Extraction Failed! RomFS 抽取失敗! - + There was an error copying the RomFS files or the user cancelled the operation. 複製 RomFS 檔案時發生錯誤或使用者取消動作。 - + Full 全部 - + Skeleton 部分 - + Select RomFS Dump Mode 選擇RomFS傾印模式 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. 請選擇如何傾印 RomFS。<br>「全部」會複製所有檔案到新資料夾中,而<br>「部分」只會建立資料夾結構。 - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + %1 沒有足夠的空間用於抽取 RomFS。請確保有足夠的空間或於模擬 > 設定 >系統 >檔案系統 > 傾印根目錄中選擇其他資料夾。 - + Extracting RomFS... 抽取 RomFS 中... - - + + Cancel 取消 - + RomFS Extraction Succeeded! RomFS 抽取完成! - + The operation completed successfully. 動作已成功完成 - + Error Opening %1 開啟 %1 時發生錯誤 - + Select Directory 選擇資料夾 - + Properties 屬性 - + The game properties could not be loaded. 無法載入遊戲屬性 - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch 執行檔 (%1);;所有檔案 (*.*) - + Load File 開啟檔案 - + Open Extracted ROM Directory 開啟已抽取的 ROM 資料夾 - + Invalid Directory Selected 選擇的資料夾無效 - + The directory you have selected does not contain a 'main' file. 選擇的資料夾未包含「main」檔案。 - + Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) 可安装的 Switch 檔案 (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX 卡帶映像 (*.xci) - + Install Files 安裝檔案 - + %n file(s) remaining 剩餘 %n 個檔案 - + Installing file "%1"... 正在安裝檔案「%1」... - - + + Install Results 安裝結果 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. 為了避免潛在的衝突,不建議將遊戲本體安裝至內部儲存空間。 此功能僅用於安裝遊戲更新和 DLC。 - + %n file(s) were newly installed 最近安裝了 %n 個檔案 - + %n file(s) were overwritten %n 個檔案被取代 - + %n file(s) failed to install %n 個檔案安裝失敗 - + System Application 系統應用程式 - + System Archive 系統檔案 - + System Application Update 系統應用程式更新 - + Firmware Package (Type A) 韌體包(A型) - + Firmware Package (Type B) 韌體包(B型) - + Game 遊戲 - + Game Update 遊戲更新 - + Game DLC 遊戲 DLC - + Delta Title Delta Title - + Select NCA Install Type... 選擇 NCA 安裝類型... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) 請選擇此 NCA 的安裝類型: (在多數情況下,選擇預設的「遊戲」即可。) - + Failed to Install 安裝失敗 - + The title type you selected for the NCA is invalid. 選擇的 NCA 安裝類型無效。 - + File not found 找不到檔案 - + File "%1" not found 找不到「%1」檔案 - - - &Continue - 繼續(&C) - - - + OK 確定 - + Missing yuzu Account 未設定 yuzu 帳號 - + In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web. 為了上傳相容性測試結果,您必須登入 yuzu 帳號。<br><br/>欲登入 yuzu 帳號請至模擬 &gt; 設定 &gt; 網路。 - + Error opening URL 開啟 URL 時發生錯誤 - + Unable to open the URL "%1". 無法開啟 URL:「%1」。 - + + TAS Recording + TAS 錄製 + + + + Overwrite file of player 1? + 覆寫玩家 1 的檔案? + + + Amiibo File (%1);; All Files (*.*) Amiibo 檔案 (%1);; 所有檔案 (*.*) - + Load Amiibo - 載入 Amiibo + 開啟 Amiibo - + Error opening Amiibo data file 開啟 Amiibo 檔案時發生錯誤 - + Unable to open Amiibo file "%1" for reading. 無法開啟 Amiibo 檔案 %1。 - + Error reading Amiibo data file 讀取 Amiibo 檔案時發生錯誤 - + Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes. 無法讀取完整的 Amiibo 資料。應讀取 %1 位元組,但實際僅讀取到 %2 位元組。 - + Error loading Amiibo data 載入 Amiibo 資料時發生錯誤 - + Unable to load Amiibo data. 無法載入 Amiibo 資料。 - + Capture Screenshot 截圖 - + PNG Image (*.png) PNG 圖片 (*.png) - + TAS state: Running %1/%2 - + TAS 狀態:正在執行 %1/%2 - + TAS state: Recording %1 - + TAS 狀態:正在錄製 %1 - + TAS state: Idle %1/%2 - + TAS 狀態:閒置 %1/%2 - + TAS State: Invalid + TAS 狀態:無效 + + + + &Stop Running + &停止執行 + + + + &Start + 開始(&S) + + + + Stop R&ecording + 停止錄製 + + + + R&ecord - + Building: %n shader(s) - + 正在編譯 %n 個著色器檔案 - + + Scale: %1x + %1 is the resolution scaling factor + 縮放比例:%1x + + + Speed: %1% / %2% 速度:%1% / %2% - + Speed: %1% 速度:%1% - + Game: %1 FPS (Unlocked) - + 遊戲: %1 FPS(未限制) - + Game: %1 FPS 遊戲:%1 FPS - + Frame: %1 ms 畫格延遲:%1 ms - + GPU NORMAL - + GPU 一般效能 - + GPU HIGH - + GPU 高效能 - + GPU EXTREME - + GPU 最高效能 - + GPU ERROR + GPU 錯誤 + + + + NEAREST - + + + BILINEAR + + + + + BICUBIC + + + + + GAUSSIAN + + + + + SCALEFORCE + + + + + FSR + + + + + + NO AA + 抗鋸齒關 + + + + FXAA + FXAA + + + The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. 此遊戲需要從您的 Switch 傾印額外檔案。<br/><br/>有關傾印這些檔案的更多資訊,請參閱以下 wiki 網頁:Dumping System Archives and the Shared Fonts from a Switch Console<a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>。<br/><br/>您要停止並回到遊戲清單嗎?繼續模擬可能會導致當機、存檔損毀或其他錯誤。 - + yuzu was unable to locate a Switch system archive. %1 Yuzu 找不到 Switch 系統檔案 %1 - + yuzu was unable to locate a Switch system archive: %1. %2 Yuzu 找不到 Switch 系統檔案:%1。%2 - + System Archive Not Found 找不到系統檔案 - + System Archive Missing 系統檔案遺失 - + yuzu was unable to locate the Switch shared fonts. %1 Yuzu 找不到 Switch 共享字型 %1 - + Shared Fonts Not Found 找不到共享字型 - + Shared Font Missing 遺失共享字型 - + Fatal Error 嚴重錯誤 - + yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. yuzu 發生嚴重錯誤,請檢視紀錄以了解細節。更多資訊請參閱網頁:<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>。<br/><br/>您要停止模擬並回到遊戲清單嗎?繼續模擬可能會導致當機、存檔損毀或其他錯誤。 - + Fatal Error encountered 發生嚴重錯誤 - + Confirm Key Rederivation 確認重新產生金鑰 - + You are about to force rederive all of your keys. If you do not know what this means or what you are doing, this is a potentially destructive action. @@ -4445,37 +4587,37 @@ This will delete your autogenerated key files and re-run the key derivation modu 這將刪除您自動產生的金鑰檔案並重新執行產生金鑰模組。 - + Missing fuses 遺失項目 - + - Missing BOOT0 - 遺失 BOOT0 - + - Missing BCPKG2-1-Normal-Main - 遺失 BCPKG2-1-Normal-Main - + - Missing PRODINFO - 遺失 PRODINFO - + Derivation Components Missing 遺失產生元件 - - Components are missing that may hinder key derivation from completing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys and games.<br><br><small>(%1)</small> - 缺少元件可能會影響遊戲的正常運作。<br>請檢視 <a href='https://yuzu-emu.org/help/quickstart/'>yuzu 快速指引</a>以取得您的金鑰和遊戲。<br><br><small>(%1)</small> + + Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small> + 缺少加密金鑰。 <br>請按照<a href='https://yuzu-emu.org/help/quickstart/'>《Yuzu快速入門指南》來取得所有金鑰、韌體、遊戲<br><br><small>(%1)。 - + Deriving keys... This may take up to a minute depending on your system's performance. @@ -4484,39 +4626,39 @@ on your system's performance. 您的系統效能。 - + Deriving Keys 產生金鑰 - + Select RomFS Dump Target 選擇 RomFS 傾印目標 - + Please select which RomFS you would like to dump. 請選擇希望傾印的 RomFS。 - + Are you sure you want to close yuzu? 您確定要關閉 yuzu 嗎? - - - + + + yuzu yuzu - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. 您確定要停止模擬嗎?未儲存的進度將會遺失。 - + The currently running application has requested yuzu to not exit. Would you like to bypass this and exit anyway? @@ -4528,38 +4670,38 @@ Would you like to bypass this and exit anyway? GRenderWindow - + OpenGL not available! 無法使用 OpenGL 模式! - + yuzu has not been compiled with OpenGL support. yuzu 未以支援 OpenGL 的方式編譯。 - - + + Error while initializing OpenGL! 初始化 OpenGL 時發生錯誤! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 您的 GPU 可能不支援 OpenGL,或是未安裝最新的圖形驅動程式 - + Error while initializing OpenGL 4.6! 初始化 OpenGL 4.6 時發生錯誤! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支援 OpenGL 4.6,或是未安裝最新的圖形驅動程式<br><br>GL 渲染器:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 您的 GPU 可能不支援某些必需的 OpenGL 功能。請確保您已安裝最新的圖形驅動程式。<br><br>GL 渲染器:<br>%1<br><br>不支援的功能:<br>%2 @@ -4579,7 +4721,7 @@ Would you like to bypass this and exit anyway? Add-ons - 擴充功能 + 延伸模組 @@ -4619,7 +4761,7 @@ Would you like to bypass this and exit anyway? Open Transferable Pipeline Cache - + 開啟通用著色器管線快取位置 @@ -4644,17 +4786,17 @@ Would you like to bypass this and exit anyway? Remove OpenGL Pipeline Cache - + 刪除 OpenGL 著色器管線快取 Remove Vulkan Pipeline Cache - + 刪除 Vulkan 著色器管線快取 Remove All Pipeline Caches - + 刪除所有著色器管線快取 @@ -4670,7 +4812,7 @@ Would you like to bypass this and exit anyway? Dump RomFS to SDMC - + 傾印 RomFS 到 SDMC @@ -4690,7 +4832,7 @@ Would you like to bypass this and exit anyway? Scan Subfolders - 掃描子資料夾 + 包含子資料夾 @@ -4710,7 +4852,7 @@ Would you like to bypass this and exit anyway? Open Directory Location - 開啟目錄資料夾 + 開啟資料夾位置 @@ -4851,7 +4993,7 @@ Screen. The text can't contain any of the following characters: %1 - + 文字中不能包含以下字元:%1 @@ -4915,189 +5057,204 @@ Screen. 模擬 (&E) - + &View 檢視 (&V) - + &Reset Window Size 重設視窗大小(&R) - - Reset Window Size to &720p - 重設視窗大小為 &720p - - - - Reset Window Size to 720p - 重設視窗大小為 720p - - - - Reset Window Size to &900p - 重設視窗大小為 &900p - - - - Reset Window Size to 900p - 重設視窗大小為 900p - - - - Reset Window Size to &1080p - 重設視窗大小為 &1080p - - - - Reset Window Size to 1080p - 重設視窗大小為 1080p - - - + &Debugging 偵錯 (&D) - + + Reset Window Size to &720p + 重設視窗大小為 &720p + + + + Reset Window Size to 720p + 重設視窗大小為 720p + + + + Reset Window Size to &900p + 重設視窗大小為 &900p + + + + Reset Window Size to 900p + 重設視窗大小為 900p + + + + Reset Window Size to &1080p + 重設視窗大小為 &1080p + + + + Reset Window Size to 1080p + 重設視窗大小為 1080p + + + &Tools 工具 (&T) - + + &TAS + TAS (&T) + + + &Help 說明 (&H) - + &Install Files to NAND... &安裝檔案至內部儲存空間 - + L&oad File... - 載入檔案(&O)... + 開啟檔案(&O)... - + Load &Folder... 開啟資料夾(&F)... - + E&xit 結束(&X) - - &Start - 開始(&S) - - - + &Pause 暫停(&P) - + &Stop 停止(&S) - + &Reinitialize keys... 重新初始化金鑰(&R)... - + &About yuzu 關於 yuzu(&A) - + Single &Window Mode - 單視窗模式(&W) + 單一視窗模式(&W) - + Con&figure... 設定 (&F) - + Display D&ock Widget Headers - 顯示停駐小工具的標題 (&O) + 顯示 Dock 小工具標題 (&O) - + Show &Filter Bar 顯示搜尋列(&F) - + Show &Status Bar 顯示狀態列(&S) - + Show Status Bar 顯示狀態列 - + F&ullscreen 全螢幕(&U) - + &Restart 重新啟動(&R) - + Load &Amiibo... - 載入 &Amiibo... + 開啟 &Amiibo... - + &Report Compatibility 回報相容性(&R) - + Open &Mods Page - 模組網頁 (&M) + 模組資訊 (&M) - + Open &Quickstart Guide 快速入門 (&Q) - + &FAQ 常見問題 (&F) - + Open &yuzu Folder 開啟 yuzu 資料夾(&Y) - + &Capture Screenshot 截圖 (&C) - - Configure &TAS... + + &Configure TAS... 設定 &TAS… - + Configure C&urrent Game... - 設定目前遊戲...(&U) + 目前遊戲設定...(&U) + + + + &Start + 開始(&S) + + + + &Reset + 重設 (&R) + + + + R&ecord + @@ -5144,10 +5301,15 @@ p, li { white-space: pre-wrap; } PlayerControlPreview - + START/PAUSE 開始 / 暫停 + + + Charging + + QObject @@ -5169,7 +5331,7 @@ p, li { white-space: pre-wrap; } Add New Game Directory - 新增遊戲資料夾 + 加入遊戲資料夾 @@ -5178,142 +5340,222 @@ p, li { white-space: pre-wrap; } - - + Shift Shift - - + Ctrl Ctrl - - + Alt Alt - - - + + [not set] [未設定] - - Hat %1 %2 方向鍵 %1 %2 - - - - - - + + + + Axis %1%2 Axis %1%2 - Button %1 按鍵 %1 - - - + + + [unknown] [未知] - + + Left + + + + + Right + + + - Click 0 - 點擊 0 + Down + - - Click 1 - 點擊 1 + Up + - - Click 2 - 點擊 2 + Z + - - Click 3 - 點擊 3 + R + - - Click 4 - 點擊 4 + L + - + + A + + + + + B + + + + + X + + + + + Y + + + + + Start + + + + + L1 + + + + + L2 + + + + + L3 + + + + + R1 + + + + + R2 + + + + + R3 + + + + + Circle + + + + + Cross + + + + + Square + + + + + Triangle + + + + + Share + + + + + Options + 選項 + + + + [undefined] + + + + %1%2 %1%2 - - GC Axis %1%2 - GC Axis %1%2 - - - - GC Button %1 - GC 按鍵 %1 - - - - TAS Axis %1 + + [invalid] - - TAS Btn %1 + + + %1%2Hat %3 - - Motion %1 - 體感 %1 + + + + %1%2Axis %3 + - - %1Button %2 - %1按鍵 %2 + + %1%2Axis %3,%4,%5 + - - SDL Motion - SDL 體感 + + %1%2Motion %3 + - - %1Click %2 - %1點擊 %2 + + + %1%2Button %3 + %1%2按鈕 %3 - + [unused] [未使用] @@ -5354,7 +5596,7 @@ p, li { white-space: pre-wrap; } - + Pro Controller Pro 手把 @@ -5367,7 +5609,7 @@ p, li { white-space: pre-wrap; } - + Dual Joycons 雙 Joycon 手把 @@ -5380,7 +5622,7 @@ p, li { white-space: pre-wrap; } - + Left Joycon 左 Joycon 手把 @@ -5393,7 +5635,7 @@ p, li { white-space: pre-wrap; } - + Right Joycon 右 Joycon 手把 @@ -5421,7 +5663,7 @@ p, li { white-space: pre-wrap; } - + Handheld 掌機模式 @@ -5542,7 +5784,7 @@ p, li { white-space: pre-wrap; } 8 - + GameCube Controller GameCube 手把 @@ -5636,13 +5878,13 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - + + OK 確定 - + Cancel 取消 From 2c47f8aa1886522898b5b3a73185b5662be3e9f3 Mon Sep 17 00:00:00 2001 From: Feng Chen Date: Thu, 2 Dec 2021 12:19:43 +0800 Subject: [PATCH 157/291] Support multiple videos playing --- .../service/nvdrv/devices/nvhost_nvdec.cpp | 11 +++-- .../nvdrv/devices/nvhost_nvdec_common.cpp | 5 ++- .../nvdrv/devices/nvhost_nvdec_common.h | 3 +- .../hle/service/nvdrv/devices/nvhost_vic.cpp | 11 +++-- src/video_core/gpu.cpp | 43 ++++++------------- src/video_core/gpu.h | 4 +- 6 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 0d7d4ad03..8e2a16d86 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -21,7 +21,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& case 0x0: switch (command.cmd) { case 0x1: - return Submit(input, output); + return Submit(fd, input, output); case 0x2: return GetSyncpoint(input, output); case 0x3: @@ -62,11 +62,16 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(DeviceFD fd) {} +void nvhost_nvdec::OnOpen(DeviceFD fd) { + static u32 next_id{}; + fd_to_id[fd] = next_id++; +} void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); - system.GPU().ClearCdmaInstance(); + if (fd_to_id.find(fd) != fd_to_id.end()) { + system.GPU().ClearCdmaInstance(fd_to_id[fd]); + } } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index e61261f98..8a05f0668 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -59,7 +59,8 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { return NvResult::Success; } -NvResult nvhost_nvdec_common::Submit(const std::vector& input, std::vector& output) { +NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector& input, + std::vector& output) { IoctlSubmit params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); @@ -93,7 +94,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector& input, std::vectoraddr + cmd_buffer.offset, cmdlist.data(), cmdlist.size() * sizeof(u32)); - gpu.PushCommandBuffer(cmdlist); + gpu.PushCommandBuffer(fd_to_id[fd], cmdlist); } std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); // Some games expect command_buffers to be written back diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 351625c17..e28c54df6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -104,13 +104,14 @@ protected: /// Ioctl command implementations NvResult SetNVMAPfd(const std::vector& input); - NvResult Submit(const std::vector& input, std::vector& output); + NvResult Submit(DeviceFD fd, const std::vector& input, std::vector& output); NvResult GetSyncpoint(const std::vector& input, std::vector& output); NvResult GetWaitbase(const std::vector& input, std::vector& output); NvResult MapBuffer(const std::vector& input, std::vector& output); NvResult UnmapBuffer(const std::vector& input, std::vector& output); NvResult SetSubmitTimeout(const std::vector& input, std::vector& output); + std::unordered_map fd_to_id{}; s32_le nvmap_fd{}; u32_le submit_timeout{}; std::shared_ptr nvmap_dev; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index eac4dd530..420fe21c8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -21,7 +21,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& i case 0x0: switch (command.cmd) { case 0x1: - return Submit(input, output); + return Submit(fd, input, output); case 0x2: return GetSyncpoint(input, output); case 0x3: @@ -62,10 +62,15 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& i return NvResult::NotImplemented; } -void nvhost_vic::OnOpen(DeviceFD fd) {} +void nvhost_vic::OnOpen(DeviceFD fd) { + static u32 next_id{}; + fd_to_id[fd] = next_id++; +} void nvhost_vic::OnClose(DeviceFD fd) { - system.GPU().ClearCdmaInstance(); + if (fd_to_id.find(fd) != fd_to_id.end()) { + system.GPU().ClearCdmaInstance(fd_to_id[fd]); + } } } // namespace Service::Nvidia::Devices diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index ab7c21a49..27a47954d 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -185,16 +185,6 @@ struct GPU::Impl { return *dma_pusher; } - /// Returns a reference to the GPU CDMA pusher. - [[nodiscard]] Tegra::CDmaPusher& CDmaPusher() { - return *cdma_pusher; - } - - /// Returns a const reference to the GPU CDMA pusher. - [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const { - return *cdma_pusher; - } - /// Returns a reference to the underlying renderer. [[nodiscard]] VideoCore::RendererBase& Renderer() { return *renderer; @@ -338,25 +328,26 @@ struct GPU::Impl { } /// Push GPU command buffer entries to be processed - void PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { + void PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries) { if (!use_nvdec) { return; } - if (!cdma_pusher) { - cdma_pusher = std::make_unique(gpu); + if (cdma_pushers.find(id) == cdma_pushers.end()) { + cdma_pushers[id] = std::make_unique(gpu); } // SubmitCommandBuffer would make the nvdec operations async, this is not currently working // TODO(ameerj): RE proper async nvdec operation // gpu_thread.SubmitCommandBuffer(std::move(entries)); - - cdma_pusher->ProcessEntries(std::move(entries)); + cdma_pushers[id]->ProcessEntries(std::move(entries)); } /// Frees the CDMAPusher instance to free up resources - void ClearCdmaInstance() { - cdma_pusher.reset(); + void ClearCdmaInstance(u32 id) { + if (cdma_pushers.find(id) != cdma_pushers.end()) { + cdma_pushers.erase(id); + } } /// Swap buffers (render frame) @@ -659,7 +650,7 @@ struct GPU::Impl { Core::System& system; std::unique_ptr memory_manager; std::unique_ptr dma_pusher; - std::unique_ptr cdma_pusher; + std::map> cdma_pushers; std::unique_ptr renderer; VideoCore::RasterizerInterface* rasterizer = nullptr; const bool use_nvdec; @@ -811,14 +802,6 @@ const Tegra::DmaPusher& GPU::DmaPusher() const { return impl->DmaPusher(); } -Tegra::CDmaPusher& GPU::CDmaPusher() { - return impl->CDmaPusher(); -} - -const Tegra::CDmaPusher& GPU::CDmaPusher() const { - return impl->CDmaPusher(); -} - VideoCore::RendererBase& GPU::Renderer() { return impl->Renderer(); } @@ -887,12 +870,12 @@ void GPU::PushGPUEntries(Tegra::CommandList&& entries) { impl->PushGPUEntries(std::move(entries)); } -void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { - impl->PushCommandBuffer(entries); +void GPU::PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries) { + impl->PushCommandBuffer(id, entries); } -void GPU::ClearCdmaInstance() { - impl->ClearCdmaInstance(); +void GPU::ClearCdmaInstance(u32 id) { + impl->ClearCdmaInstance(id); } void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index c89a5d693..500411176 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -242,10 +242,10 @@ public: void PushGPUEntries(Tegra::CommandList&& entries); /// Push GPU command buffer entries to be processed - void PushCommandBuffer(Tegra::ChCommandHeaderList& entries); + void PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries); /// Frees the CDMAPusher instance to free up resources - void ClearCdmaInstance(); + void ClearCdmaInstance(u32 id); /// Swap buffers (render frame) void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); From 762b8ad448369cc770beae4d8368a6258b13709e Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 2 Dec 2021 14:20:43 -0500 Subject: [PATCH 158/291] general: Replace high_resolution_clock with steady_clock On some OSes, high_resolution_clock is an alias to system_clock and is not monotonic in nature. Replace this with steady_clock. --- src/common/x64/native_clock.cpp | 6 +++--- src/core/hle/service/audio/hwopus.cpp | 4 ++-- src/core/perf_stats.h | 4 ++-- src/video_core/shader_notify.cpp | 2 +- src/video_core/shader_notify.h | 2 +- src/yuzu/loading_screen.cpp | 4 ++-- src/yuzu/loading_screen.h | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 87de40624..28f834443 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -19,16 +19,16 @@ u64 EstimateRDTSCFrequency() { // get current time _mm_mfence(); const u64 tscStart = __rdtsc(); - const auto startTime = std::chrono::high_resolution_clock::now(); + const auto startTime = std::chrono::steady_clock::now(); // wait roughly 3 seconds while (true) { auto milli = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - startTime); + std::chrono::steady_clock::now() - startTime); if (milli.count() >= 3000) break; std::this_thread::sleep_for(milli_10); } - const auto endTime = std::chrono::high_resolution_clock::now(); + const auto endTime = std::chrono::steady_clock::now(); _mm_mfence(); const u64 tscEnd = __rdtsc(); // calculate difference diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 7da1f2969..981b6c996 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -96,7 +96,7 @@ private: bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector& input, std::vector& output, u64* out_performance_time) const { - const auto start_time = std::chrono::high_resolution_clock::now(); + const auto start_time = std::chrono::steady_clock::now(); const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); if (sizeof(OpusPacketHeader) > input.size()) { LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", @@ -135,7 +135,7 @@ private: return false; } - const auto end_time = std::chrono::high_resolution_clock::now() - start_time; + const auto end_time = std::chrono::steady_clock::now() - start_time; sample_count = out_sample_count; consumed = static_cast(sizeof(OpusPacketHeader) + hdr.size); if (out_performance_time != nullptr) { diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h index a2541906f..816202588 100644 --- a/src/core/perf_stats.h +++ b/src/core/perf_stats.h @@ -33,7 +33,7 @@ public: explicit PerfStats(u64 title_id_); ~PerfStats(); - using Clock = std::chrono::high_resolution_clock; + using Clock = std::chrono::steady_clock; void BeginSystemFrame(); void EndSystemFrame(); @@ -87,7 +87,7 @@ private: class SpeedLimiter { public: - using Clock = std::chrono::high_resolution_clock; + using Clock = std::chrono::steady_clock; void DoSpeedLimiting(std::chrono::microseconds current_system_time_us); diff --git a/src/video_core/shader_notify.cpp b/src/video_core/shader_notify.cpp index dc6995b46..bcaf5f575 100644 --- a/src/video_core/shader_notify.cpp +++ b/src/video_core/shader_notify.cpp @@ -18,7 +18,7 @@ int ShaderNotify::ShadersBuilding() noexcept { const int now_complete = num_complete.load(std::memory_order::relaxed); const int now_building = num_building.load(std::memory_order::relaxed); if (now_complete == now_building) { - const auto now = std::chrono::high_resolution_clock::now(); + const auto now = std::chrono::steady_clock::now(); if (completed && num_complete == num_when_completed) { if (now - complete_time > TIME_TO_STOP_REPORTING) { report_base = now_complete; diff --git a/src/video_core/shader_notify.h b/src/video_core/shader_notify.h index ad363bfb5..4d8d52071 100644 --- a/src/video_core/shader_notify.h +++ b/src/video_core/shader_notify.h @@ -28,6 +28,6 @@ private: bool completed{}; int num_when_completed{}; - std::chrono::high_resolution_clock::time_point complete_time; + std::chrono::steady_clock::time_point complete_time; }; } // namespace VideoCore diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index ae842306c..b001b8c23 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp @@ -136,7 +136,7 @@ void LoadingScreen::OnLoadComplete() { void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { using namespace std::chrono; - const auto now = high_resolution_clock::now(); + const auto now = steady_clock::now(); // reset the timer if the stage changes if (stage != previous_stage) { ui->progress_bar->setStyleSheet(QString::fromUtf8(progressbar_style[stage])); @@ -160,7 +160,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size // If theres a drastic slowdown in the rate, then display an estimate if (now - previous_time > milliseconds{50} || slow_shader_compile_start) { if (!slow_shader_compile_start) { - slow_shader_start = high_resolution_clock::now(); + slow_shader_start = steady_clock::now(); slow_shader_compile_start = true; slow_shader_first_value = value; } diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h index 801d08e1a..29155a77c 100644 --- a/src/yuzu/loading_screen.h +++ b/src/yuzu/loading_screen.h @@ -84,8 +84,8 @@ private: // shaders, it will start quickly but end slow if new shaders were added since previous launch. // These variables are used to detect the change in speed so we can generate an ETA bool slow_shader_compile_start = false; - std::chrono::high_resolution_clock::time_point slow_shader_start; - std::chrono::high_resolution_clock::time_point previous_time; + std::chrono::steady_clock::time_point slow_shader_start; + std::chrono::steady_clock::time_point previous_time; std::size_t slow_shader_first_value = 0; }; From 5ba7b11ba49ecba530612248286482f94799672c Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 27 Nov 2021 23:26:51 -0600 Subject: [PATCH 159/291] yuzu: Implement basic controller navigation --- src/yuzu/CMakeLists.txt | 2 + src/yuzu/applets/qt_controller.h | 4 +- src/yuzu/applets/qt_profile_select.cpp | 17 ++- src/yuzu/applets/qt_profile_select.h | 8 +- src/yuzu/game_list.cpp | 20 +++ src/yuzu/game_list.h | 5 + src/yuzu/main.cpp | 9 +- src/yuzu/util/controller_navigation.cpp | 177 ++++++++++++++++++++++++ src/yuzu/util/controller_navigation.h | 51 +++++++ 9 files changed, 285 insertions(+), 8 deletions(-) create mode 100644 src/yuzu/util/controller_navigation.cpp create mode 100644 src/yuzu/util/controller_navigation.h diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index a44815e71..732e8c276 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -152,6 +152,8 @@ add_executable(yuzu main.ui uisettings.cpp uisettings.h + util/controller_navigation.cpp + util/controller_navigation.h util/limitable_input_dialog.cpp util/limitable_input_dialog.h util/overlay_dialog.cpp diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index cc343e5ae..7ab9ced3d 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -7,7 +7,6 @@ #include #include #include -#include "core/core.h" #include "core/frontend/applets/controller.h" class GMainWindow; @@ -32,8 +31,9 @@ class System; } namespace Core::HID { +class HIDCore; enum class NpadStyleIndex : u8; -} +} // namespace Core::HID class QtControllerSelectorDialog final : public QDialog { Q_OBJECT diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index a56638e21..7b19f1f8d 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "core/hle/lock.h" #include "yuzu/applets/qt_profile_select.h" #include "yuzu/main.h" +#include "yuzu/util/controller_navigation.h" namespace { QString FormatUserEntryText(const QString& username, Common::UUID uuid) { @@ -45,7 +47,7 @@ QPixmap GetIcon(Common::UUID uuid) { } } // Anonymous namespace -QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) +QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent) : QDialog(parent), profile_manager(std::make_unique()) { outer_layout = new QVBoxLayout; @@ -65,6 +67,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) tree_view = new QTreeView; item_model = new QStandardItemModel(tree_view); tree_view->setModel(item_model); + controller_navigation = new ControllerNavigation(hid_core, this); tree_view->setAlternatingRowColors(true); tree_view->setSelectionMode(QHeaderView::SingleSelection); @@ -91,6 +94,14 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) scroll_area->setLayout(layout); connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); + connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, + [this](Qt::Key key) { + if (!this->isActiveWindow()) { + return; + } + QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); + QCoreApplication::postEvent(tree_view, event); + }); const auto& profiles = profile_manager->GetAllUsers(); for (const auto& user : profiles) { @@ -113,7 +124,9 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) resize(550, 400); } -QtProfileSelectionDialog::~QtProfileSelectionDialog() = default; +QtProfileSelectionDialog::~QtProfileSelectionDialog() { + controller_navigation->UnloadController(); +}; int QtProfileSelectionDialog::exec() { // Skip profile selection when there's only one. diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h index 4e9037488..56496ed31 100644 --- a/src/yuzu/applets/qt_profile_select.h +++ b/src/yuzu/applets/qt_profile_select.h @@ -11,6 +11,7 @@ #include "core/frontend/applets/profile_select.h" #include "core/hle/service/acc/profile_manager.h" +class ControllerNavigation; class GMainWindow; class QDialogButtonBox; class QGraphicsScene; @@ -20,11 +21,15 @@ class QStandardItem; class QStandardItemModel; class QVBoxLayout; +namespace Core::HID { +class HIDCore; +} // namespace Core::HID + class QtProfileSelectionDialog final : public QDialog { Q_OBJECT public: - explicit QtProfileSelectionDialog(QWidget* parent); + explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent); ~QtProfileSelectionDialog() override; int exec() override; @@ -51,6 +56,7 @@ private: QDialogButtonBox* buttons; std::unique_ptr profile_manager; + ControllerNavigation* controller_navigation = nullptr; }; class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 2af95dbe5..1a5e41588 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -17,6 +17,7 @@ #include #include "common/common_types.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "yuzu/compatibility_list.h" @@ -25,6 +26,7 @@ #include "yuzu/game_list_worker.h" #include "yuzu/main.h" #include "yuzu/uisettings.h" +#include "yuzu/util/controller_navigation.h" GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent) : QObject(parent), gamelist{gamelist} {} @@ -312,6 +314,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide this->main_window = parent; layout = new QVBoxLayout; tree_view = new QTreeView; + controller_navigation = new ControllerNavigation(system.HIDCore(), this); search_field = new GameListSearchField(this); item_model = new QStandardItemModel(tree_view); tree_view->setModel(item_model); @@ -341,6 +344,18 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded); connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded); + connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, + [this](Qt::Key key) { + // Avoid pressing buttons while playing + if (system.IsPoweredOn()) { + return; + } + if (!this->isActiveWindow()) { + return; + } + QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); + QCoreApplication::postEvent(tree_view, event); + }); // We must register all custom types with the Qt Automoc system so that we are able to use // it with signals/slots. In this case, QList falls under the umbrells of custom types. @@ -353,7 +368,12 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide setLayout(layout); } +void GameList::UnloadController() { + controller_navigation->UnloadController(); +} + GameList::~GameList() { + UnloadController(); emit ShouldCancelWorker(); } diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 675469e66..a94ea1477 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -24,6 +24,7 @@ #include "uisettings.h" #include "yuzu/compatibility_list.h" +class ControllerNavigation; class GameListWorker; class GameListSearchField; class GameListDir; @@ -88,6 +89,9 @@ public: void SaveInterfaceLayout(); void LoadInterfaceLayout(); + /// Disables events from the emulated controller + void UnloadController(); + static const QStringList supported_file_extensions; signals: @@ -143,6 +147,7 @@ private: QStandardItemModel* item_model = nullptr; GameListWorker* current_worker = nullptr; QFileSystemWatcher* watcher = nullptr; + ControllerNavigation* controller_navigation = nullptr; CompatibilityList compatibility_list; friend class GameListSearchField; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9bd0db10a..f266fd963 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -449,7 +449,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers( } void GMainWindow::ProfileSelectorSelectProfile() { - QtProfileSelectionDialog dialog(this); + QtProfileSelectionDialog dialog(system->HIDCore(), this); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); @@ -1346,7 +1346,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p } void GMainWindow::SelectAndSetCurrentUser() { - QtProfileSelectionDialog dialog(this); + QtProfileSelectionDialog dialog(system->HIDCore(), this); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -1608,7 +1608,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target if (has_user_save) { // User save data const auto select_profile = [this] { - QtProfileSelectionDialog dialog(this); + QtProfileSelectionDialog dialog(system->HIDCore(), this); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -3376,7 +3376,10 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); hotkey_registry.SaveHotkeys(); + + // Unload controllers early controller_dialog->UnloadController(); + game_list->UnloadController(); system->HIDCore().UnloadInputDevices(); // Shutdown session if the emu thread is active... diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp new file mode 100644 index 000000000..86fb28b9f --- /dev/null +++ b/src/yuzu/util/controller_navigation.cpp @@ -0,0 +1,177 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/settings_input.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "yuzu/util/controller_navigation.h" + +ControllerNavigation::ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent) { + player1_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); + handheld_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdateEvent(type); }, + .is_npad_service = false, + }; + player1_callback_key = player1_controller->SetCallback(engine_callback); + handheld_callback_key = handheld_controller->SetCallback(engine_callback); + is_controller_set = true; +} + +ControllerNavigation::~ControllerNavigation() { + UnloadController(); +} + +void ControllerNavigation::UnloadController() { + if (is_controller_set) { + player1_controller->DeleteCallback(player1_callback_key); + handheld_controller->DeleteCallback(handheld_callback_key); + is_controller_set = false; + } +} + +void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_button, + Qt::Key key) { + if (button_values[native_button].value && !button_values[native_button].locked) { + emit TriggerKeyboardEvent(key); + } +} + +void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) { + std::lock_guard lock{mutex}; + if (type == Core::HID::ControllerTriggerType::Button) { + ControllerUpdateButton(); + return; + } + + if (type == Core::HID::ControllerTriggerType::Stick) { + ControllerUpdateStick(); + return; + } +} + +void ControllerNavigation::ControllerUpdateButton() { + const auto controller_type = player1_controller->GetNpadStyleIndex(); + const auto& player1_buttons = player1_controller->GetButtonsValues(); + const auto& handheld_buttons = handheld_controller->GetButtonsValues(); + + for (std::size_t i = 0; i < player1_buttons.size(); ++i) { + const bool button = player1_buttons[i].value || handheld_buttons[i].value; + // Trigger only once + button_values[i].locked = button == button_values[i].value; + button_values[i].value = button; + } + + switch (controller_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::GameCube: + TriggerButton(Settings::NativeButton::A, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::B, Qt::Key_Escape); + TriggerButton(Settings::NativeButton::DDown, Qt::Key_Down); + TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Left); + TriggerButton(Settings::NativeButton::DRight, Qt::Key_Right); + TriggerButton(Settings::NativeButton::DUp, Qt::Key_Up); + break; + case Core::HID::NpadStyleIndex::JoyconLeft: + TriggerButton(Settings::NativeButton::DDown, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Escape); + break; + case Core::HID::NpadStyleIndex::JoyconRight: + TriggerButton(Settings::NativeButton::X, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::A, Qt::Key_Escape); + break; + default: + break; + } +} + +void ControllerNavigation::ControllerUpdateStick() { + const auto controller_type = player1_controller->GetNpadStyleIndex(); + const auto& player1_sticks = player1_controller->GetSticksValues(); + const auto& handheld_sticks = player1_controller->GetSticksValues(); + bool update = false; + + for (std::size_t i = 0; i < player1_sticks.size(); ++i) { + const Common::Input::StickStatus stick{ + .left = player1_sticks[i].left || handheld_sticks[i].left, + .right = player1_sticks[i].right || handheld_sticks[i].right, + .up = player1_sticks[i].up || handheld_sticks[i].up, + .down = player1_sticks[i].down || handheld_sticks[i].down, + }; + // Trigger only once + if (stick.down != stick_values[i].down || stick.left != stick_values[i].left || + stick.right != stick_values[i].right || stick.up != stick_values[i].up) { + update = true; + } + stick_values[i] = stick; + } + + if (!update) { + return; + } + + switch (controller_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::GameCube: + if (stick_values[Settings::NativeAnalog::LStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + case Core::HID::NpadStyleIndex::JoyconLeft: + if (stick_values[Settings::NativeAnalog::LStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + case Core::HID::NpadStyleIndex::JoyconRight: + if (stick_values[Settings::NativeAnalog::RStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + default: + break; + } +} diff --git a/src/yuzu/util/controller_navigation.h b/src/yuzu/util/controller_navigation.h new file mode 100644 index 000000000..7c616a088 --- /dev/null +++ b/src/yuzu/util/controller_navigation.h @@ -0,0 +1,51 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include +#include + +#include "common/input.h" +#include "common/settings_input.h" + +namespace Core::HID { +using ButtonValues = std::array; +using SticksValues = std::array; +enum class ControllerTriggerType; +class EmulatedController; +class HIDCore; +} // namespace Core::HID + +class ControllerNavigation : public QObject { + Q_OBJECT + +public: + explicit ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent = nullptr); + ~ControllerNavigation(); + + /// Disables events from the emulated controller + void UnloadController(); + +signals: + void TriggerKeyboardEvent(Qt::Key key); + +private: + void TriggerButton(Settings::NativeButton::Values native_button, Qt::Key key); + void ControllerUpdateEvent(Core::HID::ControllerTriggerType type); + + void ControllerUpdateButton(); + + void ControllerUpdateStick(); + + Core::HID::ButtonValues button_values{}; + Core::HID::SticksValues stick_values{}; + + int player1_callback_key{}; + int handheld_callback_key{}; + bool is_controller_set{}; + mutable std::mutex mutex; + Core::HID::EmulatedController* player1_controller; + Core::HID::EmulatedController* handheld_controller; +}; From f138731e2fc46d44ae2dc3a15e0dd435d65ddb8d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 2 Dec 2021 20:12:24 -0500 Subject: [PATCH 160/291] service: am: ISelfController: Stub SaveCurrentScreenshot - Used by Disney Magical World 2: Enchanted Edition --- src/core/hle/service/am/am.cpp | 14 +++++++++++++- src/core/hle/service/am/am.h | 1 + src/core/hle/service/caps/caps.h | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index aee8d4f93..e60661fe1 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -30,6 +30,7 @@ #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/bcat/backend/backend.h" +#include "core/hle/service/caps/caps.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -298,7 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, {110, nullptr, "SetApplicationAlbumUserData"}, - {120, nullptr, "SaveCurrentScreenshot"}, + {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, {130, nullptr, "SetRecordVolumeMuted"}, {1000, nullptr, "GetDebugStorageChannel"}, }; @@ -579,6 +580,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo rb.Push(ResultSuccess); } +void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto album_report_option = rp.PopEnum(); + + LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + AppletMessageQueue::AppletMessageQueue(Core::System& system) : service_context{system, "AppletMessageQueue"} { on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 202d20757..2a578aea5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -151,6 +151,7 @@ private: void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); + void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx); enum class ScreenshotPermission : u32 { Inherit = 0, diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index b18adcb9d..7254055e6 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h @@ -24,7 +24,7 @@ enum class AlbumImageOrientation { Orientation3 = 3, }; -enum class AlbumReportOption { +enum class AlbumReportOption : s32 { Disable = 0, Enable = 1, }; From cd27f211c8ad67c73c831e57a4eb298f9693253f Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 28 Nov 2021 23:51:25 -0700 Subject: [PATCH 161/291] video_core/codecs: more robust ffmpeg hwdecoder selection logic --- .../command_classes/codecs/codec.cpp | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 02d309170..1949a8cf3 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -23,6 +23,14 @@ namespace Tegra { namespace { constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12; constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P; +constexpr std::array PREFERRED_GPU_DECODERS = {AV_HWDEVICE_TYPE_CUDA, +#ifdef _WIN32 + AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2, +#elif linux + AV_HWDEVICE_TYPE_VDPAU, +#endif + // last resort for Linux Flatpak (w/ NVIDIA) + AV_HWDEVICE_TYPE_VULKAN}; void AVPacketDeleter(AVPacket* ptr) { av_packet_free(&ptr); @@ -61,6 +69,19 @@ Codec::~Codec() { av_buffer_unref(&av_gpu_decoder); } +// List all the currently available hwcontext in ffmpeg +static std::vector ListSupportedContexts() { + std::vector contexts{}; + enum AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; + do { + current_device_type = av_hwdevice_iterate_types(current_device_type); + // filter out VA-API since we will try that first if supported + if (current_device_type != AV_HWDEVICE_TYPE_VAAPI) + contexts.push_back(current_device_type); + } while (current_device_type != AV_HWDEVICE_TYPE_NONE); + return contexts; +} + #ifdef LIBVA_FOUND // List all the currently loaded Linux modules static std::vector ListLinuxKernelModules() { @@ -122,16 +143,12 @@ bool Codec::CreateGpuAvDevice() { av_dict_free(&hwdevice_options); #endif static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; - static constexpr std::array GPU_DECODER_TYPES{ -#ifdef linux - AV_HWDEVICE_TYPE_VDPAU, -#endif - AV_HWDEVICE_TYPE_CUDA, -#ifdef _WIN32 - AV_HWDEVICE_TYPE_D3D11VA, -#endif - }; - for (const auto& type : GPU_DECODER_TYPES) { + static const auto supported_contexts = ListSupportedContexts(); + for (const auto& type : PREFERRED_GPU_DECODERS) { + if (std::none_of(supported_contexts.begin(), supported_contexts.end(), + [&type](const auto& context) { return context == type; })) { + continue; + } const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); if (hwdevice_res < 0) { LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}", From 20a46790d7059c7fa8efeb1c95e62a57d97e42e3 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Mon, 29 Nov 2021 16:47:24 -0700 Subject: [PATCH 162/291] video_core/codec: address comments --- .../command_classes/codecs/codec.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 1949a8cf3..2c0d8da64 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -23,14 +23,17 @@ namespace Tegra { namespace { constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12; constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P; -constexpr std::array PREFERRED_GPU_DECODERS = {AV_HWDEVICE_TYPE_CUDA, +constexpr std::array PREFERRED_GPU_DECODERS = { + AV_HWDEVICE_TYPE_CUDA, #ifdef _WIN32 - AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2, -#elif linux - AV_HWDEVICE_TYPE_VDPAU, + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_DXVA2, +#elif defined(__linux__) + AV_HWDEVICE_TYPE_VDPAU, #endif - // last resort for Linux Flatpak (w/ NVIDIA) - AV_HWDEVICE_TYPE_VULKAN}; + // last resort for Linux Flatpak (w/ NVIDIA) + AV_HWDEVICE_TYPE_VULKAN, +}; void AVPacketDeleter(AVPacket* ptr) { av_packet_free(&ptr); @@ -72,12 +75,13 @@ Codec::~Codec() { // List all the currently available hwcontext in ffmpeg static std::vector ListSupportedContexts() { std::vector contexts{}; - enum AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; + AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; do { current_device_type = av_hwdevice_iterate_types(current_device_type); // filter out VA-API since we will try that first if supported - if (current_device_type != AV_HWDEVICE_TYPE_VAAPI) + if (current_device_type != AV_HWDEVICE_TYPE_VAAPI) { contexts.push_back(current_device_type); + } } while (current_device_type != AV_HWDEVICE_TYPE_NONE); return contexts; } From a578df4c6bd06c622baddd77d4e456150a673121 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Thu, 2 Dec 2021 21:27:41 -0700 Subject: [PATCH 163/291] video_core/codecs: more fixes for VAAPI detection ... * skip impersonated VAAPI implementaions ("imposter detection") * place VAAPI priority below CUDA/NVDEC/CUVID --- .../command_classes/codecs/codec.cpp | 88 ++++++------------- 1 file changed, 25 insertions(+), 63 deletions(-) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 2c0d8da64..2a532b883 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -17,6 +17,10 @@ extern "C" { #include +#ifdef LIBVA_FOUND +// for querying VAAPI driver information +#include +#endif } namespace Tegra { @@ -29,6 +33,7 @@ constexpr std::array PREFERRED_GPU_DECODERS = { AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2, #elif defined(__linux__) + AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, #endif // last resort for Linux Flatpak (w/ NVIDIA) @@ -78,79 +83,18 @@ static std::vector ListSupportedContexts() { AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; do { current_device_type = av_hwdevice_iterate_types(current_device_type); - // filter out VA-API since we will try that first if supported - if (current_device_type != AV_HWDEVICE_TYPE_VAAPI) { - contexts.push_back(current_device_type); - } + contexts.push_back(current_device_type); } while (current_device_type != AV_HWDEVICE_TYPE_NONE); return contexts; } -#ifdef LIBVA_FOUND -// List all the currently loaded Linux modules -static std::vector ListLinuxKernelModules() { - using FILEPtr = std::unique_ptr; - auto module_listing = FILEPtr{fopen("/proc/modules", "rt"), std::fclose}; - std::vector modules{}; - if (!module_listing) { - LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules"); - return modules; - } - char* buffer = nullptr; - size_t buf_len = 0; - while (getline(&buffer, &buf_len, module_listing.get()) != -1) { - // format for the module listing file (sysfs) - // - auto line = std::string(buffer); - // we are only interested in module names - auto name_pos = line.find_first_of(" "); - if (name_pos == std::string::npos) { - continue; - } - modules.push_back(line.erase(name_pos)); - } - free(buffer); - return modules; -} -#endif - bool Codec::CreateGpuAvDevice() { -#if defined(LIBVA_FOUND) - static constexpr std::array VAAPI_DRIVERS = { - "i915", - "iHD", - "amdgpu", - }; - AVDictionary* hwdevice_options = nullptr; - const auto loaded_modules = ListLinuxKernelModules(); - av_dict_set(&hwdevice_options, "connection_type", "drm", 0); - for (const auto& driver : VAAPI_DRIVERS) { - // first check if the target driver is loaded in the kernel - bool found = std::any_of(loaded_modules.begin(), loaded_modules.end(), - [&driver](const auto& module) { return module == driver; }); - if (!found) { - LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver); - continue; - } - av_dict_set(&hwdevice_options, "kernel_driver", driver, 0); - const int hwdevice_error = av_hwdevice_ctx_create(&av_gpu_decoder, AV_HWDEVICE_TYPE_VAAPI, - nullptr, hwdevice_options, 0); - if (hwdevice_error >= 0) { - LOG_INFO(Service_NVDRV, "Using VA-API with {}", driver); - av_dict_free(&hwdevice_options); - av_codec_ctx->pix_fmt = AV_PIX_FMT_VAAPI; - return true; - } - LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed {}", hwdevice_error); - } - LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed for all drivers"); - av_dict_free(&hwdevice_options); -#endif static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; static const auto supported_contexts = ListSupportedContexts(); for (const auto& type : PREFERRED_GPU_DECODERS) { if (std::none_of(supported_contexts.begin(), supported_contexts.end(), [&type](const auto& context) { return context == type; })) { + LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); continue; } const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); @@ -159,6 +103,24 @@ bool Codec::CreateGpuAvDevice() { av_hwdevice_get_type_name(type), hwdevice_res); continue; } +#ifdef LIBVA_FOUND + if (type == AV_HWDEVICE_TYPE_VAAPI) { + // we need to determine if this is an impersonated VAAPI driver + AVHWDeviceContext* hwctx = + static_cast(static_cast(av_gpu_decoder->data)); + AVVAAPIDeviceContext* vactx = static_cast(hwctx->hwctx); + const char* vendor_name = vaQueryVendorString(vactx->display); + if (strstr(vendor_name, "VDPAU backend")) { + // VDPAU impersonated VAAPI impl's are super buggy, we need to skip them + LOG_DEBUG(Service_NVDRV, "Skipping vdapu impersonated VAAPI driver"); + continue; + } else { + // according to some user testing, certain vaapi driver (Intel?) could be buggy + // so let's log the driver name which may help the developers/supporters + LOG_DEBUG(Service_NVDRV, "Using VAAPI driver: {}", vendor_name); + } + } +#endif for (int i = 0;; i++) { const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i); if (!config) { From e7f10de11a935423b233cda0b156e5e8e786bd1f Mon Sep 17 00:00:00 2001 From: liushuyu Date: Thu, 2 Dec 2021 22:35:30 -0700 Subject: [PATCH 164/291] video_core/cmake: link against libva explicitly ... ... to fix build on Flatpak (and self-builds) --- src/video_core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 91a30fef7..6a6325e38 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(host_shaders) if(LIBVA_FOUND) set_source_files_properties(command_classes/codecs/codec.cpp PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1) + list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES}) endif() add_library(video_core STATIC From f919498f8f4e36477d8ea3424f9ecbfae7576340 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:12:23 -0500 Subject: [PATCH 165/291] native_clock: Wait for less time in EstimateRDTSCFrequency In my testing, waiting for 200ms provided the same level of precision as the previous implementation when estimating the RDTSC frequency. This significantly improves the yuzu executable launch times since we reduced the wait time from 3 seconds to 200 milliseconds. --- src/common/x64/native_clock.cpp | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 28f834443..82ee2c8a1 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -15,26 +15,26 @@ namespace Common { u64 EstimateRDTSCFrequency() { - const auto milli_10 = std::chrono::milliseconds{10}; - // get current time + // Discard the first result measuring the rdtsc. _mm_mfence(); - const u64 tscStart = __rdtsc(); - const auto startTime = std::chrono::steady_clock::now(); - // wait roughly 3 seconds - while (true) { - auto milli = std::chrono::duration_cast( - std::chrono::steady_clock::now() - startTime); - if (milli.count() >= 3000) - break; - std::this_thread::sleep_for(milli_10); - } - const auto endTime = std::chrono::steady_clock::now(); + __rdtsc(); + std::this_thread::sleep_for(std::chrono::milliseconds{1}); _mm_mfence(); - const u64 tscEnd = __rdtsc(); - // calculate difference - const u64 timer_diff = - std::chrono::duration_cast(endTime - startTime).count(); - const u64 tsc_diff = tscEnd - tscStart; + __rdtsc(); + + // Get the current time. + const auto start_time = std::chrono::steady_clock::now(); + _mm_mfence(); + const u64 tsc_start = __rdtsc(); + // Wait for 200 milliseconds. + std::this_thread::sleep_for(std::chrono::milliseconds{200}); + const auto end_time = std::chrono::steady_clock::now(); + _mm_mfence(); + const u64 tsc_end = __rdtsc(); + // Calculate differences. + const u64 timer_diff = static_cast( + std::chrono::duration_cast(end_time - start_time).count()); + const u64 tsc_diff = tsc_end - tsc_start; const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); return tsc_freq; } From a5c212516cc4ca73807e03ab7c40e469ecabd061 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 4 Dec 2021 10:20:28 +0100 Subject: [PATCH 166/291] Texture Cache: Fix crashes on NVIDIA. --- src/video_core/texture_cache/texture_cache.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 565b99254..e195b1e98 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1122,7 +1122,7 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( break; } if (can_be_depth_blit) { - const ImageBase* const dst_image = src_id ? &slot_images[src_id] : nullptr; + const ImageBase* const dst_image = dst_id ? &slot_images[dst_id] : nullptr; DeduceBlitImages(dst_info, src_info, dst_image, src_image); if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { continue; @@ -1135,8 +1135,11 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); } } while (has_deleted_images); - if (GetFormatType(dst_info.format) != SurfaceType::ColorTexture) { - // Make sure the images are depth and/or stencil textures. + const ImageBase& src_image = slot_images[src_id]; + const ImageBase& dst_image = slot_images[dst_id]; + if (GetFormatType(dst_info.format) != GetFormatType(dst_image.info.format) || + GetFormatType(src_info.format) != GetFormatType(src_image.info.format)) { + // Make sure the images match the expected format. do { has_deleted_images = false; src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{}); From 5462485cc3835941713b835bce3b671b15d210b7 Mon Sep 17 00:00:00 2001 From: Feng Chen Date: Fri, 3 Dec 2021 12:31:07 +0800 Subject: [PATCH 167/291] Address feedback --- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 16 +++++++++------- .../hle/service/nvdrv/devices/nvhost_nvdec.h | 3 +++ .../hle/service/nvdrv/devices/nvhost_vic.cpp | 13 +++++++------ src/core/hle/service/nvdrv/devices/nvhost_vic.h | 3 +++ src/video_core/gpu.cpp | 9 +++++---- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 8e2a16d86..8314d1ec2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -20,8 +20,12 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& switch (command.group) { case 0x0: switch (command.cmd) { - case 0x1: + case 0x1: { + if (!fd_to_id.contains(fd)) { + fd_to_id[fd] = next_id++; + } return Submit(fd, input, output); + } case 0x2: return GetSyncpoint(input, output); case 0x3: @@ -62,15 +66,13 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(DeviceFD fd) { - static u32 next_id{}; - fd_to_id[fd] = next_id++; -} +void nvhost_nvdec::OnOpen(DeviceFD fd) {} void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); - if (fd_to_id.find(fd) != fd_to_id.end()) { - system.GPU().ClearCdmaInstance(fd_to_id[fd]); + const auto iter = fd_to_id.find(fd); + if (iter != fd_to_id.end()) { + system.GPU().ClearCdmaInstance(iter->second); } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 523d96e3a..a507c4d0a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -24,6 +24,9 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + +private: + u32 next_id{}; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 420fe21c8..76b39806f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -21,6 +21,9 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& i case 0x0: switch (command.cmd) { case 0x1: + if (!fd_to_id.contains(fd)) { + fd_to_id[fd] = next_id++; + } return Submit(fd, input, output); case 0x2: return GetSyncpoint(input, output); @@ -62,14 +65,12 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& i return NvResult::NotImplemented; } -void nvhost_vic::OnOpen(DeviceFD fd) { - static u32 next_id{}; - fd_to_id[fd] = next_id++; -} +void nvhost_vic::OnOpen(DeviceFD fd) {} void nvhost_vic::OnClose(DeviceFD fd) { - if (fd_to_id.find(fd) != fd_to_id.end()) { - system.GPU().ClearCdmaInstance(fd_to_id[fd]); + const auto iter = fd_to_id.find(fd); + if (iter != fd_to_id.end()) { + system.GPU().ClearCdmaInstance(iter->second); } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 6d7fda9d1..c9732c037 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -23,5 +23,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + +private: + u32 next_id{}; }; } // namespace Service::Nvidia::Devices diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 27a47954d..8788f5148 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -333,8 +333,8 @@ struct GPU::Impl { return; } - if (cdma_pushers.find(id) == cdma_pushers.end()) { - cdma_pushers[id] = std::make_unique(gpu); + if (!cdma_pushers.contains(id)) { + cdma_pushers.insert_or_assign(id, std::make_unique(gpu)); } // SubmitCommandBuffer would make the nvdec operations async, this is not currently working @@ -345,8 +345,9 @@ struct GPU::Impl { /// Frees the CDMAPusher instance to free up resources void ClearCdmaInstance(u32 id) { - if (cdma_pushers.find(id) != cdma_pushers.end()) { - cdma_pushers.erase(id); + const auto iter = cdma_pushers.find(id); + if (iter != cdma_pushers.end()) { + cdma_pushers.erase(iter); } } From 7fe455e42ea1a8d5e702258212d54f21f1f31610 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 4 Dec 2021 19:37:03 -0600 Subject: [PATCH 168/291] core/hid: Ensure only valid npad are connected --- src/core/hid/emulated_controller.cpp | 43 +++++ src/core/hid/emulated_controller.h | 14 ++ src/core/hid/hid_core.cpp | 10 ++ src/core/hid/hid_core.h | 2 +- src/core/hid/hid_types.h | 2 + src/core/hle/service/hid/controllers/npad.cpp | 30 ++-- .../configuration/configure_input_player.cpp | 149 ++++++++---------- src/yuzu/main.cpp | 3 + 8 files changed, 156 insertions(+), 97 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 466ff5542..720706794 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -866,7 +866,50 @@ void EmulatedController::SetLedPattern() { } } +void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) { + supported_style_tag = supported_styles; + if (!is_connected) { + return; + } + if (!IsControllerSupported()) { + LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", + npad_type); + Disconnect(); + } +} + +bool EmulatedController::IsControllerSupported() const { + switch (npad_type) { + case NpadStyleIndex::ProController: + return supported_style_tag.fullkey; + case NpadStyleIndex::JoyconDual: + return supported_style_tag.joycon_dual; + case NpadStyleIndex::JoyconLeft: + return supported_style_tag.joycon_left; + case NpadStyleIndex::JoyconRight: + return supported_style_tag.joycon_right; + case NpadStyleIndex::GameCube: + return supported_style_tag.gamecube; + case NpadStyleIndex::Pokeball: + return supported_style_tag.palma; + case NpadStyleIndex::NES: + return supported_style_tag.lark; + case NpadStyleIndex::SNES: + return supported_style_tag.lucia; + case NpadStyleIndex::N64: + return supported_style_tag.lagoon; + case NpadStyleIndex::SegaGenesis: + return supported_style_tag.lager; + default: + return false; + } +} + void EmulatedController::Connect() { + if (!IsControllerSupported()) { + LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type); + return; + } { std::lock_guard lock{mutex}; if (is_configuring) { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 5887e3e38..425b3e7c4 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -160,6 +160,13 @@ public: */ NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const; + /** + * Sets the supported controller types. Disconnects the controller if current type is not + * supported + * @param supported_styles bitflag with supported types + */ + void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); + /// Sets the connected status to true void Connect(); @@ -310,6 +317,12 @@ private: /// Set the params for TAS devices void LoadTASParams(); + /** + * Checks the current controller type against the supported_style_tag + * @return true if the controller is supported + */ + bool IsControllerSupported() const; + /** * Updates the button status of the controller * @param callback A CallbackStatus containing the button status @@ -354,6 +367,7 @@ private: NpadIdType npad_id_type; NpadStyleIndex npad_type{NpadStyleIndex::None}; + NpadStyleTag supported_style_tag{NpadStyleSet::All}; bool is_connected{false}; bool is_configuring{false}; f32 motion_sensitivity{0.01f}; diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 946adde00..0c3eb5a62 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -108,6 +108,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) { supported_style_tag.raw = style_tag.raw; + player_1->SetSupportedNpadStyleTag(supported_style_tag); + player_2->SetSupportedNpadStyleTag(supported_style_tag); + player_3->SetSupportedNpadStyleTag(supported_style_tag); + player_4->SetSupportedNpadStyleTag(supported_style_tag); + player_5->SetSupportedNpadStyleTag(supported_style_tag); + player_6->SetSupportedNpadStyleTag(supported_style_tag); + player_7->SetSupportedNpadStyleTag(supported_style_tag); + player_8->SetSupportedNpadStyleTag(supported_style_tag); + other->SetSupportedNpadStyleTag(supported_style_tag); + handheld->SetSupportedNpadStyleTag(supported_style_tag); } NpadStyleTag HIDCore::GetSupportedStyleTag() const { diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 140a0e962..2fb0f7e19 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -73,7 +73,7 @@ private: std::unique_ptr handheld; std::unique_ptr console; std::unique_ptr devices; - NpadStyleTag supported_style_tag; + NpadStyleTag supported_style_tag{NpadStyleSet::All}; }; } // namespace Core::HID diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 780659b86..7c12f01fc 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -256,6 +256,8 @@ enum class NpadStyleSet : u32 { Lager = 1U << 11, SystemExt = 1U << 29, System = 1U << 30, + + All = 0xFFFFFFFFU, }; static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 6916930f7..ae56f10cf 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -126,8 +126,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, } void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { - LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); auto& controller = GetControllerFromNpadIdType(npad_id); + if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { + return; + } + LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); auto& shared_memory = controller.shared_memory_entry; if (controller_type == Core::HID::NpadStyleIndex::None) { @@ -255,19 +258,7 @@ void Controller_NPad::OnInit() { if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { // We want to support all controllers - Core::HID::NpadStyleTag style{}; - style.handheld.Assign(1); - style.joycon_left.Assign(1); - style.joycon_right.Assign(1); - style.joycon_dual.Assign(1); - style.fullkey.Assign(1); - style.gamecube.Assign(1); - style.palma.Assign(1); - style.lark.Assign(1); - style.lucia.Assign(1); - style.lagoon.Assign(1); - style.lager.Assign(1); - hid_core.SetSupportedStyleTag(style); + hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); } supported_npad_id_types.resize(npad_id_list.size()); @@ -1072,13 +1063,18 @@ bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; const auto type_index_1 = controller_1->GetNpadStyleIndex(); const auto type_index_2 = controller_2->GetNpadStyleIndex(); + const auto is_connected_1 = controller_1->IsConnected(); + const auto is_connected_2 = controller_2->IsConnected(); - if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) { + if (!IsControllerSupported(type_index_1) && is_connected_1) { + return false; + } + if (!IsControllerSupported(type_index_2) && is_connected_2) { return false; } - AddNewControllerAt(type_index_2, npad_id_1); - AddNewControllerAt(type_index_1, npad_id_2); + UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); + UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); return true; } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 34099bc83..8a8be8e40 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -907,88 +907,79 @@ void ConfigureInputPlayer::UpdateUI() { } void ConfigureInputPlayer::SetConnectableControllers() { - const auto add_controllers = [this](bool enable_all, - Core::HID::NpadStyleTag npad_style_set = {}) { - index_controller_type_pairs.clear(); - ui->comboControllerType->clear(); + Core::HID::NpadStyleTag npad_style_set = hid_core.GetSupportedStyleTag(); + index_controller_type_pairs.clear(); + ui->comboControllerType->clear(); - if (enable_all || npad_style_set.fullkey == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::ProController); - ui->comboControllerType->addItem(tr("Pro Controller")); - } - - if (enable_all || npad_style_set.joycon_dual == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconDual); - ui->comboControllerType->addItem(tr("Dual Joycons")); - } - - if (enable_all || npad_style_set.joycon_left == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconLeft); - ui->comboControllerType->addItem(tr("Left Joycon")); - } - - if (enable_all || npad_style_set.joycon_right == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconRight); - ui->comboControllerType->addItem(tr("Right Joycon")); - } - - if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::Handheld); - ui->comboControllerType->addItem(tr("Handheld")); - } - - if (enable_all || npad_style_set.gamecube == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::GameCube); - ui->comboControllerType->addItem(tr("GameCube Controller")); - } - - // Disable all unsupported controllers - if (!Settings::values.enable_all_controllers) { - return; - } - if (enable_all || npad_style_set.palma == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::Pokeball); - ui->comboControllerType->addItem(tr("Poke Ball Plus")); - } - - if (enable_all || npad_style_set.lark == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::NES); - ui->comboControllerType->addItem(tr("NES Controller")); - } - - if (enable_all || npad_style_set.lucia == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::SNES); - ui->comboControllerType->addItem(tr("SNES Controller")); - } - - if (enable_all || npad_style_set.lagoon == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::N64); - ui->comboControllerType->addItem(tr("N64 Controller")); - } - - if (enable_all || npad_style_set.lager == 1) { - index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::SegaGenesis); - ui->comboControllerType->addItem(tr("Sega Genesis")); - } - }; - - if (!is_powered_on) { - add_controllers(true); - return; + if (npad_style_set.fullkey == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::ProController); + ui->comboControllerType->addItem(tr("Pro Controller")); } - add_controllers(false, hid_core.GetSupportedStyleTag()); + if (npad_style_set.joycon_dual == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::JoyconDual); + ui->comboControllerType->addItem(tr("Dual Joycons")); + } + + if (npad_style_set.joycon_left == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::JoyconLeft); + ui->comboControllerType->addItem(tr("Left Joycon")); + } + + if (npad_style_set.joycon_right == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::JoyconRight); + ui->comboControllerType->addItem(tr("Right Joycon")); + } + + if (player_index == 0 && npad_style_set.handheld == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::Handheld); + ui->comboControllerType->addItem(tr("Handheld")); + } + + if (npad_style_set.gamecube == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::GameCube); + ui->comboControllerType->addItem(tr("GameCube Controller")); + } + + // Disable all unsupported controllers + if (!Settings::values.enable_all_controllers) { + return; + } + if (npad_style_set.palma == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::Pokeball); + ui->comboControllerType->addItem(tr("Poke Ball Plus")); + } + + if (npad_style_set.lark == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::NES); + ui->comboControllerType->addItem(tr("NES Controller")); + } + + if (npad_style_set.lucia == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::SNES); + ui->comboControllerType->addItem(tr("SNES Controller")); + } + + if (npad_style_set.lagoon == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::N64); + ui->comboControllerType->addItem(tr("N64 Controller")); + } + + if (npad_style_set.lager == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Core::HID::NpadStyleIndex::SegaGenesis); + ui->comboControllerType->addItem(tr("Sega Genesis")); + } } Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f266fd963..5a9dec8f3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1516,6 +1516,9 @@ void GMainWindow::ShutdownGame() { input_subsystem->GetTas()->Stop(); OnTasStateChanged(); + // Enable all controllers + system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); From 722005697415463d1708b896d903b592086f134e Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Sat, 4 Dec 2021 23:06:56 -0800 Subject: [PATCH 169/291] Fixed #7502 --- src/yuzu/main.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f266fd963..77f2375ea 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1082,14 +1082,15 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { state != Qt::ApplicationActive) { LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state); } - if (ui->action_Pause->isEnabled() && - (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { - auto_paused = true; - OnPauseGame(); - } else if (emulation_running && !emu_thread->IsRunning() && auto_paused && - state == Qt::ApplicationActive) { - auto_paused = false; - OnStartGame(); + if (emulation_running) { + if (emu_thread->IsRunning() && + (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { + auto_paused = true; + OnPauseGame(); + } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) { + auto_paused = false; + OnStartGame(); + } } } From 7347cdb65150e6a8250a619020483ab6ffcf2dbb Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 5 Dec 2021 13:57:48 -0600 Subject: [PATCH 170/291] core/hid: Add missing controller type --- src/core/hid/emulated_controller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 720706794..fbb19f230 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -882,6 +882,8 @@ bool EmulatedController::IsControllerSupported() const { switch (npad_type) { case NpadStyleIndex::ProController: return supported_style_tag.fullkey; + case NpadStyleIndex::Handheld: + return supported_style_tag.handheld; case NpadStyleIndex::JoyconDual: return supported_style_tag.joycon_dual; case NpadStyleIndex::JoyconLeft: From 8aef8f39d86affd8fcc9a812d3d597f8eaee90b8 Mon Sep 17 00:00:00 2001 From: itsmeft24 Date: Sun, 5 Dec 2021 15:04:08 -0500 Subject: [PATCH 171/291] kernel: svc: Implement Map/UnmapProcessMemory and Create/ControlCodeMemory Used by Skyline modding framework --- src/core/hle/kernel/init/init_slab_setup.cpp | 2 + src/core/hle/kernel/k_class_token.cpp | 5 +- src/core/hle/kernel/k_code_memory.cpp | 159 ++++++++++++++ src/core/hle/kernel/k_code_memory.h | 76 +++++++ src/core/hle/kernel/k_memory_block.h | 20 ++ src/core/hle/kernel/k_page_linked_list.h | 4 + src/core/hle/kernel/k_page_table.cpp | 124 ++++++++++- src/core/hle/kernel/k_page_table.h | 8 + src/core/hle/kernel/kernel.h | 4 + src/core/hle/kernel/svc.cpp | 214 ++++++++++++++++++- src/core/hle/kernel/svc_wrap.h | 27 +++ 11 files changed, 636 insertions(+), 7 deletions(-) create mode 100644 src/core/hle/kernel/k_code_memory.cpp create mode 100644 src/core/hle/kernel/k_code_memory.h diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 8ff0f695d..36fc0944a 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/hardware_properties.h" #include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_code_memory.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" @@ -32,6 +33,7 @@ namespace Kernel::Init { HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ + HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp index 0be0027be..21e2fe494 100644 --- a/src/core/hle/kernel/k_class_token.cpp +++ b/src/core/hle/kernel/k_class_token.cpp @@ -6,6 +6,7 @@ #include "core/hle/kernel/k_class_token.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_code_memory.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_process.h" @@ -48,7 +49,7 @@ static_assert(ClassToken == 0b10001001'00000000); static_assert(ClassToken == 0b10010001'00000000); // static_assert(ClassToken == 0b01100001'00000000); // static_assert(ClassToken == 0b10100001'00000000); -// static_assert(ClassToken == 0b11000001'00000000); +static_assert(ClassToken == 0b11000001'00000000); // Ensure that the token hierarchy is correct. @@ -79,7 +80,7 @@ static_assert(ClassToken == ((0b10001001 << 8) | ClassToken == ((0b10010001 << 8) | ClassToken)); // static_assert(ClassToken == ((0b01100001 << 8) | ClassToken)); // static_assert(ClassToken == ((0b10100001 << 8) | ClassToken)); -// static_assert(ClassToken == ((0b11000001 << 8) | ClassToken)); +static_assert(ClassToken == ((0b11000001 << 8) | ClassToken)); // Ensure that the token hierarchy reflects the class hierarchy. diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp new file mode 100644 index 000000000..926d1c076 --- /dev/null +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -0,0 +1,159 @@ +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_code_memory.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/kernel/svc_wrap.h" +#include "core/hle/lock.h" +#include "core/hle/result.h" +#include "core/memory.h" +#include "core/reporter.h" +namespace Kernel { + +KCodeMemory::KCodeMemory(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {} + +ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) { + // Set members. + m_owner = kernel.CurrentProcess(); + + // Get the owner page table. + auto& page_table = m_owner->PageTable(); + + // Construct the page group. + KMemoryInfo kBlockInfo = page_table.QueryInfo(addr); + m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); + + // Lock the memory. + R_TRY(page_table.LockForCodeMemory(addr, size)) + + // Clear the memory. + for (const auto& block : m_page_group.Nodes()) { + std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); + } + + // Set remaining tracking members. + m_address = addr; + m_is_initialized = true; + m_is_owner_mapped = false; + m_is_mapped = false; + + // We succeeded. + return ResultSuccess; +} + +void KCodeMemory::Finalize() { + // Unlock. + if (!m_is_mapped && !m_is_owner_mapped) { + const size_t size = m_page_group.GetNumPages() * PageSize; + m_owner->PageTable().UnlockForCodeMemory(m_address, size); + } +} + +ResultCode KCodeMemory::Map(VAddr address, size_t size) { + // Validate the size. + R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + + // Lock ourselves. + KScopedLightLock lk(m_lock); + + // Ensure we're not already mapped. + R_UNLESS(!m_is_mapped, ResultInvalidState); + + // Map the memory. + R_TRY(kernel.CurrentProcess()->PageTable().MapPages( + address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); + + // Mark ourselves as mapped. + m_is_mapped = true; + + return ResultSuccess; +} + +ResultCode KCodeMemory::Unmap(VAddr address, size_t size) { + // Validate the size. + R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + + // Lock ourselves. + KScopedLightLock lk(m_lock); + + // Unmap the memory. + R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group, + KMemoryState::CodeOut)); + + // Mark ourselves as unmapped. + m_is_mapped = false; + + return ResultSuccess; +} + +ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) { + // Validate the size. + R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + + // Lock ourselves. + KScopedLightLock lk(m_lock); + + // Ensure we're not already mapped. + R_UNLESS(!m_is_owner_mapped, ResultInvalidState); + + // Convert the memory permission. + KMemoryPermission k_perm{}; + switch (perm) { + case Svc::MemoryPermission::Read: + k_perm = KMemoryPermission::UserRead; + break; + case Svc::MemoryPermission::ReadExecute: + k_perm = KMemoryPermission::UserReadExecute; + break; + default: + break; + } + + // Map the memory. + R_TRY( + m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm)); + + // Mark ourselves as mapped. + m_is_owner_mapped = true; + + return ResultSuccess; +} + +ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { + // Validate the size. + R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + + // Lock ourselves. + KScopedLightLock lk(m_lock); + + // Unmap the memory. + R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode)); + + // Mark ourselves as unmapped. + m_is_owner_mapped = false; + + return ResultSuccess; +} + +} // namespace Kernel \ No newline at end of file diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h new file mode 100644 index 000000000..a7f7d749b --- /dev/null +++ b/src/core/hle/kernel/k_code_memory.h @@ -0,0 +1,76 @@ +#pragma once + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/kernel/svc_wrap.h" +#include "core/hle/lock.h" +#include "core/hle/result.h" +#include "core/memory.h" +#include "core/reporter.h" + +namespace Kernel { + +enum class CodeMemoryOperation : u32 { Map = 0, MapToOwner = 1, Unmap = 2, UnmapFromOwner = 3 }; + +class KCodeMemory final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); + +private: + KPageLinkedList m_page_group; + KProcess* m_owner; + VAddr m_address; + KLightLock m_lock; + bool m_is_initialized; + bool m_is_owner_mapped; + bool m_is_mapped; + +public: + explicit KCodeMemory(KernelCore& kernel_); + + ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size); + void Finalize(); + + ResultCode Map(VAddr address, size_t size); + ResultCode Unmap(VAddr address, size_t size); + ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm); + ResultCode UnmapFromOwner(VAddr address, size_t size); + + bool IsInitialized() const { + return m_is_initialized; + } + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + KProcess* GetOwner() const { + return m_owner; + } + VAddr GetSourceAddress() { + return m_address; + } + size_t GetSize() const { + return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; + } +}; +} // namespace Kernel \ No newline at end of file diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index a7fdb5fb8..fd491146f 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -131,6 +131,26 @@ enum class KMemoryPermission : u8 { UserMask = static_cast(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | Svc::MemoryPermission::Execute), + + KernelShift = 3, + + KernelRead = Read << KernelShift, + KernelWrite = Write << KernelShift, + KernelExecute = Execute << KernelShift, + + NotMapped = (1 << (2 * KernelShift)), + + KernelReadWrite = KernelRead | KernelWrite, + KernelReadExecute = KernelRead | KernelExecute, + + UserRead = Read | KernelRead, + UserWrite = Write | KernelWrite, + UserExecute = Execute, + + UserReadWrite = UserRead | UserWrite, + UserReadExecute = UserRead | UserExecute, + + IpcLockChangeMask = NotMapped | UserReadWrite }; DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h index 3362fb236..0e2ae582a 100644 --- a/src/core/hle/kernel/k_page_linked_list.h +++ b/src/core/hle/kernel/k_page_linked_list.h @@ -27,6 +27,10 @@ public: return num_pages; } + constexpr std::size_t GetSize() const { + return GetNumPages() * PageSize; + } + private: u64 addr{}; std::size_t num_pages{}; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 9bda5c5b2..47f529fcd 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -368,6 +368,33 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st return ResultSuccess; } +ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, + KPageTable& src_page_table, VAddr src_addr) { + std::lock_guard lock{page_table_lock}; + + const std::size_t num_pages{size / PageSize}; + + // Check that the memory is mapped in the destination process. + size_t num_allocator_blocks; + R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All, + KMemoryState::SharedCode, KMemoryPermission::UserReadWrite, + KMemoryPermission::UserReadWrite, KMemoryAttribute::All, + KMemoryAttribute::None)); + + // Check that the memory is mapped in the source process. + R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess, + KMemoryState::FlagCanMapProcess, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::All, + KMemoryAttribute::None)); + + CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); + + // Apply the memory block update. + block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None, + KMemoryAttribute::None); + + return ResultSuccess; +} void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { auto node{page_linked_list.Nodes().begin()}; PAddr map_addr{node->GetAddress()}; @@ -942,6 +969,62 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) return ResultSuccess; } +ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { + + std::lock_guard lock{page_table_lock}; + + KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; + + KMemoryPermission old_perm{}; + + if (const ResultCode result{CheckMemoryState( + nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, + KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask, + KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; + result.IsError()) { + return result; + } + + new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; + + block_manager->UpdateLock( + addr, size / PageSize, + [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { + block->ShareToDevice(permission); + }, + new_perm); + + return ResultSuccess; +} + +ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { + + std::lock_guard lock{page_table_lock}; + + KMemoryPermission new_perm = KMemoryPermission::UserReadWrite; + + KMemoryPermission old_perm{}; + + if (const ResultCode result{CheckMemoryState( + nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, + KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::All, KMemoryAttribute::Locked)}; + result.IsError()) { + return result; + } + + new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; + + block_manager->UpdateLock( + addr, size / PageSize, + [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { + block->UnshareToDevice(permission); + }, + new_perm); + + return ResultSuccess; +} + ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { block_manager = std::make_unique(start, end); @@ -1231,4 +1314,43 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi return ResultSuccess; } -} // namespace Kernel +ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr) const { + + // Get information about the first block. + const VAddr last_addr = addr + size - 1; + KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; + KMemoryInfo info = it->GetMemoryInfo(); + + // If the start address isn't aligned, we need a block. + const size_t blocks_for_start_align = + (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0; + + while (true) { + // Validate against the provided masks. + R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); + + // Break once we're done. + if (last_addr <= info.GetLastAddress()) { + break; + } + + // Advance our iterator. + it++; + info = it->GetMemoryInfo(); + } + + // If the end address isn't aligned, we need a block. + const size_t blocks_for_end_align = + (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0; + + if (out_blocks_needed != nullptr) { + *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; + } + + return ResultSuccess; +} + +} // namespace Kernel \ No newline at end of file diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index b7ec38f06..d784aa67e 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -33,6 +33,8 @@ public: KMemoryPermission perm); ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); + ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, + VAddr src_addr); ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); ResultCode UnmapMemory(VAddr addr, std::size_t size); @@ -55,6 +57,8 @@ public: KMemoryPermission perm, PAddr map_addr = 0); ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); + ResultCode LockForCodeMemory(VAddr addr, std::size_t size); + ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); Common::PageTable& PageTableImpl() { return page_table_impl; @@ -115,6 +119,10 @@ private: return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr); } + ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr) const; std::recursive_mutex page_table_lock; std::unique_ptr block_manager; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d2ceae950..d847fd0c5 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -53,6 +53,7 @@ class KSharedMemoryInfo; class KThread; class KTransferMemory; class KWritableEvent; +class KCodeMemory; class PhysicalCore; class ServiceThread; class Synchronization; @@ -326,6 +327,8 @@ public: return slab_heap_container->transfer_memory; } else if constexpr (std::is_same_v) { return slab_heap_container->writeable_event; + } else if constexpr (std::is_same_v) { + return slab_heap_container->code_memory; } } @@ -377,6 +380,7 @@ private: KSlabHeap thread; KSlabHeap transfer_memory; KSlabHeap writeable_event; + KSlabHeap code_memory; }; std::unique_ptr slab_heap_container; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f0cd8471e..b37db918e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -18,6 +18,7 @@ #include "core/core_timing.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_code_memory.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_block.h" @@ -1197,6 +1198,22 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { } } +constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) { + return perm == Svc::MemoryPermission::ReadWrite; +} + +constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { + return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute; +} + +constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) { + return perm == Svc::MemoryPermission::None; +} + +constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { + return perm == Svc::MemoryPermission::None; +} + } // Anonymous namespace static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, @@ -1306,6 +1323,195 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); } +static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, + VAddr src_address, u64 size) { + LOG_TRACE(Kernel_SVC, + "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + dst_address, process_handle, src_address, size); + + // Validate the address/size. + R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); + R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); + + // Get the processes. + KProcess* dst_process = system.CurrentProcess(); + KScopedAutoObject src_process = + dst_process->GetHandleTable().GetObjectWithoutPseudoHandle(process_handle); + R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); + + // Get the page tables. + auto& dst_pt = dst_process->PageTable(); + auto& src_pt = src_process->PageTable(); + + // Validate that the mapping is in range. + R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); + R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), + ResultInvalidMemoryRegion); + + // Create a new page group. + KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address); + KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); + + // Map the group. + R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode, + KMemoryPermission::UserReadWrite)); + + return ResultSuccess; +} + +static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, + VAddr src_address, u64 size) { + LOG_TRACE(Kernel_SVC, + "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + dst_address, process_handle, src_address, size); + + // Validate the address/size. + R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); + R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); + + // Get the processes. + KProcess* dst_process = system.CurrentProcess(); + KScopedAutoObject src_process = + dst_process->GetHandleTable().GetObjectWithoutPseudoHandle(process_handle); + R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); + + // Get the page tables. + auto& dst_pt = dst_process->PageTable(); + auto& src_pt = src_process->PageTable(); + + // Validate that the mapping is in range. + R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); + R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), + ResultInvalidMemoryRegion); + + // Unmap the memory. + R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address)); + + return ResultSuccess; +} + +static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { + LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}", + static_cast(out), address, size); + // Get kernel instance. + auto& kernel = system.Kernel(); + + // Validate address / size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + + // Create the code memory. + + KCodeMemory* code_mem = KCodeMemory::Create(kernel); + R_UNLESS(code_mem != nullptr, ResultOutOfResource); + + // Verify that the region is in range. + R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size), + ResultInvalidCurrentMemory); + + // Initialize the code memory. + R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size)); + + // Register the code memory. + KCodeMemory::Register(kernel, code_mem); + + // Add the code memory to the handle table. + R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem)); + + code_mem->Close(); + + return ResultSuccess; +} + +static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation, + VAddr address, size_t size, Svc::MemoryPermission perm) { + + LOG_TRACE(Kernel_SVC, + "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " + "permission=0x{:X}", + code_memory_handle, operation, address, size, perm); + + // Validate the address / size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + + // Get the code memory from its handle. + KScopedAutoObject code_mem = + system.CurrentProcess()->GetHandleTable().GetObject(code_memory_handle); + R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle); + + // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process. + // This enables homebrew usage of these SVCs for JIT. + + // Perform the operation. + switch (static_cast(operation)) { + case CodeMemoryOperation::Map: { + // Check that the region is in range. + R_UNLESS( + system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Map the memory. + R_TRY(code_mem->Map(address, size)); + } break; + case CodeMemoryOperation::Unmap: { + // Check that the region is in range. + R_UNLESS( + system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Unmap the memory. + R_TRY(code_mem->Unmap(address, size)); + } break; + case CodeMemoryOperation::MapToOwner: { + // Check that the region is in range. + R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, + KMemoryState::GeneratedCode), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Map the memory to its owner. + R_TRY(code_mem->MapToOwner(address, size, perm)); + } break; + case CodeMemoryOperation::UnmapFromOwner: { + // Check that the region is in range. + R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, + KMemoryState::GeneratedCode), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Unmap the memory from its owner. + R_TRY(code_mem->UnmapFromOwner(address, size)); + } break; + default: + return ResultInvalidEnumValue; + } + + return ResultSuccess; +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -2600,8 +2806,8 @@ static const FunctionDef SVC_Table_64[] = { {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, {0x4A, nullptr, "SetUnsafeLimit"}, - {0x4B, nullptr, "CreateCodeMemory"}, - {0x4C, nullptr, "ControlCodeMemory"}, + {0x4B, SvcWrap64, "CreateCodeMemory"}, + {0x4C, SvcWrap64, "ControlCodeMemory"}, {0x4D, nullptr, "SleepSystem"}, {0x4E, nullptr, "ReadWriteRegister"}, {0x4F, nullptr, "SetProcessActivity"}, @@ -2641,8 +2847,8 @@ static const FunctionDef SVC_Table_64[] = { {0x71, nullptr, "ManageNamedPort"}, {0x72, nullptr, "ConnectToPort"}, {0x73, SvcWrap64, "SetProcessMemoryPermission"}, - {0x74, nullptr, "MapProcessMemory"}, - {0x75, nullptr, "UnmapProcessMemory"}, + {0x74, SvcWrap64, "MapProcessMemory"}, + {0x75, SvcWrap64, "UnmapProcessMemory"}, {0x76, SvcWrap64, "QueryProcessMemory"}, {0x77, SvcWrap64, "MapProcessCodeMemory"}, {0x78, SvcWrap64, "UnmapProcessCodeMemory"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 6e62e656f..86255fe6d 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -73,6 +73,23 @@ void SvcWrap64(Core::System& system) { .raw); } +// Used by MapProcessMemory and UnmapProcessMemory +template +void SvcWrap64(Core::System& system) { + FuncReturn(system, func(system, Param(system, 0), static_cast(Param(system, 1)), + Param(system, 2), Param(system, 3)) + .raw); +} + +// Used by ControlCodeMemory +template +void SvcWrap64(Core::System& system) { + FuncReturn(system, func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), Param(system, 2), Param(system, 3), + static_cast(Param(system, 4))) + .raw); +} + template void SvcWrap64(Core::System& system) { u32 param = 0; @@ -301,6 +318,16 @@ void SvcWrap64(Core::System& system) { FuncReturn(system, retval); } +// Used by CreateCodeMemory +template +void SvcWrap64(Core::System& system) { + u32 param_1 = 0; + const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); +} + template void SvcWrap64(Core::System& system) { u32 param_1 = 0; From 36350d3f78b331ef232cc8d935561670f2cdf949 Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Sun, 5 Dec 2021 15:56:44 -0500 Subject: [PATCH 172/291] Add KCodeMemory to CMakeLists.txt --- src/core/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eee8e2ccd..4a9aadd6d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -179,6 +179,8 @@ add_library(core STATIC hle/kernel/k_client_port.h hle/kernel/k_client_session.cpp hle/kernel/k_client_session.h + hle/kernel/k_code_memory.cpp + hle/kernel/k_code_memory.h hle/kernel/k_condition_variable.cpp hle/kernel/k_condition_variable.h hle/kernel/k_event.cpp From 41aec2773f382ac4ff27daee5401b78f7669190d Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:18:53 -0500 Subject: [PATCH 173/291] general: Add missing copyright notices --- src/audio_core/delay_line.cpp | 4 ++++ src/audio_core/delay_line.h | 4 ++++ src/common/host_memory.cpp | 4 ++++ src/core/hle/service/nvdrv/nvdata.h | 4 ++++ src/shader_recompiler/environment.h | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/src/audio_core/delay_line.cpp b/src/audio_core/delay_line.cpp index f4e4dd8d2..2793ed8db 100644 --- a/src/audio_core/delay_line.cpp +++ b/src/audio_core/delay_line.cpp @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #include #include "audio_core/delay_line.h" diff --git a/src/audio_core/delay_line.h b/src/audio_core/delay_line.h index cafddd432..84f11bc52 100644 --- a/src/audio_core/delay_line.h +++ b/src/audio_core/delay_line.h @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #pragma once #include "common/common_types.h" diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index b44a44949..28949fe5e 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #ifdef _WIN32 #include diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 3294bc0e7..5ab221fc1 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -1,3 +1,7 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #pragma once #include diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 8369d0d84..b4df73e8a 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #pragma once #include From 5286a7bc4ccf8da0827b0352f40dbce651b57d09 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:33:44 -0500 Subject: [PATCH 174/291] shader_recompiler: Rename backend emit_context files --- src/shader_recompiler/CMakeLists.txt | 12 ++++++------ .../{emit_context.cpp => glasm_emit_context.cpp} | 0 .../glasm/{emit_context.h => glasm_emit_context.h} | 0 .../glsl/{emit_context.cpp => glsl_emit_context.cpp} | 0 .../glsl/{emit_context.h => glsl_emit_context.h} | 0 .../{emit_context.cpp => spirv_emit_context.cpp} | 0 .../spirv/{emit_context.h => spirv_emit_context.h} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename src/shader_recompiler/backend/glasm/{emit_context.cpp => glasm_emit_context.cpp} (100%) rename src/shader_recompiler/backend/glasm/{emit_context.h => glasm_emit_context.h} (100%) rename src/shader_recompiler/backend/glsl/{emit_context.cpp => glsl_emit_context.cpp} (100%) rename src/shader_recompiler/backend/glsl/{emit_context.h => glsl_emit_context.h} (100%) rename src/shader_recompiler/backend/spirv/{emit_context.cpp => spirv_emit_context.cpp} (100%) rename src/shader_recompiler/backend/spirv/{emit_context.h => spirv_emit_context.h} (100%) diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index bc3df80c8..4c76ce1ea 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -1,7 +1,5 @@ add_library(shader_recompiler STATIC backend/bindings.h - backend/glasm/emit_context.cpp - backend/glasm/emit_context.h backend/glasm/emit_glasm.cpp backend/glasm/emit_glasm.h backend/glasm/emit_glasm_barriers.cpp @@ -22,10 +20,10 @@ add_library(shader_recompiler STATIC backend/glasm/emit_glasm_special.cpp backend/glasm/emit_glasm_undefined.cpp backend/glasm/emit_glasm_warp.cpp + backend/glasm/glasm_emit_context.cpp + backend/glasm/glasm_emit_context.h backend/glasm/reg_alloc.cpp backend/glasm/reg_alloc.h - backend/glsl/emit_context.cpp - backend/glsl/emit_context.h backend/glsl/emit_glsl.cpp backend/glsl/emit_glsl.h backend/glsl/emit_glsl_atomic.cpp @@ -47,10 +45,10 @@ add_library(shader_recompiler STATIC backend/glsl/emit_glsl_special.cpp backend/glsl/emit_glsl_undefined.cpp backend/glsl/emit_glsl_warp.cpp + backend/glsl/glsl_emit_context.cpp + backend/glsl/glsl_emit_context.h backend/glsl/var_alloc.cpp backend/glsl/var_alloc.h - backend/spirv/emit_context.cpp - backend/spirv/emit_context.h backend/spirv/emit_spirv.cpp backend/spirv/emit_spirv.h backend/spirv/emit_spirv_atomic.cpp @@ -72,6 +70,8 @@ add_library(shader_recompiler STATIC backend/spirv/emit_spirv_special.cpp backend/spirv/emit_spirv_undefined.cpp backend/spirv/emit_spirv_warp.cpp + backend/spirv/spirv_emit_context.cpp + backend/spirv/spirv_emit_context.h environment.h exception.h frontend/ir/abstract_syntax_list.h diff --git a/src/shader_recompiler/backend/glasm/emit_context.cpp b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp similarity index 100% rename from src/shader_recompiler/backend/glasm/emit_context.cpp rename to src/shader_recompiler/backend/glasm/glasm_emit_context.cpp diff --git a/src/shader_recompiler/backend/glasm/emit_context.h b/src/shader_recompiler/backend/glasm/glasm_emit_context.h similarity index 100% rename from src/shader_recompiler/backend/glasm/emit_context.h rename to src/shader_recompiler/backend/glasm/glasm_emit_context.h diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp similarity index 100% rename from src/shader_recompiler/backend/glsl/emit_context.cpp rename to src/shader_recompiler/backend/glsl/glsl_emit_context.cpp diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h similarity index 100% rename from src/shader_recompiler/backend/glsl/emit_context.h rename to src/shader_recompiler/backend/glsl/glsl_emit_context.h diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp similarity index 100% rename from src/shader_recompiler/backend/spirv/emit_context.cpp rename to src/shader_recompiler/backend/spirv/spirv_emit_context.cpp diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h similarity index 100% rename from src/shader_recompiler/backend/spirv/emit_context.h rename to src/shader_recompiler/backend/spirv/spirv_emit_context.h From b7d80c127f3b4c919887aaed391f88c033f3e7a2 Mon Sep 17 00:00:00 2001 From: itsmeft24 Date: Sun, 5 Dec 2021 16:49:52 -0500 Subject: [PATCH 175/291] Add copyright notice --- src/core/hle/kernel/k_code_memory.cpp | 4 ++++ src/core/hle/kernel/k_code_memory.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 926d1c076..2e436fb4a 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/k_client_port.h" diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index a7f7d749b..3961105a6 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -1,3 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #pragma once #include "core/core.h" From d6ae9c68f80792cf11f13ca2c81ac34ddf01dafa Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 5 Dec 2021 16:17:52 -0600 Subject: [PATCH 176/291] service/hid: Implement SetNpadJoyAssignmentMode --- src/core/hid/hid_core.cpp | 10 ++ src/core/hid/hid_core.h | 3 + src/core/hle/service/hid/controllers/npad.cpp | 165 +++++++++++++++--- src/core/hle/service/hid/controllers/npad.h | 8 +- src/core/hle/service/hid/hid.cpp | 26 +-- 5 files changed, 174 insertions(+), 38 deletions(-) diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 0c3eb5a62..a1c3bbb57 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -145,6 +145,16 @@ NpadIdType HIDCore::GetFirstNpadId() const { return NpadIdType::Player1; } +NpadIdType HIDCore::GetFirstDisconnectedNpadId() const { + for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) { + const auto* const controller = GetEmulatedControllerByIndex(player_index); + if (!controller->IsConnected()) { + return controller->GetNpadIdType(); + } + } + return NpadIdType::Player1; +} + void HIDCore::EnableAllControllerConfiguration() { player_1->EnableConfiguration(); player_2->EnableConfiguration(); diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 2fb0f7e19..837f7de49 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -45,6 +45,9 @@ public: /// Returns the first connected npad id NpadIdType GetFirstNpadId() const; + /// Returns the first disconnected npad id + NpadIdType GetFirstDisconnectedNpadId() const; + /// Sets all emulated controllers into configuring mode. void EnableAllControllerConfiguration(); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ae56f10cf..2705e9dcb 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -110,7 +110,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, UpdateControllerAt(npad_type, npad_id, is_connected); break; case Core::HID::ControllerTriggerType::Battery: { - if (!controller.is_connected) { + if (!controller.device->IsConnected()) { return; } auto& shared_memory = controller.shared_memory_entry; @@ -150,7 +150,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; break; case Core::HID::NpadStyleIndex::Handheld: @@ -166,21 +165,30 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { break; case Core::HID::NpadStyleIndex::JoyconDual: shared_memory.style_tag.joycon_dual.Assign(1); - shared_memory.device_type.joycon_left.Assign(1); - shared_memory.device_type.joycon_right.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); + if (controller.is_dual_left_connected) { + shared_memory.device_type.joycon_left.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + } + if (controller.is_dual_right_connected) { + shared_memory.device_type.joycon_right.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + } shared_memory.system_properties.use_directional_buttons.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; + if (controller.is_dual_left_connected && controller.is_dual_right_connected) { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; + } else if (controller.is_dual_left_connected) { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; + } else { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; + } break; case Core::HID::NpadStyleIndex::JoyconLeft: shared_memory.style_tag.joycon_left.Assign(1); shared_memory.device_type.joycon_left.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; break; case Core::HID::NpadStyleIndex::JoyconRight: @@ -188,7 +196,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.device_type.joycon_right.Assign(1); shared_memory.system_properties.is_horizontal.Assign(1); shared_memory.system_properties.use_plus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; break; case Core::HID::NpadStyleIndex::GameCube: @@ -200,7 +207,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { case Core::HID::NpadStyleIndex::Pokeball: shared_memory.style_tag.palma.Assign(1); shared_memory.device_type.palma.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; break; case Core::HID::NpadStyleIndex::NES: shared_memory.style_tag.lark.Assign(1); @@ -443,11 +449,15 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* case Core::HID::NpadStyleIndex::JoyconDual: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); + if (controller.is_dual_left_connected) { + pad_state.connection_status.is_left_connected.Assign(1); + libnx_state.connection_status.is_left_connected.Assign(1); + } + if (controller.is_dual_right_connected) { + pad_state.connection_status.is_right_connected.Assign(1); + libnx_state.connection_status.is_right_connected.Assign(1); + } - libnx_state.connection_status.is_left_connected.Assign(1); - libnx_state.connection_status.is_right_connected.Assign(1); pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.joy_dual_lifo.WriteNextEntry(pad_state); @@ -687,7 +697,7 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, +void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); @@ -698,6 +708,62 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, if (controller.shared_memory_entry.assignment_mode != assignment_mode) { controller.shared_memory_entry.assignment_mode = assignment_mode; } + + if (!controller.device->IsConnected()) { + return; + } + + if (assignment_mode == NpadJoyAssignmentMode::Dual) { + if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { + DisconnectNpad(npad_id); + controller.is_dual_left_connected = true; + controller.is_dual_right_connected = false; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); + return; + } + if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { + DisconnectNpad(npad_id); + controller.is_dual_left_connected = false; + controller.is_dual_right_connected = true; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); + return; + } + return; + } + + // This is for NpadJoyAssignmentMode::Single + + // Only JoyconDual get affected by this function + if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { + return; + } + + if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { + DisconnectNpad(npad_id); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); + return; + } + if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { + DisconnectNpad(npad_id); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); + return; + } + + // We have two controllers connected to the same npad_id we need to split them + const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId(); + auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); + DisconnectNpad(npad_id); + if (npad_device_type == NpadJoyDeviceType::Left) { + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); + controller_2.is_dual_left_connected = false; + controller_2.is_dual_right_connected = true; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); + } else { + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); + controller_2.is_dual_left_connected = true; + controller_2.is_dual_right_connected = false; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); + } } bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, @@ -907,6 +973,7 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { } auto& shared_memory_entry = controller.shared_memory_entry; + // Don't reset shared_memory_entry.assignment_mode this value is persistent shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out shared_memory_entry.device_type.raw = 0; shared_memory_entry.system_properties.raw = 0; @@ -923,9 +990,10 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { .left = {}, .right = {}, }; - shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory_entry.applet_footer.type = AppletFooterUiType::None; + controller.is_dual_left_connected = true; + controller.is_dual_right_connected = true; controller.is_connected = false; controller.device->Disconnect(); SignalStyleSetChangedEvent(npad_id); @@ -1022,19 +1090,70 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, npad_id_2); return; } - auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; - auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; + auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); + auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); + const auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); + const auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); + bool merge_controllers = false; // If the controllers at both npad indices form a pair of left and right joycons, merge them. // Otherwise, do nothing. - if ((controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) || - (controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) { + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight && + controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && + !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && + controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && + !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected && + !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected && + controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { + merge_controllers = true; + } + + if (merge_controllers) { // Disconnect the joycon at the second id and connect the dual joycon at the first index. DisconnectNpad(npad_id_2); + controller_1.is_dual_left_connected = true; + controller_1.is_dual_right_connected = true; AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); + return; } + LOG_WARNING(Service_HID, + "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, " + "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}", + npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(), + controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected, + controller_1.is_dual_right_connected, controller_2.is_dual_left_connected, + controller_2.is_dual_right_connected); } void Controller_NPad::StartLRAssignmentMode() { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index de5fa5a64..63281cb35 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -113,7 +113,8 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode); + void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, + NpadJoyAssignmentMode assignment_mode); bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, const Core::HID::VibrationValue& vibration_value); @@ -464,7 +465,10 @@ private: std::array vibration{}; bool unintended_home_button_input_protection{}; bool is_connected{}; - Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; + + // Dual joycons can have only one side connected + bool is_dual_left_connected{true}; + bool is_dual_right_connected{true}; // Motion parameters bool sixaxis_at_rest{true}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index b36689552..ea5b2680d 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -975,35 +975,35 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, + Controller_NPad::NpadJoyAssignmentMode::Single); - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - parameters.npad_id, parameters.applet_resource_user_id); + 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(Kernel::HLERequestContext& ctx) { - // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault IPC::RequestParser rp{ctx}; struct Parameters { Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - u64 npad_joy_device_type; + Controller_NPad::NpadJoyDeviceType npad_joy_device_type; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); + .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, + Controller_NPad::NpadJoyAssignmentMode::Single); - LOG_WARNING(Service_HID, - "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", - parameters.npad_id, parameters.applet_resource_user_id, - parameters.npad_joy_device_type); + 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); @@ -1021,10 +1021,10 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual); + .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - parameters.npad_id, parameters.applet_resource_user_id); + 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); From f32b2bcd200097659d7c6e0dfdef1e96e3f2f69e Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:42:03 -0500 Subject: [PATCH 177/291] shader_recompiler: Adjust emit_context includes --- src/shader_recompiler/backend/glasm/emit_glasm.cpp | 2 +- .../backend/glasm/emit_glasm_bitwise_conversion.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp | 2 +- .../backend/glasm/emit_glasm_context_get_set.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp | 2 +- .../backend/glasm/emit_glasm_floating_point.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_image.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp | 2 +- .../backend/glasm/emit_glasm_not_implemented.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_select.cpp | 2 +- .../backend/glasm/emit_glasm_shared_memory.cpp | 2 +- src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp | 2 +- src/shader_recompiler/backend/glasm/glasm_emit_context.cpp | 2 +- src/shader_recompiler/backend/glasm/reg_alloc.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp | 2 +- .../backend/glsl/emit_glsl_bitwise_conversion.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp | 2 +- .../backend/glsl/emit_glsl_context_get_set.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_image.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp | 2 +- .../backend/glsl/emit_glsl_not_implemented.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_select.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_special.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp | 2 +- src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp | 2 +- src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | 2 +- src/shader_recompiler/backend/spirv/emit_spirv.h | 2 +- src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 004658546..42eff443f 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp @@ -9,9 +9,9 @@ #include "common/div_ceil.h" #include "common/settings.h" #include "shader_recompiler/backend/bindings.h" -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/ir_emitter.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp index 9201ccd39..3bfcbbe65 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLASM { diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp index bff0b7c1c..babbe6654 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLASM { diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 02c9dc6d7..1b98e5b6c 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" #include "shader_recompiler/shader_info.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp index ccdf1cbc8..4cff70fe4 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp index 4ed58619d..356640471 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp index d325d31c7..237a5af3f 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp index 8aa494a4d..f698b8b9b 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLASM { diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp index af9fac7c1..f135b67f5 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/runtime_info.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp index 681aeda8d..b6a2161aa 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp index 68fff613c..dc441c56d 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp @@ -3,8 +3,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLASM { diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp index c1498f449..39e1c6c3a 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp @@ -3,8 +3,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLASM { diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp index 544d475b4..32e0dd923 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp index 8fd459dfe..0401953f7 100644 --- a/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp +++ b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp @@ -5,8 +5,8 @@ #include #include "shader_recompiler/backend/bindings.h" -#include "shader_recompiler/backend/glasm/emit_context.h" #include "shader_recompiler/backend/glasm/emit_glasm.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/profile.h" #include "shader_recompiler/runtime_info.h" diff --git a/src/shader_recompiler/backend/glasm/reg_alloc.cpp b/src/shader_recompiler/backend/glasm/reg_alloc.cpp index 4c046db6e..201e428c1 100644 --- a/src/shader_recompiler/backend/glasm/reg_alloc.cpp +++ b/src/shader_recompiler/backend/glasm/reg_alloc.cpp @@ -6,7 +6,7 @@ #include -#include "shader_recompiler/backend/glasm/emit_context.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/backend/glasm/reg_alloc.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp index 8a430d573..78b2eeaa2 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp @@ -9,9 +9,9 @@ #include "common/div_ceil.h" #include "common/settings.h" -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/ir_emitter.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp index 772acc5a4..dc377b053 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp index e1d1b558e..8a9faa394 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp index 3c1714e89..0f2668d9e 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp index 49a66e3ec..98cc57e58 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index 4c26f3829..1920047f4 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" #include "shader_recompiler/runtime_info.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp index 53f8896be..c86465e8b 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/exception.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp index eeae6562c..ce6ea1bb7 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp index d423bfb1b..b765a251b 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" #include "shader_recompiler/frontend/ir/value.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp index 2f78d0267..fae2e397a 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp index 88c1d4c5e..44060df33 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp index 338ff4bd6..742fec9cf 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp index e3957491f..9fd41b4fd 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp index f420fe388..4ebdfb3bc 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #ifdef _MSC_VER diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp index 49fba9073..b1e486e5f 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp index 518b78f06..74ae345e5 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp index 67f9dad68..b8ddafe48 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp index 15bf02dd6..cace1db85 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" namespace Shader::Backend::GLSL { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp index cd285e2c8..6e01979b4 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp @@ -4,8 +4,8 @@ #include -#include "shader_recompiler/backend/glsl/emit_context.h" #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 97bd59302..1de017e76 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include "shader_recompiler/backend/bindings.h" -#include "shader_recompiler/backend/glsl/emit_context.h" +#include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/profile.h" #include "shader_recompiler/runtime_info.h" diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 4b25534ce..63dea090d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h @@ -10,7 +10,7 @@ #include "common/common_types.h" #include "shader_recompiler/backend/bindings.h" -#include "shader_recompiler/backend/spirv/emit_context.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/profile.h" diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 723455462..4b6f792bf 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -13,8 +13,8 @@ #include "common/common_types.h" #include "common/div_ceil.h" -#include "shader_recompiler/backend/spirv/emit_context.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { From 1e1f7b32341f6538fce07d0df415a4d494a2b209 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:58:18 -0500 Subject: [PATCH 178/291] glasm: Move implemented instructions from not_implemented.cpp --- .../backend/glasm/emit_glasm_barriers.cpp | 22 +++ .../glasm/emit_glasm_context_get_set.cpp | 29 +++ .../backend/glasm/emit_glasm_control_flow.cpp | 18 ++ .../backend/glasm/emit_glasm_logical.cpp | 26 +++ .../glasm/emit_glasm_not_implemented.cpp | 169 ------------------ .../backend/glasm/emit_glasm_special.cpp | 95 ++++++++++ .../backend/glasm/emit_glasm_undefined.cpp | 30 ++++ 7 files changed, 220 insertions(+), 169 deletions(-) diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp index e69de29bb..c0b97683e 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp @@ -0,0 +1,22 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" + +namespace Shader::Backend::GLASM { + +void EmitBarrier(EmitContext& ctx) { + ctx.Add("BAR;"); +} + +void EmitWorkgroupMemoryBarrier(EmitContext& ctx) { + ctx.Add("MEMBAR.CTA;"); +} + +void EmitDeviceMemoryBarrier(EmitContext& ctx) { + ctx.Add("MEMBAR;"); +} + +} // namespace Shader::Backend::GLASM diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 1b98e5b6c..081b2c8e0 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp @@ -335,6 +335,35 @@ void EmitSetFragDepth(EmitContext& ctx, ScalarF32 value) { ctx.Add("MOV.F result.depth.z,{};", value); } +void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {},invocation.groupid;", inst); +} + +void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {},invocation.localid;", inst); +} + +void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); +} + +void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); +} + +void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst); +} + +void EmitYDirection(EmitContext& ctx, IR::Inst& inst) { + ctx.uses_y_direction = true; + ctx.Add("MOV.F {}.x,y_direction[0].w;", inst); +} + +void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.F {}.x,scaling[0].z;", inst); +} + void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) { ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset); } diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp index e69de29bb..8a14fc8d9 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp @@ -0,0 +1,18 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" + +namespace Shader::Backend::GLASM { + +void EmitJoin(EmitContext&) { + throw NotImplementedException("Join shouldn't be emitted"); +} + +void EmitDemoteToHelperInvocation(EmitContext& ctx) { + ctx.Add("KIL TR.x;"); +} + +} // namespace Shader::Backend::GLASM diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp index e69de29bb..eed7bfec2 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp @@ -0,0 +1,26 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" + +namespace Shader::Backend::GLASM { + +void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { + ctx.Add("OR.S {},{},{};", inst, a, b); +} + +void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { + ctx.Add("AND.S {},{},{};", inst, a, b); +} + +void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { + ctx.Add("XOR.S {},{},{};", inst, a, b); +} + +void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) { + ctx.Add("SEQ.S {},{},0;", inst, value); +} + +} // namespace Shader::Backend::GLASM diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp index b6a2161aa..86287ee3f 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp @@ -17,110 +17,6 @@ namespace Shader::Backend::GLASM { #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) -static void DefinePhi(EmitContext& ctx, IR::Inst& phi) { - switch (phi.Type()) { - case IR::Type::U1: - case IR::Type::U32: - case IR::Type::F32: - ctx.reg_alloc.Define(phi); - break; - case IR::Type::U64: - case IR::Type::F64: - ctx.reg_alloc.LongDefine(phi); - break; - default: - throw NotImplementedException("Phi node type {}", phi.Type()); - } -} - -void EmitPhi(EmitContext& ctx, IR::Inst& phi) { - const size_t num_args{phi.NumArgs()}; - for (size_t i = 0; i < num_args; ++i) { - ctx.reg_alloc.Consume(phi.Arg(i)); - } - if (!phi.Definition().is_valid) { - // The phi node wasn't forward defined - DefinePhi(ctx, phi); - } -} - -void EmitVoid(EmitContext&) {} - -void EmitReference(EmitContext& ctx, const IR::Value& value) { - ctx.reg_alloc.Consume(value); -} - -void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) { - IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())}; - if (!phi.Definition().is_valid) { - // The phi node wasn't forward defined - DefinePhi(ctx, phi); - } - const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})}; - const Value eval_value{ctx.reg_alloc.Consume(value)}; - - if (phi_reg == eval_value) { - return; - } - switch (phi.Flags()) { - case IR::Type::U1: - case IR::Type::U32: - case IR::Type::F32: - ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value}); - break; - case IR::Type::U64: - case IR::Type::F64: - ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value}); - break; - default: - throw NotImplementedException("Phi node type {}", phi.Type()); - } -} - -void EmitJoin(EmitContext& ctx) { - NotImplemented(); -} - -void EmitDemoteToHelperInvocation(EmitContext& ctx) { - ctx.Add("KIL TR.x;"); -} - -void EmitBarrier(EmitContext& ctx) { - ctx.Add("BAR;"); -} - -void EmitWorkgroupMemoryBarrier(EmitContext& ctx) { - ctx.Add("MEMBAR.CTA;"); -} - -void EmitDeviceMemoryBarrier(EmitContext& ctx) { - ctx.Add("MEMBAR;"); -} - -void EmitPrologue(EmitContext& ctx) { - // TODO -} - -void EmitEpilogue(EmitContext& ctx) { - // TODO -} - -void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) { - if (stream.type == Type::U32 && stream.imm_u32 == 0) { - ctx.Add("EMIT;"); - } else { - ctx.Add("EMITS {};", stream); - } -} - -void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { - if (!stream.IsImmediate()) { - LOG_WARNING(Shader_GLASM, "Stream is not immediate"); - } - ctx.reg_alloc.Consume(stream); - ctx.Add("ENDPRIM;"); -} - void EmitGetRegister(EmitContext& ctx) { NotImplemented(); } @@ -185,55 +81,6 @@ void EmitSetOFlag(EmitContext& ctx) { NotImplemented(); } -void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {},invocation.groupid;", inst); -} - -void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {},invocation.localid;", inst); -} - -void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); -} - -void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); -} - -void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst); -} - -void EmitYDirection(EmitContext& ctx, IR::Inst& inst) { - ctx.uses_y_direction = true; - ctx.Add("MOV.F {}.x,y_direction[0].w;", inst); -} - -void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.F {}.x,scaling[0].z;", inst); -} - -void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,0;", inst); -} - -void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,0;", inst); -} - -void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,0;", inst); -} - -void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) { - ctx.Add("MOV.S {}.x,0;", inst); -} - -void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) { - ctx.LongAdd("MOV.S64 {}.x,0;", inst); -} - void EmitGetZeroFromOp(EmitContext& ctx) { NotImplemented(); } @@ -258,20 +105,4 @@ void EmitGetInBoundsFromOp(EmitContext& ctx) { NotImplemented(); } -void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { - ctx.Add("OR.S {},{},{};", inst, a, b); -} - -void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { - ctx.Add("AND.S {},{},{};", inst, a, b); -} - -void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { - ctx.Add("XOR.S {},{},{};", inst, a, b); -} - -void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) { - ctx.Add("SEQ.S {},{},0;", inst, value); -} - } // namespace Shader::Backend::GLASM diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp index e69de29bb..e7a5fb13a 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp @@ -0,0 +1,95 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" +#include "shader_recompiler/frontend/ir/value.h" + +namespace Shader::Backend::GLASM { + +static void DefinePhi(EmitContext& ctx, IR::Inst& phi) { + switch (phi.Type()) { + case IR::Type::U1: + case IR::Type::U32: + case IR::Type::F32: + ctx.reg_alloc.Define(phi); + break; + case IR::Type::U64: + case IR::Type::F64: + ctx.reg_alloc.LongDefine(phi); + break; + default: + throw NotImplementedException("Phi node type {}", phi.Type()); + } +} + +void EmitPhi(EmitContext& ctx, IR::Inst& phi) { + const size_t num_args{phi.NumArgs()}; + for (size_t i = 0; i < num_args; ++i) { + ctx.reg_alloc.Consume(phi.Arg(i)); + } + if (!phi.Definition().is_valid) { + // The phi node wasn't forward defined + DefinePhi(ctx, phi); + } +} + +void EmitVoid(EmitContext&) {} + +void EmitReference(EmitContext& ctx, const IR::Value& value) { + ctx.reg_alloc.Consume(value); +} + +void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) { + IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())}; + if (!phi.Definition().is_valid) { + // The phi node wasn't forward defined + DefinePhi(ctx, phi); + } + const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})}; + const Value eval_value{ctx.reg_alloc.Consume(value)}; + + if (phi_reg == eval_value) { + return; + } + switch (phi.Flags()) { + case IR::Type::U1: + case IR::Type::U32: + case IR::Type::F32: + ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value}); + break; + case IR::Type::U64: + case IR::Type::F64: + ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value}); + break; + default: + throw NotImplementedException("Phi node type {}", phi.Type()); + } +} + +void EmitPrologue(EmitContext&) { + // TODO +} + +void EmitEpilogue(EmitContext&) { + // TODO +} + +void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) { + if (stream.type == Type::U32 && stream.imm_u32 == 0) { + ctx.Add("EMIT;"); + } else { + ctx.Add("EMITS {};", stream); + } +} + +void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { + if (!stream.IsImmediate()) { + LOG_WARNING(Shader_GLASM, "Stream is not immediate"); + } + ctx.reg_alloc.Consume(stream); + ctx.Add("ENDPRIM;"); +} + +} // namespace Shader::Backend::GLASM diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp index e69de29bb..875e9d991 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp @@ -0,0 +1,30 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" +#include "shader_recompiler/backend/glasm/glasm_emit_context.h" + +namespace Shader::Backend::GLASM { + +void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,0;", inst); +} + +void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,0;", inst); +} + +void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,0;", inst); +} + +void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) { + ctx.Add("MOV.S {}.x,0;", inst); +} + +void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) { + ctx.LongAdd("MOV.S64 {}.x,0;", inst); +} + +} // namespace Shader::Backend::GLASM From 7105204a7ed0ac45701e57ff157c9e0c679c5ce9 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 5 Dec 2021 17:24:54 -0500 Subject: [PATCH 179/291] emit_spirv: Reduce emit_spirv.h include overhead emit_spirv.h is included in video_core, which was propagating further includes that video_core did not depend on. --- src/shader_recompiler/backend/spirv/emit_spirv.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv.h | 4 +--- src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp | 1 + .../backend/spirv/emit_spirv_bitwise_conversion.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp | 1 + .../backend/spirv/emit_spirv_context_get_set.cpp | 1 + .../backend/spirv/emit_spirv_control_flow.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp | 1 + .../backend/spirv/emit_spirv_floating_point.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | 1 + .../backend/spirv/emit_spirv_image_atomic.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_select.cpp | 1 + .../backend/spirv/emit_spirv_shared_memory.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_special.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp | 1 + src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp | 1 + 20 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index d7a86e270..6ce7ed12a 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -11,6 +11,7 @@ #include "common/settings.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/program.h" diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 63dea090d..b412957c7 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h @@ -6,13 +6,11 @@ #include -#include - #include "common/common_types.h" #include "shader_recompiler/backend/bindings.h" -#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/program.h" #include "shader_recompiler/profile.h" +#include "shader_recompiler/runtime_info.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 9af8bb9e1..0d37b405c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp index e0b52a001..9ce95a41b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp index bb11f4f4e..02d1e63f7 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp index 10ff4ecab..5c3e1ee2b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" namespace Shader::Backend::SPIRV { 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 bac683ae1..ad84966b5 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 @@ -7,6 +7,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp index d33486f28..1eca3aa85 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp index fd42b7a16..832de2452 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp index 61cf25f9c..0cdc46495 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 4d168a96d..d18d5f1d5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp @@ -6,6 +6,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp index d7f1a365a..a96190bc6 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/frontend/ir/modifiers.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index 50277eec3..44521f539 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp index b9a9500fc..47745f7ee 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp index 679ee2684..175f4be19 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp @@ -6,6 +6,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp index c5b4f4720..48caf1ffc 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp index 9a79fc7a2..330c9052c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 9e7eb3cb1..d96a17583 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp index c9f469e90..b5766fc52 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index cef52c56e..7034228bf 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp @@ -4,6 +4,7 @@ #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" +#include "shader_recompiler/backend/spirv/spirv_emit_context.h" namespace Shader::Backend::SPIRV { namespace { From 8254f238b9e71c0292bc6456afb92086113b12ac Mon Sep 17 00:00:00 2001 From: itsmeft24 Date: Sun, 5 Dec 2021 18:49:40 -0500 Subject: [PATCH 180/291] Remove unnecessary includes --- src/core/hle/kernel/k_code_memory.cpp | 31 ++++++-------------------- src/core/hle/kernel/k_code_memory.h | 32 +++++---------------------- 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 2e436fb4a..9264faf4e 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -2,36 +2,19 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_client_session.h" +#include "common/common_types.h" +#include "core/device_memory.h" +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_code_memory.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/kernel/k_writable_event.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/svc.h" -#include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" -#include "core/hle/kernel/svc_wrap.h" -#include "core/hle/lock.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" -#include "core/memory.h" -#include "core/reporter.h" + namespace Kernel { KCodeMemory::KCodeMemory(KernelCore& kernel_) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 3961105a6..da60ece67 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -4,35 +4,15 @@ #pragma once -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_client_session.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_handle_table.h" -#include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/k_memory_layout.h" -#include "core/hle/kernel/k_page_table.h" +#include "common/common_types.h" +#include "core/device_memory.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/kernel/k_writable_event.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/svc.h" -#include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" -#include "core/hle/kernel/svc_wrap.h" -#include "core/hle/lock.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" -#include "core/memory.h" -#include "core/reporter.h" namespace Kernel { From 14c03b97483bb394e210972ed30f105b9994cd04 Mon Sep 17 00:00:00 2001 From: itsmeft24 Date: Sun, 5 Dec 2021 19:00:29 -0500 Subject: [PATCH 181/291] fix formatting --- src/core/hle/kernel/k_code_memory.cpp | 2 +- src/core/hle/kernel/k_code_memory.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 9264faf4e..d69f7ffb7 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -11,8 +11,8 @@ #include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/slab_helpers.h" +#include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" namespace Kernel { diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index da60ece67..9166d98b5 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -10,8 +10,8 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/slab_helpers.h" +#include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" namespace Kernel { From 29559930e95cfc8ed5ee523fd7f61c5309280ebf Mon Sep 17 00:00:00 2001 From: jam1garner <8260240+jam1garner@users.noreply.github.com> Date: Sun, 5 Dec 2021 23:07:50 -0500 Subject: [PATCH 182/291] loader: Support loading subsdk{8,9} --- src/core/loader/deconstructed_rom_directory.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 1b5aca65d..b47e3bf69 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -125,8 +125,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect } metadata.Print(); - const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", - "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}; + const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", + "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", + "subsdk8", "subsdk9", "sdk"}; // Use the NSO module loader to figure out the code layout std::size_t code_size{}; From 189741b521e569a7087deee9f92ac66ab4f6f154 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 5 Dec 2021 22:41:21 -0600 Subject: [PATCH 183/291] service/hid: Stub SetNpadCaptureButtonAssignment and ClearNpadCaptureButtonAssignment Used by ring fit adventure 1.2.0 --- src/core/hle/service/hid/hid.cpp | 35 ++++++++++++++++++++++++++++++-- src/core/hle/service/hid/hid.h | 2 ++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index b36689552..14f737d39 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -293,8 +293,8 @@ Hid::Hid(Core::System& system_) {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, - {135, nullptr, "SetNpadCaptureButtonAssignment"}, - {136, nullptr, "ClearNpadCaptureButtonAssignment"}, + {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, + {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, {201, &Hid::SendVibrationValue, "SendVibrationValue"}, {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, @@ -1186,6 +1186,37 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Hid::SetNpadCaptureButtonAssignment(Kernel::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()}; + + 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(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop()}; + + 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(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw()}; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index ab0084118..d290df161 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -136,6 +136,8 @@ private: void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx); + void SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); + void ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); void SendVibrationValue(Kernel::HLERequestContext& ctx); void GetActualVibrationValue(Kernel::HLERequestContext& ctx); From 6d25fe6c9aa829fa12c7a7304c81b3f61de3b9b7 Mon Sep 17 00:00:00 2001 From: Void48 <85196642+Void48@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:39:55 +0100 Subject: [PATCH 184/291] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cb030aed..c09d49ca4 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f alt="Azure Mainline CI Build Status"> - Discord

From 32854a299223c7fff759bb779adda0022c632bd3 Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Mon, 6 Dec 2021 07:58:28 -0500 Subject: [PATCH 185/291] fix formatting Co-authored-by: Mai M. --- src/core/hle/kernel/k_code_memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 9166d98b5..91ffafa89 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -16,7 +16,7 @@ namespace Kernel { -enum class CodeMemoryOperation : u32 { Map = 0, MapToOwner = 1, Unmap = 2, UnmapFromOwner = 3 }; +enum class CodeMemoryOperation : u32 { Map = 0, MapToOwner = 1, Unmap = 2, UnmapFromOwner = 3, }; class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer { From 4bdacdedc1d4ccb633d7427999b552382f99863c Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Mon, 6 Dec 2021 10:37:09 -0500 Subject: [PATCH 186/291] fix formatting --- src/core/hle/kernel/k_page_table.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 47f529fcd..99982e5a3 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -970,7 +970,6 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) } ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; @@ -998,7 +997,6 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { } ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; KMemoryPermission new_perm = KMemoryPermission::UserReadWrite; @@ -1318,7 +1316,6 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm, KMemoryAttribute attr_mask, KMemoryAttribute attr) const { - // Get information about the first block. const VAddr last_addr = addr + size - 1; KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; @@ -1353,4 +1350,4 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s return ResultSuccess; } -} // namespace Kernel \ No newline at end of file +} // namespace Kernel From e10903cab928e3cbc9d554a6c388434fbaa2f1db Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Mon, 6 Dec 2021 10:37:13 -0500 Subject: [PATCH 187/291] move private members below public members --- src/core/hle/kernel/k_code_memory.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 91ffafa89..7408b775d 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -22,15 +22,6 @@ class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer { KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); -private: - KPageLinkedList m_page_group; - KProcess* m_owner; - VAddr m_address; - KLightLock m_lock; - bool m_is_initialized; - bool m_is_owner_mapped; - bool m_is_mapped; - public: explicit KCodeMemory(KernelCore& kernel_); @@ -56,5 +47,15 @@ public: size_t GetSize() const { return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; } + +private: + KPageLinkedList m_page_group; + KProcess* m_owner; + VAddr m_address; + KLightLock m_lock; + bool m_is_initialized; + bool m_is_owner_mapped; + bool m_is_mapped; }; -} // namespace Kernel \ No newline at end of file + +} // namespace Kernel From 8ed2748820d6b991ae2da4e97c98a2f8637fc331 Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:02:33 -0500 Subject: [PATCH 188/291] fix formatting --- src/core/hle/kernel/k_code_memory.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 7408b775d..e8e83a0e5 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -16,7 +16,12 @@ namespace Kernel { -enum class CodeMemoryOperation : u32 { Map = 0, MapToOwner = 1, Unmap = 2, UnmapFromOwner = 3, }; +enum class CodeMemoryOperation : u32 { + Map = 0, + MapToOwner = 1, + Unmap = 2, + UnmapFromOwner = 3, +}; class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer { From ac1bfe228f688bb8eef38bdaf26011008891afdf Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 5 Dec 2021 22:55:23 -0600 Subject: [PATCH 189/291] service/notif: Add notif:a and stub ListAlarmSettings,Initialize Used by ring fit adventure 1.2.0 --- src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + src/core/CMakeLists.txt | 2 ++ src/core/hle/service/glue/glue.cpp | 4 +++ src/core/hle/service/glue/notif.cpp | 44 +++++++++++++++++++++++++++++ src/core/hle/service/glue/notif.h | 25 ++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 src/core/hle/service/glue/notif.cpp create mode 100644 src/core/hle/service/glue/notif.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 42744c994..b898a652c 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Service, NGCT) \ SUB(Service, NIFM) \ SUB(Service, NIM) \ + SUB(Service, NOTIF) \ SUB(Service, NPNS) \ SUB(Service, NS) \ SUB(Service, NVDRV) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 2d21fc483..9ed0c7ad6 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -82,6 +82,7 @@ enum class Class : u8 { Service_NGCT, ///< The NGCT (No Good Content for Terra) service Service_NIFM, ///< The NIFM (Network interface) service Service_NIM, ///< The NIM service + Service_NOTIF, ///< The NOTIF (Notification) service Service_NPNS, ///< The NPNS service Service_NS, ///< The NS services Service_NVDRV, ///< The NVDRV (Nvidia driver) service diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eee8e2ccd..721685bb7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -408,6 +408,8 @@ add_library(core STATIC hle/service/glue/glue.h hle/service/glue/glue_manager.cpp hle/service/glue/glue_manager.h + hle/service/glue/notif.cpp + hle/service/glue/notif.h hle/service/grc/grc.cpp hle/service/grc/grc.h hle/service/hid/hid.cpp diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index a08dc9758..b24d469cf 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp @@ -8,6 +8,7 @@ #include "core/hle/service/glue/bgtc.h" #include "core/hle/service/glue/ectx.h" #include "core/hle/service/glue/glue.h" +#include "core/hle/service/glue/notif.h" namespace Service::Glue { @@ -24,6 +25,9 @@ void InstallInterfaces(Core::System& system) { // Error Context std::make_shared(system)->InstallAsService(system.ServiceManager()); + + // Notification Services for application + std::make_shared(system)->InstallAsService(system.ServiceManager()); } } // namespace Service::Glue diff --git a/src/core/hle/service/glue/notif.cpp b/src/core/hle/service/glue/notif.cpp new file mode 100644 index 000000000..c559ec9df --- /dev/null +++ b/src/core/hle/service/glue/notif.cpp @@ -0,0 +1,44 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/glue/notif.h" + +namespace Service::Glue { + +NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { + // clang-format off + static const FunctionInfo functions[] = { + {500, nullptr, "RegisterAlarmSetting"}, + {510, nullptr, "UpdateAlarmSetting"}, + {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"}, + {530, nullptr, "LoadApplicationParameter"}, + {540, nullptr, "DeleteAlarmSetting"}, + {1000, &NOTIF_A::Initialize, "Initialize"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +NOTIF_A::~NOTIF_A() = default; + +void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) { + // Returns an array of AlarmSetting + constexpr s32 alarm_count = 0; + + LOG_WARNING(Service_NOTIF, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(alarm_count); +} + +void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NOTIF, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::Glue diff --git a/src/core/hle/service/glue/notif.h b/src/core/hle/service/glue/notif.h new file mode 100644 index 000000000..6ecf2015c --- /dev/null +++ b/src/core/hle/service/glue/notif.h @@ -0,0 +1,25 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::Glue { + +class NOTIF_A final : public ServiceFramework { +public: + explicit NOTIF_A(Core::System& system_); + ~NOTIF_A() override; + +private: + void ListAlarmSettings(Kernel::HLERequestContext& ctx); + void Initialize(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::Glue From f4587c596feb022fe2e681bb7f2b8283b4f72a37 Mon Sep 17 00:00:00 2001 From: Andrea Pappacoda Date: Mon, 6 Dec 2021 18:56:43 +0100 Subject: [PATCH 190/291] build: update cubeb and remove the result_of comment Cubeb doesn't use result_of anymore, it has been dropped in commit mozilla/cubeb@75d9d125ee655ef80f3bfcd97ae5a805931042b8 --- CMakeLists.txt | 2 +- externals/cubeb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61510cc0f..bb858dda3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) if (MSVC) add_compile_options($<$:/std:c++latest>) - # cubeb and boost still make use of deprecated result_of. + # boost still makes use of deprecated result_of. add_definitions(-D_HAS_DEPRECATED_RESULT_OF) else() set(CMAKE_CXX_STANDARD 20) diff --git a/externals/cubeb b/externals/cubeb index 1d66483ad..75d9d125e 160000 --- a/externals/cubeb +++ b/externals/cubeb @@ -1 +1 @@ -Subproject commit 1d66483ad2b93f0e00e175f9480c771af90003a7 +Subproject commit 75d9d125ee655ef80f3bfcd97ae5a805931042b8 From 133504b74b73d5d1f29f59a6ca1bc0f2d2f2a037 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Wed, 1 Dec 2021 14:45:00 -0600 Subject: [PATCH 191/291] input_common: Update SDL to 2.0.18 --- CMakeLists.txt | 4 ++-- externals/SDL | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61510cc0f..c834e9396 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -370,7 +370,7 @@ if (ENABLE_SDL2) if (YUZU_USE_BUNDLED_SDL2) # Detect toolchain and platform if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) - set(SDL2_VER "SDL2-2.0.16") + set(SDL2_VER "SDL2-2.0.18") else() message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") endif() @@ -390,7 +390,7 @@ if (ENABLE_SDL2) elseif (YUZU_USE_EXTERNAL_SDL2) message(STATUS "Using SDL2 from externals.") else() - find_package(SDL2 2.0.16 REQUIRED) + find_package(SDL2 2.0.18 REQUIRED) # Some installations don't set SDL2_LIBRARIES if("${SDL2_LIBRARIES}" STREQUAL "") diff --git a/externals/SDL b/externals/SDL index 25f9ed87f..2e9821423 160000 --- a/externals/SDL +++ b/externals/SDL @@ -1 +1 @@ -Subproject commit 25f9ed87ff6947d9576fc9d79dee0784e638ac58 +Subproject commit 2e9821423a237a1206e3c09020778faacfe430be From c61857286d10f6165d2625384dda2b802b8f51a5 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 6 Dec 2021 19:14:29 -0500 Subject: [PATCH 192/291] CMakeLists: Specify /Zm200 when compiling in MSVC This increases the memory heap size for constructing precompiled headers to 2x the default. --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63dd9febf..19d16147d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ if (MSVC) # /W3 - Level 3 warnings # /MP - Multi-threaded compilation # /Zi - Output debugging information + # /Zm - Specifies the precompiled header memory allocation limit # /Zo - Enhanced debug info for optimized builds # /permissive- - Enables stricter C++ standards conformance checks # /EHsc - C++-only exception handling semantics @@ -36,6 +37,7 @@ if (MSVC) add_compile_options( /MP /Zi + /Zm200 /Zo /permissive- /EHsc From 669a2d2c67bd9a3267286bc0c2e6e3c1dc98c154 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 22:45:18 -0700 Subject: [PATCH 193/291] core: hle: kernel: Reflect non-emulated threads as core 3. --- src/core/core.cpp | 6 ------ src/core/core.h | 3 --- src/core/hle/kernel/k_address_arbiter.cpp | 4 ++-- src/core/hle/kernel/k_condition_variable.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 8 ++++++++ src/core/hle/kernel/kernel.h | 3 +++ src/core/hle/kernel/svc.cpp | 5 +++-- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 473ab9f81..aa96f709b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -521,12 +521,6 @@ const ARM_Interface& System::CurrentArmInterface() const { return impl->kernel.CurrentPhysicalCore().ArmInterface(); } -std::size_t System::CurrentCoreIndex() const { - std::size_t core = impl->kernel.GetCurrentHostThreadID(); - ASSERT(core < Core::Hardware::NUM_CPU_CORES); - return core; -} - Kernel::PhysicalCore& System::CurrentPhysicalCore() { return impl->kernel.CurrentPhysicalCore(); } diff --git a/src/core/core.h b/src/core/core.h index 645e5c241..52ff90359 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -208,9 +208,6 @@ public: /// Gets an ARM interface to the CPU core that is currently running [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; - /// Gets the index of the currently running CPU core - [[nodiscard]] std::size_t CurrentCoreIndex() const; - /// Gets the physical core for the CPU core that is currently running [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 1b429bc1e..6771ef621 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -28,7 +28,7 @@ bool ReadFromUser(Core::System& system, s32* out, VAddr address) { bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) { auto& monitor = system.Monitor(); - const auto current_core = system.CurrentCoreIndex(); + const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. // TODO(bunnei): We should call CanAccessAtomic(..) here. @@ -58,7 +58,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) { auto& monitor = system.Monitor(); - const auto current_core = system.CurrentCoreIndex(); + const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. // TODO(bunnei): We should call CanAccessAtomic(..) here. diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 7fa9b8cc3..ed6f328fc 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -33,7 +33,7 @@ bool WriteToUser(Core::System& system, VAddr address, const u32* p) { bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero, u32 new_orr_mask) { auto& monitor = system.Monitor(); - const auto current_core = system.CurrentCoreIndex(); + const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); // Load the value from the address. const auto expected = monitor.ExclusiveRead32(current_core, address); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 45e86a677..04926a291 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -845,6 +845,14 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { return impl->cores[id]; } +size_t KernelCore::CurrentPhysicalCoreIndex() const { + const u32 core_id = impl->GetCurrentHostThreadID(); + if (core_id >= Core::Hardware::NUM_CPU_CORES) { + return Core::Hardware::NUM_CPU_CORES - 1; + } + return core_id; +} + Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { u32 core_id = impl->GetCurrentHostThreadID(); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d2ceae950..3499f8b90 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -148,6 +148,9 @@ public: /// Gets the an instance of the respective physical CPU core. const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + /// Gets the current physical core index for the running host thread. + std::size_t CurrentPhysicalCoreIndex() const; + /// Gets the sole instance of the Scheduler at the current running core. Kernel::KScheduler* CurrentScheduler(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f0cd8471e..e5e879eb5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -873,7 +873,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle const u64 thread_ticks = current_thread->GetCpuTime(); out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); - } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { + } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; } @@ -887,7 +887,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle return ResultInvalidHandle; } - if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) { + if (info_sub_id != 0xFFFFFFFFFFFFFFFF && + info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) { LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); return ResultInvalidCombination; } From 3bd5d4b6f8887ffe302a73e3ad595f58409b5c9e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 22:58:46 -0700 Subject: [PATCH 194/291] core: hle: kernel: Ensure idle threads are closed before destroying scheduler. --- src/core/hle/kernel/k_scheduler.cpp | 6 ++++- src/core/hle/kernel/k_scheduler.h | 2 ++ src/core/hle/kernel/kernel.cpp | 38 ++++++++++++----------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 6a7d80d03..4bae69f71 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -617,13 +617,17 @@ KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, c state.highest_priority_thread = nullptr; } -KScheduler::~KScheduler() { +void KScheduler::Finalize() { if (idle_thread) { idle_thread->Close(); idle_thread = nullptr; } } +KScheduler::~KScheduler() { + ASSERT(!idle_thread); +} + KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { return result; diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 7df288438..82fcd99e7 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -33,6 +33,8 @@ public: explicit KScheduler(Core::System& system_, s32 core_id_); ~KScheduler(); + void Finalize(); + /// Reschedules to the next available thread (call after current thread is suspended) void RescheduleCurrentCore(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 04926a291..275fee0d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -83,8 +83,9 @@ struct KernelCore::Impl { } void InitializeCores() { - for (auto& core : cores) { - core.Initialize(current_process->Is64BitProcess()); + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + cores[core_id].Initialize(current_process->Is64BitProcess()); + system.Memory().SetCurrentPageTable(*current_process, core_id); } } @@ -123,15 +124,6 @@ struct KernelCore::Impl { next_user_process_id = KProcess::ProcessIDMin; next_thread_id = 1; - for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - if (suspend_threads[core_id]) { - suspend_threads[core_id]->Close(); - suspend_threads[core_id] = nullptr; - } - - schedulers[core_id].reset(); - } - cores.clear(); global_handle_table->Finalize(); @@ -159,6 +151,16 @@ struct KernelCore::Impl { CleanupObject(time_shared_mem); CleanupObject(system_resource_limit); + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + if (suspend_threads[core_id]) { + suspend_threads[core_id]->Close(); + suspend_threads[core_id] = nullptr; + } + + schedulers[core_id]->Finalize(); + schedulers[core_id].reset(); + } + // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; @@ -267,14 +269,6 @@ struct KernelCore::Impl { void MakeCurrentProcess(KProcess* process) { current_process = process; - if (process == nullptr) { - return; - } - - const u32 core_id = GetCurrentHostThreadID(); - if (core_id < Core::Hardware::NUM_CPU_CORES) { - system.Memory().SetCurrentPageTable(*process, core_id); - } } static inline thread_local u32 host_thread_id = UINT32_MAX; @@ -1079,13 +1073,11 @@ void KernelCore::ExceptionalExit() { } void KernelCore::EnterSVCProfile() { - std::size_t core = impl->GetCurrentHostThreadID(); - impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); + impl->svc_ticks[CurrentPhysicalCoreIndex()] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); } void KernelCore::ExitSVCProfile() { - std::size_t core = impl->GetCurrentHostThreadID(); - MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); + MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]); } std::weak_ptr KernelCore::CreateServiceThread(const std::string& name) { From 04daefa4887fac9f90d873b5ae4b87548eafb2f0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:04:32 -0700 Subject: [PATCH 195/291] core: hle: kernel: k_thread: Add KScopedDisableDispatch. --- src/core/hle/kernel/k_thread.cpp | 17 ++++++++++++++++- src/core/hle/kernel/k_thread.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index db65ce79a..de94c737d 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -184,7 +184,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s // Setup the stack parameters. StackParameters& sp = GetStackParameters(); sp.cur_thread = this; - sp.disable_count = 1; + sp.disable_count = 0; SetInExceptionHandler(); // Set thread ID. @@ -966,6 +966,9 @@ ResultCode KThread::Run() { // Set our state and finish. SetState(ThreadState::Runnable); + + DisableDispatch(); + return ResultSuccess; } } @@ -1050,4 +1053,16 @@ s32 GetCurrentCoreId(KernelCore& kernel) { return GetCurrentThread(kernel).GetCurrentCore(); } +KScopedDisableDispatch::~KScopedDisableDispatch() { + if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { + auto scheduler = kernel.CurrentScheduler(); + + if (scheduler) { + scheduler->RescheduleCurrentCore(); + } + } else { + GetCurrentThread(kernel).EnableDispatch(); + } +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index c77f44ad4..a149744c8 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -450,16 +450,35 @@ public: sleeping_queue = q; } + [[nodiscard]] bool IsKernelThread() const { + return GetActiveCore() == 3; + } + [[nodiscard]] s32 GetDisableDispatchCount() const { + if (IsKernelThread()) { + // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. + return 1; + } + return this->GetStackParameters().disable_count; } void DisableDispatch() { + if (IsKernelThread()) { + // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. + return; + } + ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0); this->GetStackParameters().disable_count++; } void EnableDispatch() { + if (IsKernelThread()) { + // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. + return; + } + ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0); this->GetStackParameters().disable_count--; } @@ -752,4 +771,16 @@ public: } }; +class KScopedDisableDispatch { +public: + explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { + GetCurrentThread(kernel).DisableDispatch(); + } + + ~KScopedDisableDispatch(); + +private: + KernelCore& kernel; +}; + } // namespace Kernel From 4c18a207a4898f391afab5d7e44c1c2921bc9d6f Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:05:01 -0700 Subject: [PATCH 196/291] core: hle: kernel: k_handle_table: Use KScopedDisableDispatch as necessary. --- src/core/hle/kernel/k_handle_table.cpp | 6 ++++++ src/core/hle/kernel/k_handle_table.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp index e90fc0628..cf95f0852 100644 --- a/src/core/hle/kernel/k_handle_table.cpp +++ b/src/core/hle/kernel/k_handle_table.cpp @@ -13,6 +13,7 @@ ResultCode KHandleTable::Finalize() { // Get the table and clear our record of it. u16 saved_table_size = 0; { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); std::swap(m_table_size, saved_table_size); @@ -43,6 +44,7 @@ bool KHandleTable::Remove(Handle handle) { // Find the object and free the entry. KAutoObject* obj = nullptr; { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); if (this->IsValidHandle(handle)) { @@ -62,6 +64,7 @@ bool KHandleTable::Remove(Handle handle) { } ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); // Never exceed our capacity. @@ -84,6 +87,7 @@ ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { } ResultCode KHandleTable::Reserve(Handle* out_handle) { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); // Never exceed our capacity. @@ -94,6 +98,7 @@ ResultCode KHandleTable::Reserve(Handle* out_handle) { } void KHandleTable::Unreserve(Handle handle) { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); // Unpack the handle. @@ -112,6 +117,7 @@ void KHandleTable::Unreserve(Handle handle) { } void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); // Unpack the handle. diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 95ec905ae..4b114ec2f 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -68,6 +68,7 @@ public: template KScopedAutoObject GetObjectWithoutPseudoHandle(Handle handle) const { // Lock and look up in table. + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); if constexpr (std::is_same_v) { @@ -122,6 +123,7 @@ public: size_t num_opened; { // Lock the table. + KScopedDisableDispatch dd(kernel); KScopedSpinLock lk(m_lock); for (num_opened = 0; num_opened < num_handles; num_opened++) { // Get the current handle. From f13fce3953b376d2321645b4de4d023da0d6713d Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:08:26 -0700 Subject: [PATCH 197/291] core: hle: kernel: k_process: DisableDispatch on main thread. --- src/core/hle/kernel/k_process.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 1aad061e1..7cc2061ea 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -60,6 +60,7 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority thread->GetContext64().cpu_registers[0] = 0; thread->GetContext32().cpu_registers[1] = thread_handle; thread->GetContext64().cpu_registers[1] = thread_handle; + thread->DisableDispatch(); auto& kernel = system.Kernel(); // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires From f412d2027a6e5798fe6fc3b43250bc2f5f1d17fc Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:12:47 -0700 Subject: [PATCH 198/291] core: hle: kernel: k_scheduler: Improve Unload. --- src/core/hle/kernel/k_scheduler.cpp | 46 ++++++++++++++++++----------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 4bae69f71..5ee4b8adc 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -650,6 +650,7 @@ void KScheduler::RescheduleCurrentCore() { if (state.needs_scheduling.load()) { Schedule(); } else { + GetCurrentThread()->EnableDispatch(); guard.Unlock(); } } @@ -659,26 +660,37 @@ void KScheduler::OnThreadStart() { } void KScheduler::Unload(KThread* thread) { + ASSERT(thread); + + if (!thread) { + return; + } + LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); - if (thread) { - if (thread->IsCallingSvc()) { - thread->ClearIsCallingSvc(); - } - if (!thread->IsTerminationRequested()) { - prev_thread = thread; - - Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); - cpu_core.SaveContext(thread->GetContext32()); - cpu_core.SaveContext(thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); - cpu_core.ClearExclusiveState(); - } else { - prev_thread = nullptr; - } - thread->context_guard.Unlock(); + if (thread->IsCallingSvc()) { + thread->ClearIsCallingSvc(); } + + auto& physical_core = system.Kernel().PhysicalCore(core_id); + if (!physical_core.IsInitialized()) { + return; + } + + Core::ARM_Interface& cpu_core = physical_core.ArmInterface(); + cpu_core.SaveContext(thread->GetContext32()); + cpu_core.SaveContext(thread->GetContext64()); + // Save the TPIDR_EL0 system register in case it was modified. + thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + + if (!thread->IsTerminationRequested() && thread->GetActiveCore() == core_id) { + prev_thread = thread; + } else { + prev_thread = nullptr; + } + + thread->context_guard.Unlock(); } void KScheduler::Reload(KThread* thread) { From 13c82d042f10dbaec7fb66764bf4b636e7a2949b Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:16:12 -0700 Subject: [PATCH 199/291] core: hle: kernel: k_scheduler: Improve ScheduleImpl. --- src/core/hle/kernel/k_scheduler.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 5ee4b8adc..e523c4923 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -721,7 +721,7 @@ void KScheduler::SwitchContextStep2() { } void KScheduler::ScheduleImpl() { - KThread* previous_thread = current_thread.load(); + KThread* previous_thread = GetCurrentThread(); KThread* next_thread = state.highest_priority_thread; state.needs_scheduling = false; @@ -733,10 +733,15 @@ void KScheduler::ScheduleImpl() { // If we're not actually switching thread, there's nothing to do. if (next_thread == current_thread.load()) { + previous_thread->EnableDispatch(); guard.Unlock(); return; } + if (next_thread->GetCurrentCore() != core_id) { + next_thread->SetCurrentCore(core_id); + } + current_thread.store(next_thread); KProcess* const previous_process = system.Kernel().CurrentProcess(); @@ -747,11 +752,7 @@ void KScheduler::ScheduleImpl() { Unload(previous_thread); std::shared_ptr* old_context; - if (previous_thread != nullptr) { - old_context = &previous_thread->GetHostContext(); - } else { - old_context = &idle_thread->GetHostContext(); - } + old_context = &previous_thread->GetHostContext(); guard.Unlock(); Common::Fiber::YieldTo(*old_context, *switch_fiber); From 629f9274ac88722d828e3484f73084376c2811ba Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:16:36 -0700 Subject: [PATCH 200/291] core: hle: kernel: k_scheduler: Remove unnecessary MakeCurrentProcess. --- src/core/hle/kernel/k_scheduler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index e523c4923..f5236dfea 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -699,11 +699,6 @@ void KScheduler::Reload(KThread* thread) { if (thread) { ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); - auto* const thread_owner_process = thread->GetOwnerProcess(); - if (thread_owner_process != nullptr) { - system.Kernel().MakeCurrentProcess(thread_owner_process); - } - Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(thread->GetContext32()); cpu_core.LoadContext(thread->GetContext64()); From 178584e56f742274ca6392ce3d87ff2ca08de731 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:20:07 -0700 Subject: [PATCH 201/291] core: hle: kernel: Use CurrentPhysicalCoreIndex as appropriate. --- src/core/hle/kernel/kernel.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 275fee0d8..288488644 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -848,15 +848,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const { } Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { - u32 core_id = impl->GetCurrentHostThreadID(); - ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - return impl->cores[core_id]; + return impl->cores[CurrentPhysicalCoreIndex()]; } const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { - u32 core_id = impl->GetCurrentHostThreadID(); - ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - return impl->cores[core_id]; + return impl->cores[CurrentPhysicalCoreIndex()]; } Kernel::KScheduler* KernelCore::CurrentScheduler() { From d604edfedffa1245ad33dd668e9e42394a213e24 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:22:52 -0700 Subject: [PATCH 202/291] core: cpu_manager: Use KScopedDisableDispatch. --- src/core/cpu_manager.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 5d43c6e5d..45cc176dc 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -117,17 +117,18 @@ void CpuManager::MultiCoreRunGuestLoop() { physical_core = &kernel.CurrentPhysicalCore(); } system.ExitDynarmicProfile(); - physical_core->ArmInterface().ClearExclusiveState(); - kernel.CurrentScheduler()->RescheduleCurrentCore(); + { + Kernel::KScopedDisableDispatch dd(kernel); + physical_core->ArmInterface().ClearExclusiveState(); + } } } void CpuManager::MultiCoreRunIdleThread() { auto& kernel = system.Kernel(); while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); - physical_core.Idle(); - kernel.CurrentScheduler()->RescheduleCurrentCore(); + Kernel::KScopedDisableDispatch dd(kernel); + kernel.CurrentPhysicalCore().Idle(); } } @@ -135,12 +136,12 @@ void CpuManager::MultiCoreRunSuspendThread() { auto& kernel = system.Kernel(); kernel.CurrentScheduler()->OnThreadStart(); while (true) { - auto core = kernel.GetCurrentHostThreadID(); + auto core = kernel.CurrentPhysicalCoreIndex(); auto& scheduler = *kernel.CurrentScheduler(); Kernel::KThread* current_thread = scheduler.GetCurrentThread(); Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); ASSERT(scheduler.ContextSwitchPending()); - ASSERT(core == kernel.GetCurrentHostThreadID()); + ASSERT(core == kernel.CurrentPhysicalCoreIndex()); scheduler.RescheduleCurrentCore(); } } From 284015dfd7d0b963b9ad0d196ee283ef2287b812 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:27:33 -0700 Subject: [PATCH 203/291] core: hle: kernel: k_scheduler: Improve DisableScheduling and EnableScheduling. --- src/core/hle/kernel/k_scheduler.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index f5236dfea..6ddbae52c 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -376,20 +376,18 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) { } void KScheduler::DisableScheduling(KernelCore& kernel) { - if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { - ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0); - scheduler->GetCurrentThread()->DisableDispatch(); - } + ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 0); + GetCurrentThreadPointer(kernel)->DisableDispatch(); } void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { - if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { - ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); - if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { - scheduler->GetCurrentThread()->EnableDispatch(); - } + ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 1); + + if (GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() > 1) { + GetCurrentThreadPointer(kernel)->EnableDispatch(); + } else { + RescheduleCores(kernel, cores_needing_scheduling); } - RescheduleCores(kernel, cores_needing_scheduling); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -646,6 +644,7 @@ void KScheduler::RescheduleCurrentCore() { if (phys_core.IsInterrupted()) { phys_core.ClearInterrupt(); } + guard.Lock(); if (state.needs_scheduling.load()) { Schedule(); @@ -662,10 +661,6 @@ void KScheduler::OnThreadStart() { void KScheduler::Unload(KThread* thread) { ASSERT(thread); - if (!thread) { - return; - } - LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); if (thread->IsCallingSvc()) { From 3239442de6204f41054b8c0121420e64f66c832e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 6 Aug 2021 23:43:26 -0700 Subject: [PATCH 204/291] core: hle: kernel: DisableDispatch on suspend threads. --- src/core/hle/kernel/kernel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 288488644..cf155ff66 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1055,6 +1055,9 @@ void KernelCore::Suspend(bool in_suspention) { impl->suspend_threads[core_id]->SetState(state); impl->suspend_threads[core_id]->SetWaitReasonForDebugging( ThreadWaitReasonForDebugging::Suspended); + if (!should_suspend) { + impl->suspend_threads[core_id]->DisableDispatch(); + } } } } From 07690572f777c66f649110db780f556186f5fea8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 7 Aug 2021 01:16:29 -0700 Subject: [PATCH 205/291] core: hle: kernel: k_auto_object: Add GetName method. - Useful purely for debugging. --- src/core/hle/kernel/k_auto_object.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index e4fcdbc67..165b76747 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -170,6 +170,10 @@ public: } } + const std::string& GetName() const { + return name; + } + private: void RegisterWithKernel(); void UnregisterWithKernel(); From 08c63d5c75522ce6b484153302de4c6cfac674f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 7 Aug 2021 12:33:07 -0700 Subject: [PATCH 206/291] core: cpu_manager: Use invalid core_id on init and simplify shutdown. --- src/core/cpu_manager.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 45cc176dc..d9bd5b665 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -32,7 +32,7 @@ void CpuManager::Initialize() { core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); } } else { - core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); + core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), -1); } } @@ -347,13 +347,9 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { sc_sync_first_use = false; } - // Abort if emulation was killed before the session really starts - if (!system.IsPoweredOn()) { - return; - } - + // Emulation was stopped if (stop_token.stop_requested()) { - break; + return; } auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); From d14b8fc7471061b84e7de0bd982a64660ee7f349 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 7 Aug 2021 12:33:31 -0700 Subject: [PATCH 207/291] core: hle: kernel: k_thread: Mark KScopedDisableDispatch as nodiscard. --- src/core/hle/kernel/k_thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index a149744c8..8bbf66c52 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -773,7 +773,7 @@ public: class KScopedDisableDispatch { public: - explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { + [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { GetCurrentThread(kernel).DisableDispatch(); } From 3dc803a430107fb22ffc91608c613e09ec5c8b51 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 14 Aug 2021 02:14:19 -0700 Subject: [PATCH 208/291] core: hle: kernel: Disable dispatch count tracking on single core. - This would have limited value, and would be a mess to handle properly. --- src/core/cpu_manager.cpp | 2 +- src/core/hle/kernel/k_thread.cpp | 6 +++++- src/core/hle/kernel/k_thread.h | 11 ++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index d9bd5b665..cbcc54891 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -32,7 +32,7 @@ void CpuManager::Initialize() { core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); } } else { - core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), -1); + core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); } } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index de94c737d..41bf9a6bb 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -13,6 +13,9 @@ #include "common/common_types.h" #include "common/fiber.h" #include "common/logging/log.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "common/thread_queue_list.h" #include "core/core.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" @@ -211,9 +214,10 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint // Initialize the thread. R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); - // Initialize host context. + // Initialize emulation parameters. thread->host_context = std::make_shared(std::move(init_func), init_func_parameter); + thread->is_single_core = !Settings::values.use_multi_core.GetValue(); return ResultSuccess; } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 8bbf66c52..e4c4c877d 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -454,8 +454,12 @@ public: return GetActiveCore() == 3; } + [[nodiscard]] bool IsDispatchTrackingDisabled() const { + return is_single_core || IsKernelThread(); + } + [[nodiscard]] s32 GetDisableDispatchCount() const { - if (IsKernelThread()) { + if (IsDispatchTrackingDisabled()) { // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. return 1; } @@ -464,7 +468,7 @@ public: } void DisableDispatch() { - if (IsKernelThread()) { + if (IsDispatchTrackingDisabled()) { // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. return; } @@ -474,7 +478,7 @@ public: } void EnableDispatch() { - if (IsKernelThread()) { + if (IsDispatchTrackingDisabled()) { // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. return; } @@ -727,6 +731,7 @@ private: // For emulation std::shared_ptr host_context{}; + bool is_single_core{}; // For debugging std::vector wait_objects_for_debugging; From bc1399204b914608715306a8a8dbe2f201dd4365 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 19:02:11 -0800 Subject: [PATCH 209/291] hle: kernel: Update KThreadQueue and migrate KSynchronizationObject. --- src/core/CMakeLists.txt | 1 + .../k_scoped_scheduler_lock_and_sleep.h | 1 + .../hle/kernel/k_synchronization_object.cpp | 155 +++++++++--------- .../hle/kernel/k_synchronization_object.h | 32 ++++ src/core/hle/kernel/k_thread.cpp | 42 ++++- src/core/hle/kernel/k_thread.h | 27 +++ src/core/hle/kernel/k_thread_queue.cpp | 51 ++++++ src/core/hle/kernel/k_thread_queue.h | 17 ++ 8 files changed, 251 insertions(+), 75 deletions(-) create mode 100644 src/core/hle/kernel/k_thread_queue.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eee8e2ccd..c42a29cc7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -237,6 +237,7 @@ add_library(core STATIC hle/kernel/k_system_control.h hle/kernel/k_thread.cpp hle/kernel/k_thread.h + hle/kernel/k_thread_queue.cpp hle/kernel/k_thread_queue.h hle/kernel/k_trace.h hle/kernel/k_transfer_memory.cpp diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 61dc2858f..2995c492d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -8,6 +8,7 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/global_scheduler_context.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/time_manager.h" diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index f168b4f21..ba8fc4010 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -8,11 +8,70 @@ #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { +namespace { + +class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { +private: + using ThreadListNode = KSynchronizationObject::ThreadListNode; + +private: + KSynchronizationObject** m_objects; + ThreadListNode* m_nodes; + s32 m_count; + +public: + ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o, + ThreadListNode* n, s32 c) + : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) { // ... + } + + virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, + ResultCode wait_result) override { + // Determine the sync index, and unlink all nodes. + s32 sync_index = -1; + for (auto i = 0; i < m_count; ++i) { + // Check if this is the signaled object. + if (m_objects[i] == signaled_object && sync_index == -1) { + sync_index = i; + } + + // Unlink the current node from the current object. + m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); + } + + // Set the waiting thread's sync index. + waiting_thread->SetSyncedIndex(sync_index); + + // Set the waiting thread as not cancellable. + waiting_thread->ClearCancellable(); + + // Invoke the base end wait handler. + KThreadQueue::EndWait(waiting_thread, wait_result); + } + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Remove all nodes from our list. + for (auto i = 0; i < m_count; ++i) { + m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); + } + + // Set the waiting thread as not cancellable. + waiting_thread->ClearCancellable(); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +} // namespace + void KSynchronizationObject::Finalize() { this->OnFinalizeSynchronizationObject(); KAutoObject::Finalize(); @@ -25,11 +84,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, std::vector thread_nodes(num_objects); // Prepare for wait. - KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); + KThread* thread = GetCurrentThreadPointer(kernel_ctx); + ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects, + thread_nodes.data(), num_objects); { // Setup the scheduling lock and sleep. - KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; + KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout); + + // Check if the thread should terminate. + if (thread->IsTerminationRequested()) { + slp.CancelSleep(); + return ResultTerminationRequested; + } // Check if any of the objects are already signaled. for (auto i = 0; i < num_objects; ++i) { @@ -48,12 +115,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, return ResultTimedOut; } - // Check if the thread should terminate. - if (thread->IsTerminationRequested()) { - slp.CancelSleep(); - return ResultTerminationRequested; - } - // Check if waiting was canceled. if (thread->IsWaitCancelled()) { slp.CancelSleep(); @@ -66,73 +127,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, thread_nodes[i].thread = thread; thread_nodes[i].next = nullptr; - if (objects[i]->thread_list_tail == nullptr) { - objects[i]->thread_list_head = std::addressof(thread_nodes[i]); - } else { - objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); - } - - objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); + objects[i]->LinkNode(std::addressof(thread_nodes[i])); } - // For debugging only - thread->SetWaitObjectsForDebugging({objects, static_cast(num_objects)}); - - // Mark the thread as waiting. + // Mark the thread as cancellable. thread->SetCancellable(); - thread->SetSyncedObject(nullptr, ResultTimedOut); - thread->SetState(ThreadState::Waiting); + + // Clear the thread's synced index. + thread->SetSyncedIndex(-1); + + // Wait for an object to be signaled. + thread->BeginWait(std::addressof(wait_queue)); thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); } - // The lock/sleep is done, so we should be able to get our result. - - // Thread is no longer cancellable. - thread->ClearCancellable(); - - // For debugging only - thread->SetWaitObjectsForDebugging({}); - - // Cancel the timer as needed. - kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); + // Set the output index. + *out_index = thread->GetSyncedIndex(); // Get the wait result. - ResultCode wait_result{ResultSuccess}; - s32 sync_index = -1; - { - KScopedSchedulerLock lock(kernel_ctx); - KSynchronizationObject* synced_obj; - wait_result = thread->GetWaitResult(std::addressof(synced_obj)); - - for (auto i = 0; i < num_objects; ++i) { - // Unlink the object from the list. - ThreadListNode* prev_ptr = - reinterpret_cast(std::addressof(objects[i]->thread_list_head)); - ThreadListNode* prev_val = nullptr; - ThreadListNode *prev, *tail_prev; - - do { - prev = prev_ptr; - prev_ptr = prev_ptr->next; - tail_prev = prev_val; - prev_val = prev_ptr; - } while (prev_ptr != std::addressof(thread_nodes[i])); - - if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { - objects[i]->thread_list_tail = tail_prev; - } - - prev->next = thread_nodes[i].next; - - if (objects[i] == synced_obj) { - sync_index = i; - } - } - } - - // Set output. - *out_index = sync_index; - return wait_result; + return thread->GetWaitResult(); } KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) @@ -141,7 +154,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) KSynchronizationObject::~KSynchronizationObject() = default; void KSynchronizationObject::NotifyAvailable(ResultCode result) { - KScopedSchedulerLock lock(kernel); + KScopedSchedulerLock sl(kernel); // If we're not signaled, we've nothing to notify. if (!this->IsSignaled()) { @@ -150,11 +163,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { // Iterate over each thread. for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { - KThread* thread = cur_node->thread; - if (thread->GetState() == ThreadState::Waiting) { - thread->SetSyncedObject(this, result); - thread->SetState(ThreadState::Runnable); - } + cur_node->thread->NotifyAvailable(this, result); } } diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 898e58e16..789ff4780 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -35,6 +35,38 @@ public: [[nodiscard]] std::vector GetWaitingThreadsForDebugging() const; + void LinkNode(ThreadListNode* node) { + // Link the node to the list. + if (thread_list_tail == nullptr) { + thread_list_head = node; + } else { + thread_list_tail->next = node; + } + + thread_list_tail = node; + } + + void UnlinkNode(ThreadListNode* node) { + // Unlink the node from the list. + ThreadListNode* prev_ptr = + reinterpret_cast(std::addressof(thread_list_head)); + ThreadListNode* prev_val = nullptr; + ThreadListNode *prev, *tail_prev; + + do { + prev = prev_ptr; + prev_ptr = prev_ptr->next; + tail_prev = prev_val; + prev_val = prev_ptr; + } while (prev_ptr != node); + + if (thread_list_tail == node) { + thread_list_tail = tail_prev; + } + + prev->next = node->next; + } + protected: explicit KSynchronizationObject(KernelCore& kernel); ~KSynchronizationObject() override; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 41bf9a6bb..3331b4845 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -303,7 +303,7 @@ void KThread::Wakeup() { if (GetState() == ThreadState::Waiting) { if (sleeping_queue != nullptr) { - sleeping_queue->WakeupThread(this); + sleeping_queue->EndWait(this, ResultSuccess); } else { SetState(ThreadState::Runnable); } @@ -331,7 +331,7 @@ void KThread::StartTermination() { // Signal. signaled = true; - NotifyAvailable(); + KSynchronizationObject::NotifyAvailable(); // Clear previous thread in KScheduler. KScheduler::ClearPreviousThread(kernel, this); @@ -1026,6 +1026,44 @@ ResultCode KThread::Sleep(s64 timeout) { return ResultSuccess; } +void KThread::BeginWait(KThreadQueue* queue) { + // Set our state as waiting. + SetState(ThreadState::Waiting); + + // Set our wait queue. + sleeping_queue = queue; +} + +void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { + // Lock the scheduler. + KScopedSchedulerLock sl(kernel); + + // If we're waiting, notify our queue that we're available. + if (GetState() == ThreadState::Waiting) { + sleeping_queue->NotifyAvailable(this, signaled_object, wait_result_); + } +} + +void KThread::EndWait(ResultCode wait_result_) { + // Lock the scheduler. + KScopedSchedulerLock sl(kernel); + + // If we're waiting, notify our queue that we're available. + if (GetState() == ThreadState::Waiting) { + sleeping_queue->EndWait(this, wait_result_); + } +} + +void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) { + // Lock the scheduler. + KScopedSchedulerLock sl(kernel); + + // If we're waiting, notify our queue that we're available. + if (GetState() == ThreadState::Waiting) { + sleeping_queue->CancelWait(this, wait_result_, cancel_timer_task); + } +} + void KThread::SetState(ThreadState state) { KScopedSchedulerLock sl{kernel}; diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e4c4c877d..bea5fd84d 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -202,6 +202,23 @@ public: wait_result = wait_res; } + constexpr void SetSyncedIndex(s32 index) { + synced_index = index; + } + + constexpr s32 GetSyncedIndex() const { + return synced_index; + } + + constexpr void SetWaitResult(ResultCode wait_res) { + wait_result = wait_res; + synced_object = nullptr; + } + + constexpr ResultCode GetWaitResult() const { + return wait_result; + } + [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { *out = synced_object; return wait_result; @@ -596,6 +613,15 @@ public: address_key_value = val; } + void ClearWaitQueue() { + sleeping_queue = nullptr; + } + + void BeginWait(KThreadQueue* queue); + void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_); + void EndWait(ResultCode wait_result_); + void CancelWait(ResultCode wait_result_, bool cancel_timer_task); + [[nodiscard]] bool HasWaiters() const { return !waiter_list.empty(); } @@ -707,6 +733,7 @@ private: u32 address_key_value{}; u32 suspend_request_flags{}; u32 suspend_allowed_flags{}; + s32 synced_index{}; ResultCode wait_result{ResultSuccess}; s32 base_priority{}; s32 physical_ideal_core_id{}; diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp new file mode 100644 index 000000000..46f27172b --- /dev/null +++ b/src/core/hle/kernel/k_thread_queue.cpp @@ -0,0 +1,51 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/time_manager.h" + +namespace Kernel { + +void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread, + [[maybe_unused]] KSynchronizationObject* signaled_object, + [[maybe_unused]] ResultCode wait_result) {} + +void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) { + // Set the thread's wait result. + waiting_thread->SetWaitResult(wait_result); + + // Set the thread as runnable. + waiting_thread->SetState(ThreadState::Runnable); + + // Clear the thread's wait queue. + waiting_thread->ClearWaitQueue(); + + // Cancel the thread task. + kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); +} + +void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) { + // Set the thread's wait result. + waiting_thread->SetWaitResult(wait_result); + + // Set the thread as runnable. + waiting_thread->SetState(ThreadState::Runnable); + + // Clear the thread's wait queue. + waiting_thread->ClearWaitQueue(); + + // Cancel the thread task. + if (cancel_timer_task) { + kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); + } +} + +void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread, + [[maybe_unused]] ResultCode wait_result) {} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 35d471dc5..74e76e7cb 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h @@ -4,6 +4,7 @@ #pragma once +#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" namespace Kernel { @@ -11,7 +12,16 @@ namespace Kernel { class KThreadQueue { public: explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} + virtual ~KThreadQueue(){}; + virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, + ResultCode wait_result); + virtual void EndWait(KThread* waiting_thread, ResultCode wait_result); + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task); + + // Deprecated, will be removed in subsequent commits. +public: bool IsEmpty() const { return wait_list.empty(); } @@ -78,4 +88,11 @@ private: KThread::WaiterList wait_list{}; }; +class KThreadQueueWithoutEndWait : public KThreadQueue { +public: + explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {} + + virtual void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; +}; + } // namespace Kernel From 2f894560413db9bf8efc1febc26904937a28380f Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 19:21:20 -0800 Subject: [PATCH 210/291] hle: kernel: KThread: Remove tracking of sync object from threads. --- src/core/hle/kernel/k_address_arbiter.cpp | 16 +++++++------- src/core/hle/kernel/k_condition_variable.cpp | 22 +++++++++----------- src/core/hle/kernel/k_server_session.cpp | 2 +- src/core/hle/kernel/k_thread.cpp | 7 ++----- src/core/hle/kernel/k_thread.h | 12 ----------- src/core/hle/kernel/svc.cpp | 3 +-- 6 files changed, 21 insertions(+), 41 deletions(-) diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 6771ef621..c5c81a880 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -97,7 +97,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread* target_thread = std::addressof(*it); - target_thread->SetSyncedObject(nullptr, ResultSuccess); + target_thread->SetWaitResult(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->Wakeup(); @@ -130,7 +130,7 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread* target_thread = std::addressof(*it); - target_thread->SetSyncedObject(nullptr, ResultSuccess); + target_thread->SetWaitResult(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->Wakeup(); @@ -198,7 +198,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread* target_thread = std::addressof(*it); - target_thread->SetSyncedObject(nullptr, ResultSuccess); + target_thread->SetWaitResult(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->Wakeup(); @@ -225,7 +225,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement } // Set the synced object. - cur_thread->SetSyncedObject(nullptr, ResultTimedOut); + cur_thread->SetWaitResult(ResultTimedOut); // Read the value from userspace. s32 user_value{}; @@ -274,8 +274,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement } // Get the result. - KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(&dummy); + return cur_thread->GetWaitResult(); } ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { @@ -292,7 +291,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { } // Set the synced object. - cur_thread->SetSyncedObject(nullptr, ResultTimedOut); + cur_thread->SetWaitResult(ResultTimedOut); // Read the value from userspace. s32 user_value{}; @@ -334,8 +333,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { } // Get the result. - KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(&dummy); + return cur_thread->GetWaitResult(); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index ed6f328fc..9eacbed7e 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -84,14 +84,14 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { next_value |= Svc::HandleWaitMask; } - next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); + next_owner_thread->SetWaitResult(ResultSuccess); next_owner_thread->Wakeup(); } // Write the value to userspace. if (!WriteToUser(system, addr, std::addressof(next_value))) { if (next_owner_thread) { - next_owner_thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); + next_owner_thread->SetWaitResult(ResultInvalidCurrentMemory); } return ResultInvalidCurrentMemory; @@ -110,7 +110,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val ASSERT(owner_thread.IsNull()); { KScopedSchedulerLock sl(kernel); - cur_thread->SetSyncedObject(nullptr, ResultSuccess); + cur_thread->SetWaitResult(ResultSuccess); // Check if the thread should terminate. R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); @@ -151,8 +151,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val } // Get the wait result. - KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(std::addressof(dummy)); + return cur_thread->GetWaitResult(); } KThread* KConditionVariable::SignalImpl(KThread* thread) { @@ -179,7 +178,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { if (can_access) { if (prev_tag == Svc::InvalidHandle) { // If nobody held the lock previously, we're all good. - thread->SetSyncedObject(nullptr, ResultSuccess); + thread->SetWaitResult(ResultSuccess); thread->Wakeup(); } else { // Get the previous owner. @@ -195,13 +194,13 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { thread_to_close = owner_thread; } else { // The lock was tagged with a thread that doesn't exist. - thread->SetSyncedObject(nullptr, ResultInvalidState); + thread->SetWaitResult(ResultInvalidState); thread->Wakeup(); } } } else { // If the address wasn't accessible, note so. - thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); + thread->SetWaitResult(ResultInvalidCurrentMemory); thread->Wakeup(); } @@ -265,7 +264,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; // Set the synced object. - cur_thread->SetSyncedObject(nullptr, ResultTimedOut); + cur_thread->SetWaitResult(ResultTimedOut); // Check that the thread isn't terminating. if (cur_thread->IsTerminationRequested()) { @@ -290,7 +289,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) } // Wake up the next owner. - next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); + next_owner_thread->SetWaitResult(ResultSuccess); next_owner_thread->Wakeup(); } @@ -340,8 +339,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) } // Get the result. - KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(std::addressof(dummy)); + return cur_thread->GetWaitResult(); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 2bd53ccbd..1f7220d48 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -176,7 +176,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { KScopedSchedulerLock lock(kernel); if (!context.IsThreadWaiting()) { context.GetThread().Wakeup(); - context.GetThread().SetSyncedObject(nullptr, result); + context.GetThread().SetWaitResult(result); } } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 3331b4845..2c1f29bad 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -130,9 +130,6 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s priority = prio; base_priority = prio; - // Set sync object and waiting lock to null. - synced_object = nullptr; - // Initialize sleeping queue. sleeping_queue = nullptr; @@ -279,7 +276,7 @@ void KThread::Finalize() { while (it != waiter_list.end()) { // The thread shouldn't be a kernel waiter. it->SetLockOwner(nullptr); - it->SetSyncedObject(nullptr, ResultInvalidState); + it->SetWaitResult(ResultInvalidState); it->Wakeup(); it = waiter_list.erase(it); } @@ -650,7 +647,7 @@ void KThread::WaitCancel() { sleeping_queue->WakeupThread(this); wait_cancelled = true; } else { - SetSyncedObject(nullptr, ResultCancelled); + SetWaitResult(ResultCancelled); SetState(ThreadState::Runnable); wait_cancelled = false; } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index bea5fd84d..f9a324eb3 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -197,11 +197,6 @@ public: void Suspend(); - void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { - synced_object = obj; - wait_result = wait_res; - } - constexpr void SetSyncedIndex(s32 index) { synced_index = index; } @@ -212,18 +207,12 @@ public: constexpr void SetWaitResult(ResultCode wait_res) { wait_result = wait_res; - synced_object = nullptr; } constexpr ResultCode GetWaitResult() const { return wait_result; } - [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { - *out = synced_object; - return wait_result; - } - /* * Returns the Thread Local Storage address of the current thread * @returns VAddr of the thread's TLS @@ -716,7 +705,6 @@ private: KAffinityMask physical_affinity_mask{}; u64 thread_id{}; std::atomic cpu_time{}; - KSynchronizationObject* synced_object{}; VAddr address_key{}; KProcess* parent{}; VAddr kernel_stack_top{}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e5e879eb5..50c6e513d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -325,8 +325,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { } } - KSynchronizationObject* dummy{}; - return thread->GetWaitResult(std::addressof(dummy)); + return thread->GetWaitResult(); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { From 15c721b90977865d964e26537f8a8f8740134164 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 19:23:37 -0800 Subject: [PATCH 211/291] hle: kernel: KAddressArbiter: Migrate to updated KThreadQueue. --- src/core/hle/kernel/k_address_arbiter.cpp | 82 +++++++++++------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index c5c81a880..165475fbf 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" @@ -85,6 +86,27 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 return true; } +class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { +private: + KAddressArbiter::ThreadTree* m_tree; + +public: + explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t) + : KThreadQueue(kernel_), m_tree(t) {} + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // If the thread is waiting on an address arbiter, remove it from the tree. + if (waiting_thread->IsWaitingForAddressArbiter()) { + m_tree->erase(m_tree->iterator_to(*waiting_thread)); + waiting_thread->ClearAddressArbiter(); + } + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + } // namespace ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { @@ -96,14 +118,14 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { auto it = thread_tree.nfind_light({addr, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { + // End the thread's wait. KThread* target_thread = std::addressof(*it); - target_thread->SetWaitResult(ResultSuccess); + target_thread->EndWait(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); - target_thread->Wakeup(); + target_thread->ClearAddressArbiter(); it = thread_tree.erase(it); - target_thread->ClearAddressArbiter(); ++num_waiters; } } @@ -129,14 +151,14 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 auto it = thread_tree.nfind_light({addr, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { + // End the thread's wait. KThread* target_thread = std::addressof(*it); - target_thread->SetWaitResult(ResultSuccess); + target_thread->EndWait(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); - target_thread->Wakeup(); + target_thread->ClearAddressArbiter(); it = thread_tree.erase(it); - target_thread->ClearAddressArbiter(); ++num_waiters; } } @@ -197,14 +219,14 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { + // End the thread's wait. KThread* target_thread = std::addressof(*it); - target_thread->SetWaitResult(ResultSuccess); + target_thread->EndWait(ResultSuccess); ASSERT(target_thread->IsWaitingForAddressArbiter()); - target_thread->Wakeup(); + target_thread->ClearAddressArbiter(); it = thread_tree.erase(it); - target_thread->ClearAddressArbiter(); ++num_waiters; } } @@ -214,6 +236,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { // Prepare to wait. KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); { KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; @@ -224,9 +247,6 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement return ResultTerminationRequested; } - // Set the synced object. - cur_thread->SetWaitResult(ResultTimedOut); - // Read the value from userspace. s32 user_value{}; bool succeeded{}; @@ -256,23 +276,12 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement // Set the arbiter. cur_thread->SetAddressArbiter(&thread_tree, addr); thread_tree.insert(*cur_thread); - cur_thread->SetState(ThreadState::Waiting); + + // Wait for the thread to finish. + cur_thread->BeginWait(std::addressof(wait_queue)); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); } - // Cancel the timer wait. - kernel.TimeManager().UnscheduleTimeEvent(cur_thread); - - // Remove from the address arbiter. - { - KScopedSchedulerLock sl(kernel); - - if (cur_thread->IsWaitingForAddressArbiter()) { - thread_tree.erase(thread_tree.iterator_to(*cur_thread)); - cur_thread->ClearAddressArbiter(); - } - } - // Get the result. return cur_thread->GetWaitResult(); } @@ -280,6 +289,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Prepare to wait. KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); { KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; @@ -290,9 +300,6 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { return ResultTerminationRequested; } - // Set the synced object. - cur_thread->SetWaitResult(ResultTimedOut); - // Read the value from userspace. s32 user_value{}; if (!ReadFromUser(system, &user_value, addr)) { @@ -315,23 +322,12 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Set the arbiter. cur_thread->SetAddressArbiter(&thread_tree, addr); thread_tree.insert(*cur_thread); - cur_thread->SetState(ThreadState::Waiting); + + // Wait for the thread to finish. + cur_thread->BeginWait(std::addressof(wait_queue)); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); } - // Cancel the timer wait. - kernel.TimeManager().UnscheduleTimeEvent(cur_thread); - - // Remove from the address arbiter. - { - KScopedSchedulerLock sl(kernel); - - if (cur_thread->IsWaitingForAddressArbiter()) { - thread_tree.erase(thread_tree.iterator_to(*cur_thread)); - cur_thread->ClearAddressArbiter(); - } - } - // Get the result. return cur_thread->GetWaitResult(); } From 423acf53b740ce96ca37988aad79ddf5013645ef Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 20:51:47 -0800 Subject: [PATCH 212/291] hle: kernel: KLightLock: Migrate to updated KThreadQueue. --- src/core/hle/kernel/k_light_lock.cpp | 69 ++++++++++++++-------------- src/core/hle/kernel/k_light_lock.h | 2 +- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 0896e705f..5e8f1a510 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -5,44 +5,54 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" namespace Kernel { +namespace { + +class ThreadQueueImplForKLightLock final : public KThreadQueue { +public: + explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {} + + virtual void CancelWait([[maybe_unused]] KThread* waiting_thread, + [[maybe_unused]] ResultCode wait_result, + [[maybe_unused]] bool cancel_timer_task) override { + // Do nothing, waiting to acquire a light lock cannot be canceled. + } +}; + +} // namespace + void KLightLock::Lock() { const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); - const uintptr_t cur_thread_tag = (cur_thread | 1); while (true) { uintptr_t old_tag = tag.load(std::memory_order_relaxed); - while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, + while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1), std::memory_order_acquire)) { - if ((old_tag | 1) == cur_thread_tag) { - return; - } } - if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { + if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) { break; } - - LockSlowPath(old_tag | 1, cur_thread); } } void KLightLock::Unlock() { const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); + uintptr_t expected = cur_thread; - do { - if (expected != cur_thread) { - return UnlockSlowPath(cur_thread); - } - } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release)); + if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) { + this->UnlockSlowPath(cur_thread); + } } -void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { +bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { KThread* cur_thread = reinterpret_cast(_cur_thread); + ThreadQueueImplForKLightLock wait_queue(kernel); // Pend the current thread waiting on the owner thread. { @@ -50,30 +60,23 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { // Ensure we actually have locking to do. if (tag.load(std::memory_order_relaxed) != _owner) { - return; + return false; } // Add the current thread as a waiter on the owner. - KThread* owner_thread = reinterpret_cast(_owner & ~1ULL); + KThread* owner_thread = reinterpret_cast(_owner & ~1ul); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); - // Set thread states. - cur_thread->SetState(ThreadState::Waiting); + // Begin waiting to hold the lock. + cur_thread->BeginWait(std::addressof(wait_queue)); if (owner_thread->IsSuspended()) { owner_thread->ContinueIfHasKernelWaiters(); } } - // We're no longer waiting on the lock owner. - { - KScopedSchedulerLock sl{kernel}; - - if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) { - owner_thread->RemoveWaiter(cur_thread); - } - } + return true; } void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { @@ -81,22 +84,20 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { // Unlock. { - KScopedSchedulerLock sl{kernel}; + KScopedSchedulerLock sl(kernel); // Get the next owner. - s32 num_waiters = 0; + s32 num_waiters; KThread* next_owner = owner_thread->RemoveWaiterByKey( std::addressof(num_waiters), reinterpret_cast(std::addressof(tag))); // Pass the lock to the next owner. uintptr_t next_tag = 0; if (next_owner != nullptr) { - next_tag = reinterpret_cast(next_owner); - if (num_waiters > 1) { - next_tag |= 0x1; - } + next_tag = + reinterpret_cast(next_owner) | static_cast(num_waiters > 1); - next_owner->SetState(ThreadState::Runnable); + next_owner->EndWait(ResultSuccess); if (next_owner->IsSuspended()) { next_owner->ContinueIfHasKernelWaiters(); @@ -110,7 +111,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { } // Write the new tag value. - tag.store(next_tag); + tag.store(next_tag, std::memory_order_release); } } diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h index ad853661d..4163b8a85 100644 --- a/src/core/hle/kernel/k_light_lock.h +++ b/src/core/hle/kernel/k_light_lock.h @@ -20,7 +20,7 @@ public: void Unlock(); - void LockSlowPath(uintptr_t owner, uintptr_t cur_thread); + bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread); void UnlockSlowPath(uintptr_t cur_thread); From 5dff28290fc4fc9bc3db3c32476dd93b2c4414c6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 20:54:44 -0800 Subject: [PATCH 213/291] hle: kernel: KLightConditionVariable: Migrate to updated KThreadQueue. --- src/core/CMakeLists.txt | 1 + .../hle/kernel/k_light_condition_variable.cpp | 80 +++++++++++++++++++ .../hle/kernel/k_light_condition_variable.h | 60 ++------------ 3 files changed, 87 insertions(+), 54 deletions(-) create mode 100644 src/core/hle/kernel/k_light_condition_variable.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c42a29cc7..cd99b447b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -185,6 +185,7 @@ add_library(core STATIC hle/kernel/k_event.h hle/kernel/k_handle_table.cpp hle/kernel/k_handle_table.h + hle/kernel/k_light_condition_variable.cpp hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp new file mode 100644 index 000000000..9ff710084 --- /dev/null +++ b/src/core/hle/kernel/k_light_condition_variable.cpp @@ -0,0 +1,80 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_light_condition_variable.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +namespace { + +class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { +private: + KThread::WaiterList* m_wait_list; + bool m_allow_terminating_thread; + +public: + ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, + bool term) + : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Only process waits if we're allowed to. + if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { + return; + } + + // Remove the thread from the waiting thread from the light condition variable. + m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +} // namespace + +void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { + // Create thread queue. + KThread* owner = GetCurrentThreadPointer(kernel); + + ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list), + allow_terminating_thread); + + // Sleep the thread. + { + KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); + + if (!allow_terminating_thread && owner->IsTerminationRequested()) { + lk.CancelSleep(); + return; + } + + lock->Unlock(); + + // Add the thread to the queue. + wait_list.push_back(*owner); + + // Begin waiting. + owner->BeginWait(std::addressof(wait_queue)); + } + + // Re-acquire the lock. + lock->Lock(); +} + +void KLightConditionVariable::Broadcast() { + KScopedSchedulerLock lk(kernel); + + // Signal all threads. + for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) { + it->EndWait(ResultSuccess); + } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h index fb0ad783a..65d3bc3e1 100644 --- a/src/core/hle/kernel/k_light_condition_variable.h +++ b/src/core/hle/kernel/k_light_condition_variable.h @@ -1,73 +1,25 @@ -// Copyright 2020 yuzu Emulator Project +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - #pragma once #include "common/common_types.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" -#include "core/hle/kernel/time_manager.h" +#include "core/hle/kernel/k_thread.h" namespace Kernel { + class KernelCore; +class KLightLock; class KLightConditionVariable { public: explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} - void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { - WaitImpl(lock, timeout, allow_terminating_thread); - } - - void Broadcast() { - KScopedSchedulerLock lk{kernel}; - - // Signal all threads. - for (auto& thread : wait_list) { - thread.SetState(ThreadState::Runnable); - } - } + void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true); + void Broadcast(); private: - void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { - KThread* owner = GetCurrentThreadPointer(kernel); - - // Sleep the thread. - { - KScopedSchedulerLockAndSleep lk{kernel, owner, timeout}; - - if (!allow_terminating_thread && owner->IsTerminationRequested()) { - lk.CancelSleep(); - return; - } - - lock->Unlock(); - - // Set the thread as waiting. - GetCurrentThread(kernel).SetState(ThreadState::Waiting); - - // Add the thread to the queue. - wait_list.push_back(GetCurrentThread(kernel)); - } - - // Remove the thread from the wait list. - { - KScopedSchedulerLock sl{kernel}; - - wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel))); - } - - // Cancel the task that the sleep setup. - kernel.TimeManager().UnscheduleTimeEvent(owner); - - // Re-acquire the lock. - lock->Lock(); - } - KernelCore& kernel; KThread::WaiterList wait_list{}; }; From e942d9754028850ea1f6b223e4f1b8da7b13c1c4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 21:02:29 -0800 Subject: [PATCH 214/291] hle: kernel: KServerSession: Migrate to updated KThreadQueue. --- src/core/hle/kernel/k_server_session.cpp | 3 +-- src/core/hle/kernel/svc.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 1f7220d48..d4e4a6b06 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -175,8 +175,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { { KScopedSchedulerLock lock(kernel); if (!context.IsThreadWaiting()) { - context.GetThread().Wakeup(); - context.GetThread().SetWaitResult(result); + context.GetThread().EndWait(result); } } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 50c6e513d..0e79e1be3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -31,6 +31,7 @@ #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" @@ -310,18 +311,24 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { auto& kernel = system.Kernel(); + // Create the wait queue. + KThreadQueue wait_queue(kernel); + auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { KScopedSchedulerLock lock(kernel); - thread->SetState(ThreadState::Waiting); - thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); + + // This is a synchronous request, so we should wait for our request to complete. + GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); + GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); { KScopedAutoObject session = kernel.CurrentProcess()->GetHandleTable().GetObject(handle); R_UNLESS(session.IsNotNull(), ResultInvalidHandle); LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); + session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), + system.CoreTiming()); } } From beb55cb90ee5a830240cd34ebf2ac236eeeb8653 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 21:28:09 -0800 Subject: [PATCH 215/291] hle: kernel: KConditionVariable: Migrate to updated KThreadQueue. --- src/core/hle/kernel/k_condition_variable.cpp | 67 ++++++++++++++++---- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 9eacbed7e..34c1eae65 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -11,6 +11,7 @@ #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_results.h" @@ -57,6 +58,48 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero return true; } +class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue { +public: + explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_) + : KThreadQueue(kernel_) {} + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Remove the thread as a waiter from its owner. + waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue { +private: + KConditionVariable::ThreadTree* m_tree; + +public: + explicit ThreadQueueImplForKConditionVariableWaitConditionVariable( + KernelCore& kernel_, KConditionVariable::ThreadTree* t) + : KThreadQueue(kernel_), m_tree(t) {} + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Remove the thread as a waiter from its owner. + if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { + owner->RemoveWaiter(waiting_thread); + } + + // If the thread is waiting on a condvar, remove it from the tree. + if (waiting_thread->IsWaitingForConditionVariable()) { + m_tree->erase(m_tree->iterator_to(*waiting_thread)); + waiting_thread->ClearConditionVariable(); + } + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + } // namespace KConditionVariable::KConditionVariable(Core::System& system_) @@ -84,8 +127,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { next_value |= Svc::HandleWaitMask; } - next_owner_thread->SetWaitResult(ResultSuccess); - next_owner_thread->Wakeup(); + next_owner_thread->EndWait(ResultSuccess); } // Write the value to userspace. @@ -103,6 +145,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel); // Wait for the address. { @@ -133,7 +176,9 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val // Update the lock. cur_thread->SetAddressKey(addr, value); owner_thread->AddWaiter(cur_thread); - cur_thread->SetState(ThreadState::Waiting); + + // Begin waiting. + cur_thread->BeginWait(std::addressof(wait_queue)); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); cur_thread->SetMutexWaitAddressForDebugging(addr); } @@ -178,8 +223,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { if (can_access) { if (prev_tag == Svc::InvalidHandle) { // If nobody held the lock previously, we're all good. - thread->SetWaitResult(ResultSuccess); - thread->Wakeup(); + thread->EndWait(ResultSuccess); } else { // Get the previous owner. KThread* owner_thread = kernel.CurrentProcess() @@ -194,14 +238,12 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { thread_to_close = owner_thread; } else { // The lock was tagged with a thread that doesn't exist. - thread->SetWaitResult(ResultInvalidState); - thread->Wakeup(); + thread->EndWait(ResultInvalidState); } } } else { // If the address wasn't accessible, note so. - thread->SetWaitResult(ResultInvalidCurrentMemory); - thread->Wakeup(); + thread->EndWait(ResultInvalidCurrentMemory); } return thread_to_close; @@ -259,6 +301,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // Prepare to wait. KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue( + kernel, std::addressof(thread_tree)); { KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; @@ -289,8 +333,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) } // Wake up the next owner. - next_owner_thread->SetWaitResult(ResultSuccess); - next_owner_thread->Wakeup(); + next_owner_thread->EndWait(ResultSuccess); } // Write to the cv key. @@ -315,7 +358,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) // If the timeout is non-zero, set the thread as waiting. if (timeout != 0) { - cur_thread->SetState(ThreadState::Waiting); + cur_thread->BeginWait(std::addressof(wait_queue)); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); cur_thread->SetMutexWaitAddressForDebugging(addr); } From b0671c7cfaa8bdb9704827af83be9223a5890f97 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 10 Nov 2021 22:28:30 -0800 Subject: [PATCH 216/291] hle: kernel: KThread: Migrate to updated KThreadQueue (part 1). --- src/core/hle/kernel/k_thread.cpp | 121 ++++++++++++++------------- src/core/hle/kernel/k_thread.h | 4 +- src/core/hle/kernel/time_manager.cpp | 6 +- 3 files changed, 71 insertions(+), 60 deletions(-) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 2c1f29bad..995f0ca50 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -59,6 +59,35 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, namespace Kernel { +namespace { + +class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { +public: + explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) + : KThreadQueueWithoutEndWait(kernel_) {} +}; + +class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { +private: + KThread::WaiterList* m_wait_list; + +public: + explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) + : KThreadQueue(kernel_), m_wait_list(wl) { // ... + } + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Remove the thread from the wait list. + m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +} // namespace + KThread::KThread(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} KThread::~KThread() = default; @@ -274,11 +303,14 @@ void KThread::Finalize() { auto it = waiter_list.begin(); while (it != waiter_list.end()) { - // The thread shouldn't be a kernel waiter. + // Clear the lock owner it->SetLockOwner(nullptr); - it->SetWaitResult(ResultInvalidState); - it->Wakeup(); + + // Erase the waiter from our list. it = waiter_list.erase(it); + + // Cancel the thread's wait. + it->CancelWait(ResultInvalidState, true); } } @@ -295,15 +327,12 @@ bool KThread::IsSignaled() const { return signaled; } -void KThread::Wakeup() { - KScopedSchedulerLock sl{kernel}; +void KThread::OnTimer() { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + // If we're waiting, cancel the wait. if (GetState() == ThreadState::Waiting) { - if (sleeping_queue != nullptr) { - sleeping_queue->EndWait(this, ResultSuccess); - } else { - SetState(ThreadState::Runnable); - } + sleeping_queue->CancelWait(this, ResultTimedOut, false); } } @@ -475,7 +504,6 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m return ResultSuccess; } - ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { ASSERT(parent != nullptr); ASSERT(v_affinity_mask != 0); @@ -642,15 +670,9 @@ void KThread::WaitCancel() { KScopedSchedulerLock sl{kernel}; // Check if we're waiting and cancellable. - if (GetState() == ThreadState::Waiting && cancellable) { - if (sleeping_queue != nullptr) { - sleeping_queue->WakeupThread(this); - wait_cancelled = true; - } else { - SetWaitResult(ResultCancelled); - SetState(ThreadState::Runnable); - wait_cancelled = false; - } + if (this->GetState() == ThreadState::Waiting && cancellable) { + wait_cancelled = false; + sleeping_queue->CancelWait(this, ResultCancelled, true); } else { // Otherwise, note that we cancelled a wait. wait_cancelled = true; @@ -701,60 +723,59 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { // Set the activity. { // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; + KScopedSchedulerLock sl(kernel); // Verify our state. - const auto cur_state = GetState(); + const auto cur_state = this->GetState(); R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), ResultInvalidState); // Either pause or resume. if (activity == Svc::ThreadActivity::Paused) { // Verify that we're not suspended. - R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState); + R_UNLESS(!this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); // Suspend. - RequestSuspend(SuspendType::Thread); + this->RequestSuspend(SuspendType::Thread); } else { ASSERT(activity == Svc::ThreadActivity::Runnable); // Verify that we're suspended. - R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState); + R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); // Resume. - Resume(SuspendType::Thread); + this->Resume(SuspendType::Thread); } } // If the thread is now paused, update the pinned waiter list. if (activity == Svc::ThreadActivity::Paused) { - bool thread_is_pinned{}; - bool thread_is_current{}; + ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, + std::addressof(pinned_waiter_list)); + + bool thread_is_current; do { // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; + KScopedSchedulerLock sl(kernel); // Don't do any further management if our termination has been requested. - R_SUCCEED_IF(IsTerminationRequested()); + R_SUCCEED_IF(this->IsTerminationRequested()); + + // By default, treat the thread as not current. + thread_is_current = false; // Check whether the thread is pinned. - if (GetStackParameters().is_pinned) { + if (this->GetStackParameters().is_pinned) { // Verify that the current thread isn't terminating. R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); - // Note that the thread was pinned and not current. - thread_is_pinned = true; - thread_is_current = false; - // Wait until the thread isn't pinned any more. pinned_waiter_list.push_back(GetCurrentThread(kernel)); - GetCurrentThread(kernel).SetState(ThreadState::Waiting); + GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_)); } else { // Check if the thread is currently running. // If it is, we'll need to retry. - thread_is_current = false; - for (auto i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { if (kernel.Scheduler(i).GetCurrentThread() == this) { thread_is_current = true; @@ -763,16 +784,6 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { } } } while (thread_is_current); - - // If the thread was pinned, it no longer is, and we should remove the current thread from - // our waiter list. - if (thread_is_pinned) { - // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; - - // Remove from the list. - pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); - } } return ResultSuccess; @@ -1000,26 +1011,22 @@ ResultCode KThread::Sleep(s64 timeout) { ASSERT(this == GetCurrentThreadPointer(kernel)); ASSERT(timeout > 0); + ThreadQueueImplForKThreadSleep wait_queue(kernel); { // Setup the scheduling lock and sleep. - KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; + KScopedSchedulerLockAndSleep slp(kernel, this, timeout); // Check if the thread should terminate. - if (IsTerminationRequested()) { + if (this->IsTerminationRequested()) { slp.CancelSleep(); return ResultTerminationRequested; } - // Mark the thread as waiting. - SetState(ThreadState::Waiting); + // Wait for the sleep to end. + this->BeginWait(std::addressof(wait_queue)); SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); } - // The lock/sleep is done. - - // Cancel the timer. - kernel.TimeManager().UnscheduleTimeEvent(this); - return ResultSuccess; } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index f9a324eb3..6d68c2399 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -161,8 +161,6 @@ public: } } - void Wakeup(); - void SetBasePriority(s32 value); [[nodiscard]] ResultCode Run(); @@ -380,6 +378,8 @@ public: [[nodiscard]] bool IsSignaled() const override; + void OnTimer(); + static void PostDestroy(uintptr_t arg); [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 8cd7279a3..aa985d820 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/time_manager.h" @@ -15,7 +16,10 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { Core::Timing::CreateEvent("Kernel::TimeManagerCallback", [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { KThread* thread = reinterpret_cast(thread_handle); - thread->Wakeup(); + { + KScopedSchedulerLock sl(system.Kernel()); + thread->OnTimer(); + } }); } From f62c7091a2bb0c70211b7424c4285906f5dccf4b Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 10 Nov 2021 22:46:07 -0800 Subject: [PATCH 217/291] hle: kernel: KThread: Migrate to updated KThreadQueue (part 2). --- src/core/hle/kernel/k_thread.cpp | 48 +++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 995f0ca50..7ef52a240 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -504,30 +504,33 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m return ResultSuccess; } -ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { + +ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) { ASSERT(parent != nullptr); ASSERT(v_affinity_mask != 0); - KScopedLightLock lk{activity_pause_lock}; + KScopedLightLock lk(activity_pause_lock); // Set the core mask. u64 p_affinity_mask = 0; { - KScopedSchedulerLock sl{kernel}; + KScopedSchedulerLock sl(kernel); ASSERT(num_core_migration_disables >= 0); - // If the core id is no-update magic, preserve the ideal core id. - if (cpu_core_id == Svc::IdealCoreNoUpdate) { - cpu_core_id = virtual_ideal_core_id; - R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination); + // If we're updating, set our ideal virtual core. + if (core_id_ != Svc::IdealCoreNoUpdate) { + virtual_ideal_core_id = core_id_; + } else { + // Preserve our ideal core id. + core_id_ = virtual_ideal_core_id; + R_UNLESS(((1ULL << core_id_) & v_affinity_mask) != 0, ResultInvalidCombination); } - // Set the virtual core/affinity mask. - virtual_ideal_core_id = cpu_core_id; + // Set our affinity mask. virtual_affinity_mask = v_affinity_mask; // Translate the virtual core to a physical core. - if (cpu_core_id >= 0) { - cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id]; + if (core_id_ >= 0) { + core_id_ = Core::Hardware::VirtualToPhysicalCoreMap[core_id_]; } // Translate the virtual affinity mask to a physical one. @@ -542,7 +545,7 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { const KAffinityMask old_mask = physical_affinity_mask; // Set our new ideals. - physical_ideal_core_id = cpu_core_id; + physical_ideal_core_id = core_id_; physical_affinity_mask.SetAffinityMask(p_affinity_mask); if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { @@ -560,18 +563,18 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { } } else { // Otherwise, we edit the original affinity for restoration later. - original_physical_ideal_core_id = cpu_core_id; + original_physical_ideal_core_id = core_id_; original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); } } // Update the pinned waiter list. + ThreadQueueImplForKThreadSetProperty wait_queue(kernel, std::addressof(pinned_waiter_list)); { bool retry_update{}; - bool thread_is_pinned{}; do { // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; + KScopedSchedulerLock sl(kernel); // Don't do any further management if our termination has been requested. R_SUCCEED_IF(IsTerminationRequested()); @@ -599,12 +602,9 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); - // Note that the thread was pinned. - thread_is_pinned = true; - // Wait until the thread isn't pinned any more. pinned_waiter_list.push_back(GetCurrentThread(kernel)); - GetCurrentThread(kernel).SetState(ThreadState::Waiting); + GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); } else { // If the thread isn't pinned, release the scheduler lock and retry until it's // not current. @@ -612,16 +612,6 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { } } } while (retry_update); - - // If the thread was pinned, it no longer is, and we should remove the current thread from - // our waiter list. - if (thread_is_pinned) { - // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; - - // Remove from the list. - pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); - } } return ResultSuccess; From f3d6e31e7805711803d11607fd807f23715d3449 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 9 Nov 2021 22:06:49 -0800 Subject: [PATCH 218/291] hle: kernel: KConditionVariable: Various updates & simplifications. --- src/core/hle/kernel/k_condition_variable.cpp | 188 +++++++------------ src/core/hle/kernel/k_condition_variable.h | 2 +- 2 files changed, 67 insertions(+), 123 deletions(-) diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 34c1eae65..f343e3c2f 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -121,26 +121,31 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { // Determine the next tag. u32 next_value{}; - if (next_owner_thread) { + if (next_owner_thread != nullptr) { next_value = next_owner_thread->GetAddressKeyValue(); if (num_waiters > 1) { next_value |= Svc::HandleWaitMask; } - next_owner_thread->EndWait(ResultSuccess); - } - - // Write the value to userspace. - if (!WriteToUser(system, addr, std::addressof(next_value))) { - if (next_owner_thread) { - next_owner_thread->SetWaitResult(ResultInvalidCurrentMemory); + // Write the value to userspace. + ResultCode result{ResultSuccess}; + if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] { + result = ResultSuccess; + } else { + result = ResultInvalidCurrentMemory; } - return ResultInvalidCurrentMemory; + // Signal the next owner thread. + next_owner_thread->EndWait(result); + return result; + } else { + // Just write the value to userspace. + R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)), + ResultInvalidCurrentMemory); + + return ResultSuccess; } } - - return ResultSuccess; } ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { @@ -148,58 +153,45 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel); // Wait for the address. - { - KScopedAutoObject owner_thread; - ASSERT(owner_thread.IsNull()); - { - KScopedSchedulerLock sl(kernel); - cur_thread->SetWaitResult(ResultSuccess); - - // Check if the thread should terminate. - R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); - - { - // Read the tag from userspace. - u32 test_tag{}; - R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), - ResultInvalidCurrentMemory); - - // If the tag isn't the handle (with wait mask), we're done. - R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), ResultSuccess); - - // Get the lock owner thread. - owner_thread = - kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle( - handle); - R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle); - - // Update the lock. - cur_thread->SetAddressKey(addr, value); - owner_thread->AddWaiter(cur_thread); - - // Begin waiting. - cur_thread->BeginWait(std::addressof(wait_queue)); - cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); - cur_thread->SetMutexWaitAddressForDebugging(addr); - } - } - ASSERT(owner_thread.IsNotNull()); - } - - // Remove the thread as a waiter from the lock owner. + KThread* owner_thread{}; { KScopedSchedulerLock sl(kernel); - KThread* owner_thread = cur_thread->GetLockOwner(); - if (owner_thread != nullptr) { - owner_thread->RemoveWaiter(cur_thread); - } + + // Check if the thread should terminate. + R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); + + // Read the tag from userspace. + u32 test_tag{}; + R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory); + + // If the tag isn't the handle (with wait mask), we're done. + R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask)); + + // Get the lock owner thread. + owner_thread = kernel.CurrentProcess() + ->GetHandleTable() + .GetObjectWithoutPseudoHandle(handle) + .ReleasePointerUnsafe(); + R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); + + // Update the lock. + cur_thread->SetAddressKey(addr, value); + owner_thread->AddWaiter(cur_thread); + + // Begin waiting. + cur_thread->BeginWait(std::addressof(wait_queue)); + cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); + cur_thread->SetMutexWaitAddressForDebugging(addr); } + // Close our reference to the owner thread, now that the wait is over. + owner_thread->Close(); + // Get the wait result. return cur_thread->GetWaitResult(); } -KThread* KConditionVariable::SignalImpl(KThread* thread) { +void KConditionVariable::SignalImpl(KThread* thread) { // Check pre-conditions. ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -213,14 +205,13 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. // TODO(bunnei): We should call CanAccessAtomic(..) here. can_access = true; - if (can_access) { + if (can_access) [[likely]] { UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag, Svc::HandleWaitMask); } } - KThread* thread_to_close = nullptr; - if (can_access) { + if (can_access) [[likely]] { if (prev_tag == Svc::InvalidHandle) { // If nobody held the lock previously, we're all good. thread->EndWait(ResultSuccess); @@ -232,10 +223,10 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { static_cast(prev_tag & ~Svc::HandleWaitMask)) .ReleasePointerUnsafe(); - if (owner_thread) { + if (owner_thread) [[likely]] { // Add the thread as a waiter on the owner. owner_thread->AddWaiter(thread); - thread_to_close = owner_thread; + owner_thread->Close(); } else { // The lock was tagged with a thread that doesn't exist. thread->EndWait(ResultInvalidState); @@ -245,20 +236,11 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { // If the address wasn't accessible, note so. thread->EndWait(ResultInvalidCurrentMemory); } - - return thread_to_close; } void KConditionVariable::Signal(u64 cv_key, s32 count) { - // Prepare for signaling. - constexpr int MaxThreads = 16; - - KLinkedList thread_list{kernel}; - std::array thread_array; - s32 num_to_close{}; - // Perform signaling. - s32 num_waiters{}; + int num_waiters = 0; { KScopedSchedulerLock sl(kernel); @@ -267,14 +249,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { (it->GetConditionVariableKey() == cv_key)) { KThread* target_thread = std::addressof(*it); - if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { - if (num_to_close < MaxThreads) { - thread_array[num_to_close++] = thread; - } else { - thread_list.push_back(*thread); - } - } - + this->SignalImpl(target_thread); it = thread_tree.erase(it); target_thread->ClearConditionVariable(); ++num_waiters; @@ -282,33 +257,20 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // If we have no waiters, clear the has waiter flag. if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) { - const u32 has_waiter_flag{}; + const u32 has_waiter_flag = 0; WriteToUser(system, cv_key, std::addressof(has_waiter_flag)); } } - - // Close threads in the array. - for (auto i = 0; i < num_to_close; ++i) { - thread_array[i]->Close(); - } - - // Close threads in the list. - for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { - (*it).Close(); - } } ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // Prepare to wait. - KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = GetCurrentThreadPointer(kernel); ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue( kernel, std::addressof(thread_tree)); { - KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; - - // Set the synced object. - cur_thread->SetWaitResult(ResultTimedOut); + KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout); // Check that the thread isn't terminating. if (cur_thread->IsTerminationRequested()) { @@ -350,38 +312,20 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) } } + // If timeout is zero, time out. + R_UNLESS(timeout != 0, ResultTimedOut); + // Update condition variable tracking. - { - cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); - thread_tree.insert(*cur_thread); - } + cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); + thread_tree.insert(*cur_thread); - // If the timeout is non-zero, set the thread as waiting. - if (timeout != 0) { - cur_thread->BeginWait(std::addressof(wait_queue)); - cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); - cur_thread->SetMutexWaitAddressForDebugging(addr); - } + // Begin waiting. + cur_thread->BeginWait(std::addressof(wait_queue)); + cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); + cur_thread->SetMutexWaitAddressForDebugging(addr); } - // Cancel the timer wait. - kernel.TimeManager().UnscheduleTimeEvent(cur_thread); - - // Remove from the condition variable. - { - KScopedSchedulerLock sl(kernel); - - if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) { - owner->RemoveWaiter(cur_thread); - } - - if (cur_thread->IsWaitingForConditionVariable()) { - thread_tree.erase(thread_tree.iterator_to(*cur_thread)); - cur_thread->ClearConditionVariable(); - } - } - - // Get the result. + // Get the wait result. return cur_thread->GetWaitResult(); } diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h index 861dbd420..5e4815d08 100644 --- a/src/core/hle/kernel/k_condition_variable.h +++ b/src/core/hle/kernel/k_condition_variable.h @@ -34,7 +34,7 @@ public: [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); private: - [[nodiscard]] KThread* SignalImpl(KThread* thread); + void SignalImpl(KThread* thread); ThreadTree thread_tree; From 4c747611555068817f76e72b2cb9c7af99480d12 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 10 Nov 2021 22:53:19 -0800 Subject: [PATCH 219/291] hle: kernel: KThreadQueue: Remove deprecated code. --- src/core/hle/kernel/k_thread_queue.h | 63 ---------------------------- 1 file changed, 63 deletions(-) diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 74e76e7cb..fddf16e8b 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h @@ -20,69 +20,6 @@ public: virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, bool cancel_timer_task); - // Deprecated, will be removed in subsequent commits. -public: - bool IsEmpty() const { - return wait_list.empty(); - } - - KThread::WaiterList::iterator begin() { - return wait_list.begin(); - } - KThread::WaiterList::iterator end() { - return wait_list.end(); - } - - bool SleepThread(KThread* t) { - KScopedSchedulerLock sl{kernel}; - - // If the thread needs terminating, don't enqueue it. - if (t->IsTerminationRequested()) { - return false; - } - - // Set the thread's queue and mark it as waiting. - t->SetSleepingQueue(this); - t->SetState(ThreadState::Waiting); - - // Add the thread to the queue. - wait_list.push_back(*t); - - return true; - } - - void WakeupThread(KThread* t) { - KScopedSchedulerLock sl{kernel}; - - // Remove the thread from the queue. - wait_list.erase(wait_list.iterator_to(*t)); - - // Mark the thread as no longer sleeping. - t->SetState(ThreadState::Runnable); - t->SetSleepingQueue(nullptr); - } - - KThread* WakeupFrontThread() { - KScopedSchedulerLock sl{kernel}; - - if (wait_list.empty()) { - return nullptr; - } else { - // Remove the thread from the queue. - auto it = wait_list.begin(); - KThread* thread = std::addressof(*it); - wait_list.erase(it); - - ASSERT(thread->GetState() == ThreadState::Waiting); - - // Mark the thread as no longer sleeping. - thread->SetState(ThreadState::Runnable); - thread->SetSleepingQueue(nullptr); - - return thread; - } - } - private: KernelCore& kernel; KThread::WaiterList wait_list{}; From 316a2dd22a25e4cfb31b364ab6595d8bb054411c Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 10 Nov 2021 23:02:45 -0800 Subject: [PATCH 220/291] hle: kernel: KProcess: Improvements for thread pinning. --- src/core/hle/kernel/k_process.cpp | 27 ++++++++++++++++++++++----- src/core/hle/kernel/k_process.h | 7 ++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 7cc2061ea..90dda40dc 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -228,12 +228,15 @@ void KProcess::PinCurrentThread() { const s32 core_id = GetCurrentCoreId(kernel); KThread* cur_thread = GetCurrentThreadPointer(kernel); - // Pin it. - PinThread(core_id, cur_thread); - cur_thread->Pin(); + // If the thread isn't terminated, pin it. + if (!cur_thread->IsTerminationRequested()) { + // Pin it. + PinThread(core_id, cur_thread); + cur_thread->Pin(); - // An update is needed. - KScheduler::SetSchedulerUpdateNeeded(kernel); + // An update is needed. + KScheduler::SetSchedulerUpdateNeeded(kernel); + } } void KProcess::UnpinCurrentThread() { @@ -251,6 +254,20 @@ void KProcess::UnpinCurrentThread() { KScheduler::SetSchedulerUpdateNeeded(kernel); } +void KProcess::UnpinThread(KThread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Get the thread's core id. + const auto core_id = thread->GetActiveCore(); + + // Unpin it. + UnpinThread(core_id, thread); + thread->Unpin(); + + // An update is needed. + KScheduler::SetSchedulerUpdateNeeded(kernel); +} + ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, [[maybe_unused]] size_t size) { // Lock ourselves, to prevent concurrent access. diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 8a8c1fcbb..d972c9de0 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -259,7 +259,7 @@ public: [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); - return pinned_threads[core_id]; + return pinned_threads.at(core_id); } /// Gets 8 bytes of random data for svcGetInfo RandomEntropy @@ -347,6 +347,7 @@ public: void PinCurrentThread(); void UnpinCurrentThread(); + void UnpinThread(KThread* thread); KLightLock& GetStateLock() { return state_lock; @@ -368,14 +369,14 @@ private: void PinThread(s32 core_id, KThread* thread) { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); ASSERT(thread != nullptr); - ASSERT(pinned_threads[core_id] == nullptr); + ASSERT(pinned_threads.at(core_id) == nullptr); pinned_threads[core_id] = thread; } void UnpinThread(s32 core_id, KThread* thread) { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); ASSERT(thread != nullptr); - ASSERT(pinned_threads[core_id] == thread); + ASSERT(pinned_threads.at(core_id) == thread); pinned_threads[core_id] = nullptr; } From 8f4ff06c4cf807ff68619eb69cc69dc20659d6d6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 21 Nov 2021 02:29:53 -0800 Subject: [PATCH 221/291] hle: kernel: Cleanup to match coding style. --- src/core/hle/kernel/k_address_arbiter.cpp | 6 +++--- .../hle/kernel/k_light_condition_variable.cpp | 8 ++++---- .../hle/kernel/k_synchronization_object.cpp | 18 +++++++----------- src/core/hle/kernel/k_thread.cpp | 9 ++++----- src/core/hle/kernel/k_thread.h | 4 ++-- src/core/hle/kernel/k_thread_queue.h | 2 +- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 165475fbf..a4ce99402 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -87,9 +87,6 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 } class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { -private: - KAddressArbiter::ThreadTree* m_tree; - public: explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t) : KThreadQueue(kernel_), m_tree(t) {} @@ -105,6 +102,9 @@ public: // Invoke the base cancel wait handler. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } + +private: + KAddressArbiter::ThreadTree* m_tree; }; } // namespace diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp index 9ff710084..7319a0ca0 100644 --- a/src/core/hle/kernel/k_light_condition_variable.cpp +++ b/src/core/hle/kernel/k_light_condition_variable.cpp @@ -13,10 +13,6 @@ namespace Kernel { namespace { class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { -private: - KThread::WaiterList* m_wait_list; - bool m_allow_terminating_thread; - public: ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, bool term) @@ -35,6 +31,10 @@ public: // Invoke the base cancel wait handler. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } + +private: + KThread::WaiterList* m_wait_list; + bool m_allow_terminating_thread; }; } // namespace diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index ba8fc4010..ffeb4b73f 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -17,19 +17,10 @@ namespace Kernel { namespace { class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { -private: - using ThreadListNode = KSynchronizationObject::ThreadListNode; - -private: - KSynchronizationObject** m_objects; - ThreadListNode* m_nodes; - s32 m_count; - public: ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o, - ThreadListNode* n, s32 c) - : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) { // ... - } + KSynchronizationObject::ThreadListNode* n, s32 c) + : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {} virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, ResultCode wait_result) override { @@ -68,6 +59,11 @@ public: // Invoke the base cancel wait handler. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } + +private: + KSynchronizationObject** m_objects; + KSynchronizationObject::ThreadListNode* m_nodes; + s32 m_count; }; } // namespace diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 7ef52a240..813b92ea4 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -68,13 +68,9 @@ public: }; class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { -private: - KThread::WaiterList* m_wait_list; - public: explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) - : KThreadQueue(kernel_), m_wait_list(wl) { // ... - } + : KThreadQueue(kernel_), m_wait_list(wl) {} virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, bool cancel_timer_task) override { @@ -84,6 +80,9 @@ public: // Invoke the base cancel wait handler. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } + +private: + KThread::WaiterList* m_wait_list; }; } // namespace diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 6d68c2399..1cde71e89 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -199,7 +199,7 @@ public: synced_index = index; } - constexpr s32 GetSyncedIndex() const { + [[nodiscard]] constexpr s32 GetSyncedIndex() const { return synced_index; } @@ -207,7 +207,7 @@ public: wait_result = wait_res; } - constexpr ResultCode GetWaitResult() const { + [[nodiscard]] constexpr ResultCode GetWaitResult() const { return wait_result; } diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index fddf16e8b..1f13cde83 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h @@ -12,7 +12,7 @@ namespace Kernel { class KThreadQueue { public: explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} - virtual ~KThreadQueue(){}; + virtual ~KThreadQueue() = default; virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, ResultCode wait_result); From 2c49a65d2be9cc18bf6e72bb09ad4ce6a8e7588f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 21 Nov 2021 02:30:16 -0800 Subject: [PATCH 222/291] hle: kernel: KSynchronizationObject: Fix variable shadowing. --- src/core/hle/kernel/k_synchronization_object.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 789ff4780..ec235437b 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -35,18 +35,18 @@ public: [[nodiscard]] std::vector GetWaitingThreadsForDebugging() const; - void LinkNode(ThreadListNode* node) { + void LinkNode(ThreadListNode* node_) { // Link the node to the list. if (thread_list_tail == nullptr) { - thread_list_head = node; + thread_list_head = node_; } else { - thread_list_tail->next = node; + thread_list_tail->next = node_; } - thread_list_tail = node; + thread_list_tail = node_; } - void UnlinkNode(ThreadListNode* node) { + void UnlinkNode(ThreadListNode* node_) { // Unlink the node from the list. ThreadListNode* prev_ptr = reinterpret_cast(std::addressof(thread_list_head)); @@ -58,13 +58,13 @@ public: prev_ptr = prev_ptr->next; tail_prev = prev_val; prev_val = prev_ptr; - } while (prev_ptr != node); + } while (prev_ptr != node_); - if (thread_list_tail == node) { + if (thread_list_tail == node_) { thread_list_tail = tail_prev; } - prev->next = node->next; + prev->next = node_->next; } protected: From abbea575cfcc9e933fbe8f277a5e9f754deb669d Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 25 Nov 2021 20:46:17 -0800 Subject: [PATCH 223/291] hle: kernel: Add a flag for indicating that the kernel is currently shutting down. --- src/core/hle/kernel/k_scheduler.cpp | 10 ++++++++++ src/core/hle/kernel/k_scheduler_lock.h | 10 ++++++++++ src/core/hle/kernel/k_thread.cpp | 5 +++++ src/core/hle/kernel/k_thread.h | 4 ++++ src/core/hle/kernel/kernel.cpp | 18 ++++++++++++++++++ src/core/hle/kernel/kernel.h | 2 ++ 6 files changed, 49 insertions(+) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 6ddbae52c..5423b187e 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -376,11 +376,21 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) { } void KScheduler::DisableScheduling(KernelCore& kernel) { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } + ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 0); GetCurrentThreadPointer(kernel)->DisableDispatch(); } void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } + ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 1); if (GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() > 1) { diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index c571f2992..93c47f1b1 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h @@ -23,6 +23,11 @@ public: } void Lock() { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } + if (IsLockedByCurrentThread()) { // If we already own the lock, we can just increment the count. ASSERT(lock_count > 0); @@ -43,6 +48,11 @@ public: } void Unlock() { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } + ASSERT(IsLockedByCurrentThread()); ASSERT(lock_count > 0); diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 813b92ea4..f69978caf 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1089,6 +1089,11 @@ s32 GetCurrentCoreId(KernelCore& kernel) { } KScopedDisableDispatch::~KScopedDisableDispatch() { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } + if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { auto scheduler = kernel.CurrentScheduler(); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 1cde71e89..be1bc59ae 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -794,6 +794,10 @@ public: class KScopedDisableDispatch { public: [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { + // If we are shutting down the kernel, none of this is relevant anymore. + if (kernel.IsShuttingDown()) { + return; + } GetCurrentThread(kernel).DisableDispatch(); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index cf155ff66..1a47d4716 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -14,6 +14,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/scope_exit.h" #include "common/thread.h" #include "common/thread_worker.h" #include "core/arm/arm_interface.h" @@ -90,6 +91,9 @@ struct KernelCore::Impl { } void Shutdown() { + is_shutting_down.store(true, std::memory_order_relaxed); + SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); + process_list.clear(); // Close all open server ports. @@ -338,7 +342,16 @@ struct KernelCore::Impl { is_phantom_mode_for_singlecore = value; } + bool IsShuttingDown() const { + return is_shutting_down.load(std::memory_order_relaxed); + } + KThread* GetCurrentEmuThread() { + // If we are shutting down the kernel, none of this is relevant anymore. + if (IsShuttingDown()) { + return {}; + } + const auto thread_id = GetCurrentHostThreadID(); if (thread_id >= Core::Hardware::NUM_CPU_CORES) { return GetHostDummyThread(); @@ -754,6 +767,7 @@ struct KernelCore::Impl { std::vector> dummy_threads; bool is_multicore{}; + std::atomic_bool is_shutting_down{}; bool is_phantom_mode_for_singlecore{}; u32 single_core_thread_id{}; @@ -1066,6 +1080,10 @@ bool KernelCore::IsMulticore() const { return impl->is_multicore; } +bool KernelCore::IsShuttingDown() const { + return impl->IsShuttingDown(); +} + void KernelCore::ExceptionalExit() { exception_exited = true; Suspend(true); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3499f8b90..eacf9dc61 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -274,6 +274,8 @@ public: bool IsMulticore() const; + bool IsShuttingDown() const; + void EnterSVCProfile(); void ExitSVCProfile(); From 3c2a451f47c54cb39870f8f106edbdd09b3a458d Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Fri, 26 Nov 2021 18:15:43 +0100 Subject: [PATCH 224/291] hle: kernel: fix scheduling ops from HLE host thread. --- src/core/hle/kernel/k_scheduler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 5423b187e..d3b1b2419 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -240,8 +240,8 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s3 // If the thread is runnable, we want to change its priority in the queue. if (thread->GetRawState() == ThreadState::Runnable) { - GetPriorityQueue(kernel).ChangePriority( - old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread); + GetPriorityQueue(kernel).ChangePriority(old_priority, + thread == kernel.GetCurrentEmuThread(), thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(kernel); } @@ -360,7 +360,7 @@ void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) { } bool KScheduler::CanSchedule(KernelCore& kernel) { - return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; + return kernel.GetCurrentEmuThread()->GetDisableDispatchCount() <= 1; } bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { From 894ed14ebc0ca938f2f240f37a5d8f1eda4cd66f Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Fri, 26 Nov 2021 18:16:54 +0100 Subject: [PATCH 225/291] hle: kernel: fix timing on thread preemption --- src/core/hle/kernel/kernel.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1a47d4716..2e4e4cb1c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -251,13 +251,11 @@ struct KernelCore::Impl { KScopedSchedulerLock lock(kernel); global_scheduler_context->PreemptThreads(); } - const auto time_interval = std::chrono::nanoseconds{ - Core::Timing::msToCycles(std::chrono::milliseconds(10))}; + const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; system.CoreTiming().ScheduleEvent(time_interval, preemption_event); }); - const auto time_interval = - std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))}; + const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } From 0d9afdedc4ef9c0861739b04fc9a53926305e1f3 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 26 Nov 2021 15:10:21 -0800 Subject: [PATCH 226/291] hle: kernel: k_thread: Treat dummy threads as a special type. --- src/core/hle/kernel/k_thread.cpp | 4 +++- src/core/hle/kernel/k_thread.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index f69978caf..334487d8a 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -113,6 +113,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s [[fallthrough]]; case ThreadType::HighPriority: [[fallthrough]]; + case ThreadType::Dummy: + [[fallthrough]]; case ThreadType::User: ASSERT(((owner == nullptr) || (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); @@ -248,7 +250,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint } ResultCode KThread::InitializeDummyThread(KThread* thread) { - return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); + return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); } ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index be1bc59ae..94b87bef1 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -48,6 +48,7 @@ enum class ThreadType : u32 { Kernel = 1, HighPriority = 2, User = 3, + Dummy = 100, // Special thread type for emulation purposes only }; DECLARE_ENUM_FLAG_OPERATORS(ThreadType); From e3d156ab0e020ade2a96ae82eba226d5f187aa2e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 26 Nov 2021 15:35:11 -0800 Subject: [PATCH 227/291] hle: kernel: svc: Fix deadlock that can occur with single core. --- src/core/hle/kernel/svc.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0e79e1be3..359cf515d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -308,12 +308,18 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { - auto& kernel = system.Kernel(); // Create the wait queue. KThreadQueue wait_queue(kernel); + // Get the client session from its handle. + KScopedAutoObject session = + kernel.CurrentProcess()->GetHandleTable().GetObject(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { KScopedSchedulerLock lock(kernel); @@ -321,15 +327,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { // This is a synchronous request, so we should wait for our request to complete. GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); - - { - KScopedAutoObject session = - kernel.CurrentProcess()->GetHandleTable().GetObject(handle); - R_UNLESS(session.IsNotNull(), ResultInvalidHandle); - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), - system.CoreTiming()); - } + session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming()); } return thread->GetWaitResult(); From 42697527ba6e981237f03f850826b5e722917414 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 28 Nov 2021 00:40:25 -0800 Subject: [PATCH 228/291] hle: kernel: k_thread: Rename sleeping_queue -> wait_queue. --- src/core/hle/kernel/k_thread.cpp | 22 +++++++++++----------- src/core/hle/kernel/k_thread.h | 8 ++------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 334487d8a..245437387 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -161,7 +161,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s base_priority = prio; // Initialize sleeping queue. - sleeping_queue = nullptr; + wait_queue = nullptr; // Set suspend flags. suspend_request_flags = 0; @@ -333,7 +333,7 @@ void KThread::OnTimer() { // If we're waiting, cancel the wait. if (GetState() == ThreadState::Waiting) { - sleeping_queue->CancelWait(this, ResultTimedOut, false); + wait_queue->CancelWait(this, ResultTimedOut, false); } } @@ -570,7 +570,7 @@ ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) { } // Update the pinned waiter list. - ThreadQueueImplForKThreadSetProperty wait_queue(kernel, std::addressof(pinned_waiter_list)); + ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, std::addressof(pinned_waiter_list)); { bool retry_update{}; do { @@ -605,7 +605,7 @@ ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) { // Wait until the thread isn't pinned any more. pinned_waiter_list.push_back(GetCurrentThread(kernel)); - GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); + GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_)); } else { // If the thread isn't pinned, release the scheduler lock and retry until it's // not current. @@ -663,7 +663,7 @@ void KThread::WaitCancel() { // Check if we're waiting and cancellable. if (this->GetState() == ThreadState::Waiting && cancellable) { wait_cancelled = false; - sleeping_queue->CancelWait(this, ResultCancelled, true); + wait_queue->CancelWait(this, ResultCancelled, true); } else { // Otherwise, note that we cancelled a wait. wait_cancelled = true; @@ -1002,7 +1002,7 @@ ResultCode KThread::Sleep(s64 timeout) { ASSERT(this == GetCurrentThreadPointer(kernel)); ASSERT(timeout > 0); - ThreadQueueImplForKThreadSleep wait_queue(kernel); + ThreadQueueImplForKThreadSleep wait_queue_(kernel); { // Setup the scheduling lock and sleep. KScopedSchedulerLockAndSleep slp(kernel, this, timeout); @@ -1014,7 +1014,7 @@ ResultCode KThread::Sleep(s64 timeout) { } // Wait for the sleep to end. - this->BeginWait(std::addressof(wait_queue)); + this->BeginWait(std::addressof(wait_queue_)); SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); } @@ -1026,7 +1026,7 @@ void KThread::BeginWait(KThreadQueue* queue) { SetState(ThreadState::Waiting); // Set our wait queue. - sleeping_queue = queue; + wait_queue = queue; } void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { @@ -1035,7 +1035,7 @@ void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCod // If we're waiting, notify our queue that we're available. if (GetState() == ThreadState::Waiting) { - sleeping_queue->NotifyAvailable(this, signaled_object, wait_result_); + wait_queue->NotifyAvailable(this, signaled_object, wait_result_); } } @@ -1045,7 +1045,7 @@ void KThread::EndWait(ResultCode wait_result_) { // If we're waiting, notify our queue that we're available. if (GetState() == ThreadState::Waiting) { - sleeping_queue->EndWait(this, wait_result_); + wait_queue->EndWait(this, wait_result_); } } @@ -1055,7 +1055,7 @@ void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) { // If we're waiting, notify our queue that we're available. if (GetState() == ThreadState::Waiting) { - sleeping_queue->CancelWait(this, wait_result_, cancel_timer_task); + wait_queue->CancelWait(this, wait_result_, cancel_timer_task); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 94b87bef1..c8a08bd71 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -453,10 +453,6 @@ public: return per_core_priority_queue_entry[core]; } - void SetSleepingQueue(KThreadQueue* q) { - sleeping_queue = q; - } - [[nodiscard]] bool IsKernelThread() const { return GetActiveCore() == 3; } @@ -604,7 +600,7 @@ public: } void ClearWaitQueue() { - sleeping_queue = nullptr; + wait_queue = nullptr; } void BeginWait(KThreadQueue* queue); @@ -715,7 +711,7 @@ private: s64 schedule_count{}; s64 last_scheduled_tick{}; std::array per_core_priority_queue_entry{}; - KThreadQueue* sleeping_queue{}; + KThreadQueue* wait_queue{}; WaiterList waiter_list{}; WaiterList pinned_waiter_list{}; KThread* lock_owner{}; From a2384a18fad1d7541c0e11b3c6d762aa46cd1b15 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 28 Nov 2021 00:40:50 -0800 Subject: [PATCH 229/291] hle: kernel: k_thread: Skip reschedule on DisableDispatch with SC. --- src/core/hle/kernel/k_thread.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 245437387..03175e5c2 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1096,6 +1096,11 @@ KScopedDisableDispatch::~KScopedDisableDispatch() { return; } + // Skip the reschedule if single-core, as dispatch tracking is disabled here. + if (!Settings::values.use_multi_core.GetValue()) { + return; + } + if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { auto scheduler = kernel.CurrentScheduler(); From efb5de1c5f1c26de7d8346caf4bf09cc48f9906a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 28 Nov 2021 13:05:18 -0800 Subject: [PATCH 230/291] hle: kernel: service_thread: Use std::jthread. - Fixes a potential deadlock on service thread shutdown. --- src/core/hle/kernel/service_thread.cpp | 37 +++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 6721b6276..00657bc4c 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -25,24 +25,27 @@ public: void QueueSyncRequest(KSession& session, std::shared_ptr&& context); private: - std::vector threads; + std::vector threads; std::queue> requests; std::mutex queue_mutex; - std::condition_variable condition; + std::condition_variable_any condition; const std::string service_name; - bool stop{}; }; ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) : service_name{name} { - for (std::size_t i = 0; i < num_threads; ++i) - threads.emplace_back([this, &kernel] { + for (std::size_t i = 0; i < num_threads; ++i) { + threads.emplace_back([this, &kernel](std::stop_token stop_token) { Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); // Wait for first request before trying to acquire a render context { std::unique_lock lock{queue_mutex}; - condition.wait(lock, [this] { return stop || !requests.empty(); }); + condition.wait(lock, stop_token, [this] { return !requests.empty(); }); + } + + if (stop_token.stop_requested()) { + return; } kernel.RegisterHostThread(); @@ -52,10 +55,16 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std { std::unique_lock lock{queue_mutex}; - condition.wait(lock, [this] { return stop || !requests.empty(); }); - if (stop || requests.empty()) { + condition.wait(lock, stop_token, [this] { return !requests.empty(); }); + + if (stop_token.stop_requested()) { return; } + + if (requests.empty()) { + continue; + } + task = std::move(requests.front()); requests.pop(); } @@ -63,6 +72,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std task(); } }); + } } void ServiceThread::Impl::QueueSyncRequest(KSession& session, @@ -87,16 +97,7 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, condition.notify_one(); } -ServiceThread::Impl::~Impl() { - { - std::unique_lock lock{queue_mutex}; - stop = true; - } - condition.notify_all(); - for (std::thread& thread : threads) { - thread.join(); - } -} +ServiceThread::Impl::~Impl() = default; ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) : impl{std::make_unique(kernel, num_threads, name)} {} From e596fac6ee174d9e232c1a2291dfb8e8b5825aba Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:36:15 -0800 Subject: [PATCH 231/291] hle: kernel: k_light_lock: Implement CancelWait. - Fixes a crash in Megadimension Neptunia VII. --- src/core/hle/kernel/k_light_lock.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 5e8f1a510..9830506ff 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -16,10 +16,15 @@ class ThreadQueueImplForKLightLock final : public KThreadQueue { public: explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {} - virtual void CancelWait([[maybe_unused]] KThread* waiting_thread, - [[maybe_unused]] ResultCode wait_result, - [[maybe_unused]] bool cancel_timer_task) override { - // Do nothing, waiting to acquire a light lock cannot be canceled. + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Remove the thread as a waiter from its owner. + if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { + owner->RemoveWaiter(waiting_thread); + } + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; @@ -64,7 +69,7 @@ bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } // Add the current thread as a waiter on the owner. - KThread* owner_thread = reinterpret_cast(_owner & ~1ul); + KThread* owner_thread = reinterpret_cast(_owner & ~1ULL); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); From d7f6d516cefed79dea14465abd7c2a0f036f78b9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:42:58 -0800 Subject: [PATCH 232/291] hle: kernel: service_thread: Force stop threads on destruction. --- src/core/hle/kernel/service_thread.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 00657bc4c..03f3dec10 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -97,7 +97,13 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, condition.notify_one(); } -ServiceThread::Impl::~Impl() = default; +ServiceThread::Impl::~Impl() { + condition.notify_all(); + for (auto& thread : threads) { + thread.request_stop(); + thread.join(); + } +} ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) : impl{std::make_unique(kernel, num_threads, name)} {} From 0d1bdfc1d4f9cb9ceecdb2dd9c784a664f6ba0c8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:49:26 -0800 Subject: [PATCH 233/291] hle: kernel: Remove unnecessary virtual specifier on CancelWait. --- src/core/hle/kernel/k_address_arbiter.cpp | 4 ++-- src/core/hle/kernel/k_condition_variable.cpp | 8 ++++---- src/core/hle/kernel/k_light_condition_variable.cpp | 4 ++-- src/core/hle/kernel/k_light_lock.cpp | 4 ++-- src/core/hle/kernel/k_synchronization_object.cpp | 4 ++-- src/core/hle/kernel/k_thread.cpp | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index a4ce99402..783c69858 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -91,8 +91,8 @@ public: explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t) : KThreadQueue(kernel_), m_tree(t) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // If the thread is waiting on an address arbiter, remove it from the tree. if (waiting_thread->IsWaitingForAddressArbiter()) { m_tree->erase(m_tree->iterator_to(*waiting_thread)); diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index f343e3c2f..fcfb74ec1 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -63,8 +63,8 @@ public: explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_) : KThreadQueue(kernel_) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Remove the thread as a waiter from its owner. waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); @@ -82,8 +82,8 @@ public: KernelCore& kernel_, KConditionVariable::ThreadTree* t) : KThreadQueue(kernel_), m_tree(t) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Remove the thread as a waiter from its owner. if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { owner->RemoveWaiter(waiting_thread); diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp index 7319a0ca0..a8001fffc 100644 --- a/src/core/hle/kernel/k_light_condition_variable.cpp +++ b/src/core/hle/kernel/k_light_condition_variable.cpp @@ -18,8 +18,8 @@ public: bool term) : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Only process waits if we're allowed to. if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { return; diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 9830506ff..4620342eb 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -16,8 +16,8 @@ class ThreadQueueImplForKLightLock final : public KThreadQueue { public: explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Remove the thread as a waiter from its owner. if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { owner->RemoveWaiter(waiting_thread); diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index ffeb4b73f..6ae93b0ad 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -46,8 +46,8 @@ public: KThreadQueue::EndWait(waiting_thread, wait_result); } - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Remove all nodes from our list. for (auto i = 0; i < m_count; ++i) { m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 03175e5c2..752592e2e 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -72,8 +72,8 @@ public: explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) : KThreadQueue(kernel_), m_wait_list(wl) {} - virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, - bool cancel_timer_task) override { + void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { // Remove the thread from the wait list. m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); From 2e8d737a96f2326fe773ff29d2103d3a38c62df1 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:51:24 -0800 Subject: [PATCH 234/291] hle: kernel: k_condition_variable: Revert unnecessary style changes. --- src/core/hle/kernel/k_condition_variable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index fcfb74ec1..aadcc297a 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -240,7 +240,7 @@ void KConditionVariable::SignalImpl(KThread* thread) { void KConditionVariable::Signal(u64 cv_key, s32 count) { // Perform signaling. - int num_waiters = 0; + s32 num_waiters{}; { KScopedSchedulerLock sl(kernel); @@ -257,7 +257,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // If we have no waiters, clear the has waiter flag. if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) { - const u32 has_waiter_flag = 0; + const u32 has_waiter_flag{}; WriteToUser(system, cv_key, std::addressof(has_waiter_flag)); } } From 3f8eb44e7d9c5ec97cf7c032f92ed3fa34b5ebaa Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:52:38 -0800 Subject: [PATCH 235/291] hle: kernel: k_light_condition_variable: Revert unnecessary license comment changes. --- src/core/hle/kernel/k_light_condition_variable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h index 65d3bc3e1..5d6d7f128 100644 --- a/src/core/hle/kernel/k_light_condition_variable.h +++ b/src/core/hle/kernel/k_light_condition_variable.h @@ -1,4 +1,4 @@ -// Copyright 2021 yuzu Emulator Project +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. From a63af9860b428b09aa9baf023334d6d1080094f7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:53:51 -0800 Subject: [PATCH 236/291] hle: kernel: Remove unnecessary virtual specifier on EndWait. --- src/core/hle/kernel/k_thread_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 1f13cde83..ccb718e49 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h @@ -29,7 +29,7 @@ class KThreadQueueWithoutEndWait : public KThreadQueue { public: explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {} - virtual void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; + void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; }; } // namespace Kernel From 834c25f4d95c99c614e72b5c342a8a84eb20d7aa Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:54:35 -0800 Subject: [PATCH 237/291] hle: kernel: Remove unnecessary virtual specifier on NotifyAvailable. --- src/core/hle/kernel/k_synchronization_object.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index 6ae93b0ad..e4c5eb74f 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -22,8 +22,8 @@ public: KSynchronizationObject::ThreadListNode* n, s32 c) : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {} - virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, - ResultCode wait_result) override { + void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, + ResultCode wait_result) override { // Determine the sync index, and unlink all nodes. s32 sync_index = -1; for (auto i = 0; i < m_count; ++i) { From 9a9e7dd78ba12908a5c9ae0691c549783251ce53 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:57:09 -0800 Subject: [PATCH 238/291] hle: kernel k_process: Remove unnecessary .at usage with thread pinning methods. --- src/core/hle/kernel/k_process.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index d972c9de0..cb93c7e24 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -259,7 +259,7 @@ public: [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); - return pinned_threads.at(core_id); + return pinned_threads[core_id]; } /// Gets 8 bytes of random data for svcGetInfo RandomEntropy @@ -369,14 +369,14 @@ private: void PinThread(s32 core_id, KThread* thread) { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); ASSERT(thread != nullptr); - ASSERT(pinned_threads.at(core_id) == nullptr); + ASSERT(pinned_threads[core_id] == nullptr); pinned_threads[core_id] = thread; } void UnpinThread(s32 core_id, KThread* thread) { ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); ASSERT(thread != nullptr); - ASSERT(pinned_threads.at(core_id) == thread); + ASSERT(pinned_threads[core_id] == thread); pinned_threads[core_id] = nullptr; } From 257d3c9ecf2730fad3b68918f108fa652061cabd Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 5 Dec 2021 23:59:23 -0800 Subject: [PATCH 239/291] hle: kernel k_scheduler: EnableScheduling: Remove redundant GetCurrentThreadPointer calls. --- src/core/hle/kernel/k_scheduler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index d3b1b2419..277201de4 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -391,10 +391,12 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli return; } - ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 1); + auto* current_thread = GetCurrentThreadPointer(kernel); - if (GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() > 1) { - GetCurrentThreadPointer(kernel)->EnableDispatch(); + ASSERT(current_thread->GetDisableDispatchCount() >= 1); + + if (current_thread->GetDisableDispatchCount() > 1) { + current_thread->EnableDispatch(); } else { RescheduleCores(kernel, cores_needing_scheduling); } From 60bdedc7dd95c06a9277e580007a888453f8735a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Mon, 6 Dec 2021 21:17:02 -0300 Subject: [PATCH 240/291] main: Update video core popup Old version had formatting issues, and I want to provide an answer to the most common reason this pops up in the first place, outdated drivers. --- src/yuzu/main.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 5a9dec8f3..691fa71e3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1301,16 +1301,13 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p case Core::SystemResultStatus::ErrorVideoCore: QMessageBox::critical( this, tr("An error occurred initializing the video core."), - tr("yuzu has encountered an error while running the video core, please see the " - "log for more details." + tr("yuzu has encountered an error while running the video core, " + "this is usually caused by outdated GPU drivers, including integrated ones. " + "Please see the log for more details. " "For more information on accessing the log, please see the following page: " - "How " - "to " - "Upload the Log File." - "Ensure that you have the latest graphics drivers for your GPU.")); - + "" + "How to Upload the Log File. ")); break; - default: if (result > Core::SystemResultStatus::ErrorLoader) { const u16 loader_id = static_cast(Core::SystemResultStatus::ErrorLoader); From d19724688022952c37143dc189240916910b0c6f Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Tue, 7 Dec 2021 07:58:33 -0500 Subject: [PATCH 241/291] make KCodeMemory::GetSourceAddress const Co-authored-by: Mai M. --- src/core/hle/kernel/k_code_memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index e8e83a0e5..c45939afa 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -46,7 +46,7 @@ public: KProcess* GetOwner() const { return m_owner; } - VAddr GetSourceAddress() { + VAddr GetSourceAddress() const { return m_address; } size_t GetSize() const { From e05c86aa3cbd7a0da638111d2520b93b7f757f22 Mon Sep 17 00:00:00 2001 From: itsmeft24 <57544858+itsmeft24@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:58:23 -0500 Subject: [PATCH 242/291] Update k_code_memory.h --- src/core/hle/kernel/k_code_memory.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index c45939afa..e0ba19a53 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -54,13 +54,13 @@ public: } private: - KPageLinkedList m_page_group; - KProcess* m_owner; - VAddr m_address; + KPageLinkedList m_page_group{}; + KProcess* m_owner{}; + VAddr m_address{}; KLightLock m_lock; - bool m_is_initialized; - bool m_is_owner_mapped; - bool m_is_mapped; + bool m_is_initialized{}; + bool m_is_owner_mapped{}; + bool m_is_mapped{}; }; } // namespace Kernel From 47a724780fe1e24bbbd157b1cc821e2232e832d3 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 8 Dec 2021 10:55:11 -0500 Subject: [PATCH 243/291] renderer_vulkan: Add R16G16_UINT - Used by Immortals Fenyx Rising --- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 2 +- src/video_core/vulkan_common/vulkan_device.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 31adada56..e38cfbc6c 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -162,7 +162,7 @@ struct FormatTuple { {VK_FORMAT_UNDEFINED}, // R16_SINT {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT - {VK_FORMAT_UNDEFINED}, // R16G16_UINT + {VK_FORMAT_R16G16_UINT, Attachable | Storage}, // R16G16_UINT {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 70c52aaac..7bf5b6578 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -130,6 +130,7 @@ std::unordered_map GetFormatProperties(vk::Physica VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_SFLOAT, + VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM, From 9ba812485a78c9ec666b5d5d95538c978c3ce4a0 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 8 Dec 2021 15:25:46 -0500 Subject: [PATCH 244/291] profiler: Use QWheelEvent position().toPoint() QWheelEvent::pos() is deprecated. Make use of position().toPoint() instead. --- src/yuzu/debugger/profiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index a8b254199..33110685a 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -163,7 +163,7 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) { } void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { - const auto wheel_position = ev->pos(); + const auto wheel_position = ev->position().toPoint(); MicroProfileMousePosition(wheel_position.x() / x_scale, wheel_position.y() / y_scale, ev->angleDelta().y() / 120); ev->accept(); From ae4869650a4056337e48d6b8c1ddf87240a2bfac Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 9 Dec 2021 13:53:53 -0500 Subject: [PATCH 245/291] maxwell_to_vk: Add ASTC_2D_8X5_UNORM - Used by Lego City Undercover --- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index e38cfbc6c..68ab662d5 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -176,7 +176,7 @@ struct FormatTuple { {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM - {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5_UNORM + {VK_FORMAT_ASTC_8x5_UNORM_BLOCK}, // ASTC_2D_8X5_UNORM {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB From 159842649392a2328de5f258ce742c4361f51f60 Mon Sep 17 00:00:00 2001 From: Feng Chen Date: Fri, 10 Dec 2021 12:03:34 +0800 Subject: [PATCH 246/291] Fix blit image/view not compatible --- src/video_core/texture_cache/texture_cache.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index e195b1e98..5aaeb16ca 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1137,8 +1137,13 @@ typename TextureCache

::BlitImages TextureCache

::GetBlitImages( } while (has_deleted_images); const ImageBase& src_image = slot_images[src_id]; const ImageBase& dst_image = slot_images[dst_id]; + const bool native_bgr = runtime.HasNativeBgr(); if (GetFormatType(dst_info.format) != GetFormatType(dst_image.info.format) || - GetFormatType(src_info.format) != GetFormatType(src_image.info.format)) { + GetFormatType(src_info.format) != GetFormatType(src_image.info.format) || + !VideoCore::Surface::IsViewCompatible(dst_info.format, dst_image.info.format, false, + native_bgr) || + !VideoCore::Surface::IsViewCompatible(src_info.format, src_image.info.format, false, + native_bgr)) { // Make sure the images match the expected format. do { has_deleted_images = false; From eec9aace6091bb8441ad4420b8c7cd9d623fc792 Mon Sep 17 00:00:00 2001 From: Andrea Pappacoda Date: Fri, 10 Dec 2021 12:25:04 +0100 Subject: [PATCH 247/291] build: remove remaining bits of Unicorn Unicorn has been removed in fc6db97a09e2de5eff10131ddcab9cf8fb2f736c --- externals/CMakeLists.txt | 4 ---- externals/find-modules/FindUnicorn.cmake | 18 ------------------ 2 files changed, 22 deletions(-) delete mode 100644 externals/find-modules/FindUnicorn.cmake diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index a76a3d800..64d1e6aec 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -44,10 +44,6 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include) add_library(microprofile INTERFACE) target_include_directories(microprofile INTERFACE ./microprofile) -# Unicorn -add_library(unicorn-headers INTERFACE) -target_include_directories(unicorn-headers INTERFACE ./unicorn/include) - # libusb if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB) add_subdirectory(libusb) diff --git a/externals/find-modules/FindUnicorn.cmake b/externals/find-modules/FindUnicorn.cmake deleted file mode 100644 index a0f2a71f6..000000000 --- a/externals/find-modules/FindUnicorn.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# Exports: -# LIBUNICORN_FOUND -# LIBUNICORN_INCLUDE_DIR -# LIBUNICORN_LIBRARY - -find_path(LIBUNICORN_INCLUDE_DIR - unicorn/unicorn.h - HINTS $ENV{UNICORNDIR} - PATH_SUFFIXES include) - -find_library(LIBUNICORN_LIBRARY - NAMES unicorn - HINTS $ENV{UNICORNDIR}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(unicorn DEFAULT_MSG - LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR) -mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY) From 14110230c70300b9553074c38828ae2e5f98b009 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Fri, 10 Dec 2021 22:44:24 -0500 Subject: [PATCH 248/291] maxwell_to_vk: Add ASTC_2D_5X4_UNORM --- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 68ab662d5..751e4792b 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -177,7 +177,7 @@ struct FormatTuple { {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM {VK_FORMAT_ASTC_8x5_UNORM_BLOCK}, // ASTC_2D_8X5_UNORM - {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM + {VK_FORMAT_ASTC_5x4_UNORM_BLOCK}, // ASTC_2D_5X4_UNORM {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB From b64d28492a24927f0702a7c0481134008b1bf455 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 12 Dec 2021 15:46:42 -0500 Subject: [PATCH 249/291] game_list: Add persistent setting for the favorites row expanded state Previously, the favorites row was always expanded on launch. This change introduces a persistent setting that allows the favorites row's expanded state to be remembered between launches. --- src/yuzu/configuration/config.cpp | 2 ++ src/yuzu/game_list.cpp | 19 +++++++++++++------ src/yuzu/uisettings.h | 3 ++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 463d500c2..0f679c37e 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -776,6 +776,7 @@ void Config::ReadUIGamelistValues() { ReadBasicSetting(UISettings::values.row_1_text_id); ReadBasicSetting(UISettings::values.row_2_text_id); ReadBasicSetting(UISettings::values.cache_game_list); + ReadBasicSetting(UISettings::values.favorites_expanded); const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); for (int i = 0; i < favorites_size; i++) { qt_config->setArrayIndex(i); @@ -1300,6 +1301,7 @@ void Config::SaveUIGamelistValues() { WriteBasicSetting(UISettings::values.row_1_text_id); WriteBasicSetting(UISettings::values.row_2_text_id); WriteBasicSetting(UISettings::values.cache_game_list); + WriteBasicSetting(UISettings::values.favorites_expanded); qt_config->beginWriteArray(QStringLiteral("favorites")); for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { qt_config->setArrayIndex(i); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 1a5e41588..8b5c4a10a 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -173,13 +173,17 @@ void GameList::OnItemExpanded(const QModelIndex& item) { const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir || type == GameListItemType::SysNandDir; - - if (!is_dir) { + const bool is_fave = type == GameListItemType::Favorites; + if (!is_dir && !is_fave) { return; } - - UISettings::values.game_dirs[item.data(GameListDir::GameDirRole).toInt()].expanded = - tree_view->isExpanded(item); + const bool is_expanded = tree_view->isExpanded(item); + if (is_fave) { + UISettings::values.favorites_expanded = is_expanded; + return; + } + const int item_dir_index = item.data(GameListDir::GameDirRole).toInt(); + UISettings::values.game_dirs[item_dir_index].expanded = is_expanded; } // Event in order to filter the gamelist after editing the searchfield @@ -458,10 +462,13 @@ void GameList::DonePopulating(const QStringList& watch_list) { emit ShowList(!IsEmpty()); item_model->invisibleRootItem()->appendRow(new GameListAddDir()); + + // Add favorites row item_model->invisibleRootItem()->insertRow(0, new GameListFavorites()); tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), UISettings::values.favorited_ids.size() == 0); - tree_view->expand(item_model->invisibleRootItem()->child(0)->index()); + tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(), + UISettings::values.favorites_expanded.GetValue()); for (const auto id : UISettings::values.favorited_ids) { AddFavorite(id); } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 936914ef3..a610e7e25 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -74,7 +74,6 @@ struct Values { QString game_dir_deprecated; bool game_dir_deprecated_deepscan; QVector game_dirs; - QVector favorited_ids; QStringList recent_files; QString language; @@ -96,6 +95,8 @@ struct Values { Settings::BasicSetting row_2_text_id{2, "row_2_text_id"}; std::atomic_bool is_game_list_reload_pending{false}; Settings::BasicSetting cache_game_list{true, "cache_game_list"}; + Settings::BasicSetting favorites_expanded{true, "favorites_expanded"}; + QVector favorited_ids; bool configuration_applied; bool reset_to_defaults; From 04301e1a8a825069ebda5eec850b3056d4b45cc8 Mon Sep 17 00:00:00 2001 From: Valeri Date: Mon, 13 Dec 2021 16:49:01 +0300 Subject: [PATCH 250/291] Remove erroneous #pragma once --- src/core/hle/kernel/k_thread_queue.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp index 46f27172b..d5248b547 100644 --- a/src/core/hle/kernel/k_thread_queue.cpp +++ b/src/core/hle/kernel/k_thread_queue.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#pragma once - #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/time_manager.h" From 3c618a330630ccde8233b0bb7d0bc21059829fa8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 08:52:06 -0500 Subject: [PATCH 251/291] input_engine: Remove unnecessary return This is a void function, so it doesn't need this. --- src/input_common/input_engine.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 02272b3f8..fb89f9257 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -116,9 +116,7 @@ public: // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Common::Input::LedStatus led_status) { - return; - } + [[maybe_unused]] const Common::Input::LedStatus led_status) {} // Sets rumble to a controller virtual Common::Input::VibrationError SetRumble( From 479369db43092089b7a8ace65d4eadd78cb56b00 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 08:52:59 -0500 Subject: [PATCH 252/291] input_engine: Remove unnecessary semi-colons Silences -Wextra-semi warnings --- src/input_common/input_engine.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index fb89f9257..c85c72af8 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -138,36 +138,36 @@ public: /// Used for automapping features virtual std::vector GetInputDevices() const { return {}; - }; + } /// Retrieves the button mappings for the given device virtual InputCommon::ButtonMapping GetButtonMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; - }; + } /// Retrieves the analog mappings for the given device virtual InputCommon::AnalogMapping GetAnalogMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; - }; + } /// Retrieves the motion mappings for the given device virtual InputCommon::MotionMapping GetMotionMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; - }; + } /// Retrieves the name of the given input. virtual Common::Input::ButtonNames GetUIName( [[maybe_unused]] const Common::ParamPackage& params) const { return Common::Input::ButtonNames::Engine; - }; + } /// Retrieves the index number of the given hat button direction virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const { return 0; - }; + } void PreSetController(const PadIdentifier& identifier); void PreSetButton(const PadIdentifier& identifier, int button); From 9a104e2b60a764efece235b45c805059a39df357 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 08:54:21 -0500 Subject: [PATCH 253/291] input_engine: Remove callback clearing in constructor The callback map is a member variable, so this will always be empty on initial construction. --- src/input_common/input_engine.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index c85c72af8..44accd0be 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -102,9 +102,7 @@ struct InputIdentifier { class InputEngine { public: - explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) { - callback_list.clear(); - } + explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {} virtual ~InputEngine() = default; From 2b92d22bda767c7c723935c357bea474f8e2d2f8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:05:23 -0500 Subject: [PATCH 254/291] input_engine: std::move engine name where applicable We can allow the name to be moved into, allowing allocations to be avoided. --- src/input_common/drivers/gc_adapter.cpp | 2 +- src/input_common/drivers/gc_adapter.h | 6 +++--- src/input_common/drivers/keyboard.cpp | 2 +- src/input_common/drivers/keyboard.h | 4 ++-- src/input_common/drivers/mouse.cpp | 2 +- src/input_common/drivers/mouse.h | 4 ++-- src/input_common/drivers/sdl_driver.cpp | 2 +- src/input_common/drivers/sdl_driver.h | 12 ++++++------ src/input_common/drivers/tas_input.cpp | 2 +- src/input_common/drivers/tas_input.h | 6 +++--- src/input_common/drivers/touch_screen.cpp | 2 +- src/input_common/drivers/touch_screen.h | 4 ++-- src/input_common/drivers/udp_client.cpp | 2 +- src/input_common/drivers/udp_client.h | 6 +++--- src/input_common/input_engine.h | 2 +- 15 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 8b6574223..451147755 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -69,7 +69,7 @@ private: libusb_device_handle* handle{}; }; -GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { +GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) { if (usb_adapter_handle) { return; } diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 8dc51d2e5..3c4f0396c 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -22,10 +22,10 @@ namespace InputCommon { class LibUSBContext; class LibUSBDeviceHandle; -class GCAdapter : public InputCommon::InputEngine { +class GCAdapter : public InputEngine { public: - explicit GCAdapter(const std::string& input_engine_); - ~GCAdapter(); + explicit GCAdapter(std::string input_engine_); + ~GCAdapter() override; Common::Input::VibrationError SetRumble( const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 23b0c0ccf..4c1e5bbec 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = { .pad = 1, }; -Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { +Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) { // Keyboard is broken into 3 diferent sets: // key: Unfiltered intended for controllers. // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index ad123b136..3856c882c 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -12,9 +12,9 @@ namespace InputCommon { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class Keyboard final : public InputCommon::InputEngine { +class Keyboard final : public InputEngine { public: - explicit Keyboard(const std::string& input_engine_); + explicit Keyboard(std::string input_engine_); /** * Sets the status of all buttons bound with the key to pressed diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 752118e97..aa69216c8 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { +Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) { PreSetController(identifier); PreSetAxis(identifier, mouse_axis_x); PreSetAxis(identifier, mouse_axis_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 4a1fd2fd9..040446178 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -27,9 +27,9 @@ enum class MouseButton { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class Mouse final : public InputCommon::InputEngine { +class Mouse final : public InputEngine { public: - explicit Mouse(const std::string& input_engine_); + explicit Mouse(std::string input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1052ed394..1bae6cdc8 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() { joystick_map.clear(); } -SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { +SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d03ff4b84..c6fffe374 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController; using SDL_Joystick = struct _SDL_Joystick; using SDL_JoystickID = s32; +namespace InputCommon { + +class SDLJoystick; + using ButtonBindings = std::array, 17>; using ZButtonBindings = std::array, 2>; -namespace InputCommon { - -class SDLJoystick; - -class SDLDriver : public InputCommon::InputEngine { +class SDLDriver : public InputEngine { public: /// Initializes and registers SDL device factories - SDLDriver(const std::string& input_engine_); + explicit SDLDriver(std::string input_engine_); /// Unregisters SDL device factories and shut them down. ~SDLDriver() override; diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..a2bedc951 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -47,7 +47,7 @@ constexpr std::array, 20> text_to_tas_but {"KEY_ZR", TasButton::TRIGGER_ZR}, }; -Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { +Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) { for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { PadIdentifier identifier{ .guid = Common::UUID{}, diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..9a7f98727 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -81,10 +81,10 @@ enum class TasState { Stopped, }; -class Tas final : public InputCommon::InputEngine { +class Tas final : public InputEngine { public: - explicit Tas(const std::string& input_engine_); - ~Tas(); + explicit Tas(std::string input_engine_); + ~Tas() override; /** * Changes the input status that will be stored in each frame diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 45b3086f6..880781825 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { +TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 25c11e8bf..bf395c40b 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -12,9 +12,9 @@ namespace InputCommon { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class TouchScreen final : public InputCommon::InputEngine { +class TouchScreen final : public InputEngine { public: - explicit TouchScreen(const std::string& input_engine_); + explicit TouchScreen(std::string input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index fdee0f2d5..4ab991a7d 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) { socket->Loop(); } -UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { +UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) { LOG_INFO(Input, "Udp Initialization started"); ReloadSockets(); } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 5d483f26b..1adc947c4 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -49,10 +49,10 @@ struct DeviceStatus { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class UDPClient final : public InputCommon::InputEngine { +class UDPClient final : public InputEngine { public: - explicit UDPClient(const std::string& input_engine_); - ~UDPClient(); + explicit UDPClient(std::string input_engine_); + ~UDPClient() override; void ReloadSockets(); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 44accd0be..b21adfabf 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -102,7 +102,7 @@ struct InputIdentifier { class InputEngine { public: - explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {} + explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {} virtual ~InputEngine() = default; From 38f3442ea56a3ac9447924c015c2a9ade0f5bb83 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:09:03 -0500 Subject: [PATCH 255/291] input_engine: Pass VibrationStatus by const reference in SetRumble() Avoids creating copies of the struct where not necessary. --- src/common/input.h | 6 ++---- src/input_common/drivers/gc_adapter.cpp | 4 ++-- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 6 ++++-- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/input_engine.h | 2 +- src/input_common/input_poller.cpp | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index eaee0bdea..12d5d976f 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -266,11 +266,9 @@ class OutputDevice { public: virtual ~OutputDevice() = default; - virtual void SetLED([[maybe_unused]] LedStatus led_status) { - return; - } + virtual void SetLED([[maybe_unused]] LedStatus led_status) {} - virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { + virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) { return VibrationError::NotSupported; } diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 451147755..7ab4540a8 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, - const Common::Input::VibrationStatus vibration) { +Common::Input::VibrationError GCAdapter::SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 3c4f0396c..7ce1912a3 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -28,7 +28,7 @@ public: ~GCAdapter() override; Common::Input::VibrationError SetRumble( - const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1bae6cdc8..a9219dbf2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -491,8 +491,9 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, - const Common::Input::VibrationStatus vibration) { + +Common::Input::VibrationError SDLDriver::SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { @@ -526,6 +527,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi return Common::Input::VibrationError::None; } + Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { Common::ParamPackage params{}; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index c6fffe374..e9a5d2e26 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -59,7 +59,7 @@ public: u8 GetHatButtonId(const std::string& direction_name) const override; Common::Input::VibrationError SetRumble( - const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; private: void InitJoystick(int joystick_index); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index b21adfabf..15cd5fa2e 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -119,7 +119,7 @@ public: // Sets rumble to a controller virtual Common::Input::VibrationError SetRumble( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Common::Input::VibrationStatus vibration) { + [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { return Common::Input::VibrationError::NotSupported; } diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 7e4eafded..de63f36b3 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -673,7 +673,7 @@ public: } virtual Common::Input::VibrationError SetVibration( - Common::Input::VibrationStatus vibration_status) { + const Common::Input::VibrationStatus& vibration_status) { return input_engine->SetRumble(identifier, vibration_status); } From 985599e485cbee94eb99d0bfcfdbec5345968b15 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:20:55 -0500 Subject: [PATCH 256/291] input_engine: Pass LedStatus by const reference Avoids copies where reasonably applicable --- src/common/input.h | 2 +- src/input_common/input_engine.h | 2 +- src/input_common/input_poller.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 12d5d976f..0b92449bc 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -266,7 +266,7 @@ class OutputDevice { public: virtual ~OutputDevice() = default; - virtual void SetLED([[maybe_unused]] LedStatus led_status) {} + virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {} virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) { return VibrationError::NotSupported; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 15cd5fa2e..78e7046c7 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -114,7 +114,7 @@ public: // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Common::Input::LedStatus led_status) {} + [[maybe_unused]] const Common::Input::LedStatus& led_status) {} // Sets rumble to a controller virtual Common::Input::VibrationError SetRumble( diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index de63f36b3..c56d5e0c2 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -668,7 +668,7 @@ public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED(Common::Input::LedStatus led_status) { + virtual void SetLED(const Common::Input::LedStatus& led_status) { input_engine->SetLeds(identifier, led_status); } From a92dbec96242fe246de99878b12e217b3087463e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:23:19 -0500 Subject: [PATCH 257/291] input_engine: std::move InputIdentifier in SetCallback() Allows avoiding std::function allocations. --- src/input_common/input_engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 2b2105376..6b057e2f1 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -342,7 +342,7 @@ const std::string& InputEngine::GetEngineName() const { int InputEngine::SetCallback(InputIdentifier input_identifier) { std::lock_guard lock{mutex_callback}; - callback_list.insert_or_assign(last_callback_key, input_identifier); + callback_list.insert_or_assign(last_callback_key, std::move(input_identifier)); return last_callback_key++; } From 755822ceecf2a261a09f486706955bebc23d3917 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:26:44 -0500 Subject: [PATCH 258/291] input_engine: Take BasicMotion by const reference with SetMotion() and TriggerOnMotionChange() Copies the BasicMotion instance once instead of twice. --- src/input_common/drivers/sdl_driver.cpp | 4 ++-- src/input_common/input_engine.cpp | 4 ++-- src/input_common/input_engine.h | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index a9219dbf2..e33a5ff31 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -88,7 +88,7 @@ public: return true; } - BasicMotion GetMotion() { + const BasicMotion& GetMotion() const { return motion; } @@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { if (joystick->UpdateMotion(event.csensor)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetMotion(identifier, 0, joystick->GetMotion()); - }; + } } break; } diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 6b057e2f1..5481607bf 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -91,7 +91,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value TriggerOnBatteryChange(identifier, value); } -void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { +void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) { { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); @@ -286,7 +286,7 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, } void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, - BasicMotion value) { + const BasicMotion& value) { std::lock_guard lock{mutex_callback}; for (const std::pair poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 78e7046c7..f9fa5fec3 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -190,7 +190,7 @@ protected: void SetHatButton(const PadIdentifier& identifier, int button, u8 value); void SetAxis(const PadIdentifier& identifier, int axis, f32 value); void SetBattery(const PadIdentifier& identifier, BatteryLevel value); - void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value); + void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { return "Unknown"; @@ -209,7 +209,8 @@ private: void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); - void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value); + void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, + const BasicMotion& value); bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, From e826e6715a39d10b9560fcbf3cd9081a24ddc870 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:32:55 -0500 Subject: [PATCH 259/291] input_engine: Iterate by reference rather than by value where applicable Avoids creating copies of several object instances (some of which being over 100 bytes in size). --- src/input_common/input_engine.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 5481607bf..fce914348 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -170,19 +170,19 @@ BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) } void InputEngine::ResetButtonState() { - for (std::pair controller : controller_list) { - for (std::pair button : controller.second.buttons) { + for (const auto& controller : controller_list) { + for (const auto& button : controller.second.buttons) { SetButton(controller.first, button.first, false); } - for (std::pair button : controller.second.hat_buttons) { + for (const auto& button : controller.second.hat_buttons) { SetHatButton(controller.first, button.first, false); } } } void InputEngine::ResetAnalogState() { - for (std::pair controller : controller_list) { - for (std::pair axis : controller.second.axes) { + for (const auto& controller : controller_list) { + for (const auto& axis : controller.second.axes) { SetAxis(controller.first, axis.first, 0.0); } } @@ -190,7 +190,7 @@ void InputEngine::ResetAnalogState() { void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { std::lock_guard lock{mutex_callback}; - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) { continue; @@ -218,7 +218,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) { std::lock_guard lock{mutex_callback}; - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) { continue; @@ -247,7 +247,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { std::lock_guard lock{mutex_callback}; - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) { continue; @@ -274,7 +274,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, [[maybe_unused]] BatteryLevel value) { std::lock_guard lock{mutex_callback}; - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) { continue; @@ -288,7 +288,7 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, const BasicMotion& value) { std::lock_guard lock{mutex_callback}; - for (const std::pair poller_pair : callback_list) { + for (const auto& poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) { continue; From e51b852aee249b4f462ba3a769340910aa6a88c7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:34:46 -0500 Subject: [PATCH 260/291] input_engine: Remove left-over namespace qualifiers These types are part of the InputCommon namespace. --- src/input_common/input_engine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index f9fa5fec3..59707e173 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -139,19 +139,19 @@ public: } /// Retrieves the button mappings for the given device - virtual InputCommon::ButtonMapping GetButtonMappingForDevice( + virtual ButtonMapping GetButtonMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; } /// Retrieves the analog mappings for the given device - virtual InputCommon::AnalogMapping GetAnalogMappingForDevice( + virtual AnalogMapping GetAnalogMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; } /// Retrieves the motion mappings for the given device - virtual InputCommon::MotionMapping GetMotionMappingForDevice( + virtual MotionMapping GetMotionMappingForDevice( [[maybe_unused]] const Common::ParamPackage& params) { return {}; } From 4d4a23447688030402dc1499db8a827065154136 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:50:48 -0500 Subject: [PATCH 261/291] input_engine: Avoid redundant map lookups We can use iterators to avoid looking up into maps twice in the getter functions. At the same time we can also avoid copying the ControllerData structs, since they're 264 bytes in size. --- src/input_common/input_engine.cpp | 40 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index fce914348..a4a07d4ac 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -104,68 +104,76 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const B bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), identifier.pad, identifier.port); return false; } - ControllerData controller = controller_list.at(identifier); - if (!controller.buttons.contains(button)) { + const ControllerData& controller = controller_iter->second; + const auto button_iter = controller.buttons.find(button); + if (button_iter == controller.buttons.cend()) { LOG_ERROR(Input, "Invalid button {}", button); return false; } - return controller.buttons.at(button); + return button_iter->second; } bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), identifier.pad, identifier.port); return false; } - ControllerData controller = controller_list.at(identifier); - if (!controller.hat_buttons.contains(button)) { + const ControllerData& controller = controller_iter->second; + const auto hat_iter = controller.hat_buttons.find(button); + if (hat_iter == controller.hat_buttons.cend()) { LOG_ERROR(Input, "Invalid hat button {}", button); return false; } - return (controller.hat_buttons.at(button) & direction) != 0; + return (hat_iter->second & direction) != 0; } f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), identifier.pad, identifier.port); return 0.0f; } - ControllerData controller = controller_list.at(identifier); - if (!controller.axes.contains(axis)) { + const ControllerData& controller = controller_iter->second; + const auto axis_iter = controller.axes.find(axis); + if (axis_iter == controller.axes.cend()) { LOG_ERROR(Input, "Invalid axis {}", axis); return 0.0f; } - return controller.axes.at(axis); + return axis_iter->second; } BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), identifier.pad, identifier.port); return BatteryLevel::Charging; } - ControllerData controller = controller_list.at(identifier); + const ControllerData& controller = controller_iter->second; return controller.battery; } BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), identifier.pad, identifier.port); return {}; } - ControllerData controller = controller_list.at(identifier); + const ControllerData& controller = controller_iter->second; return controller.motions.at(motion); } From a9d39b68952bf3ce9607a5947f056eb990e2b430 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:18:02 -0500 Subject: [PATCH 262/291] input_engine: Simplify PreSet* family of functions We can make use of try_emplace() to insert values only if they don't already exist. --- src/input_common/input_engine.cpp | 20 +++++--------------- src/input_common/input_engine.h | 18 +++++++++--------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index a4a07d4ac..9c17ca4f7 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -10,41 +10,31 @@ namespace InputCommon { void InputEngine::PreSetController(const PadIdentifier& identifier) { std::lock_guard lock{mutex}; - if (!controller_list.contains(identifier)) { - controller_list.insert_or_assign(identifier, ControllerData{}); - } + controller_list.try_emplace(identifier); } void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); - if (!controller.buttons.contains(button)) { - controller.buttons.insert_or_assign(button, false); - } + controller.buttons.try_emplace(button, false); } void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); - if (!controller.hat_buttons.contains(button)) { - controller.hat_buttons.insert_or_assign(button, u8{0}); - } + controller.hat_buttons.try_emplace(button, u8{0}); } void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); - if (!controller.axes.contains(axis)) { - controller.axes.insert_or_assign(axis, 0.0f); - } + controller.axes.try_emplace(axis, 0.0f); } void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); - if (!controller.motions.contains(motion)) { - controller.motions.insert_or_assign(motion, BasicMotion{}); - } + controller.motions.try_emplace(motion); } void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 59707e173..ec8890484 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -23,15 +23,15 @@ struct PadIdentifier { friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default; }; -// Basic motion data containing data from the sensors and a timestamp in microsecons +// Basic motion data containing data from the sensors and a timestamp in microseconds struct BasicMotion { - float gyro_x; - float gyro_y; - float gyro_z; - float accel_x; - float accel_y; - float accel_z; - u64 delta_timestamp; + float gyro_x{}; + float gyro_y{}; + float gyro_z{}; + float accel_x{}; + float accel_y{}; + float accel_z{}; + u64 delta_timestamp{}; }; // Stages of a battery charge @@ -202,7 +202,7 @@ private: std::unordered_map hat_buttons; std::unordered_map axes; std::unordered_map motions; - BatteryLevel battery; + BatteryLevel battery{}; }; void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); From e4de1783e129c705585adf1b88439a5e07b61fb7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:21:37 -0500 Subject: [PATCH 263/291] input_engine: Fix typo in TriggerOnAxisChange() parameter name --- src/input_common/input_engine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index ec8890484..390581c94 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -207,7 +207,7 @@ private: void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); - void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); + void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value); void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, const BasicMotion& value); From c126b0718ca4ffff463c4462ca38f61019df4acf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:41:30 -0500 Subject: [PATCH 264/291] tas_input: Make TasAxes enum an enum class Prevents these values from potentially clashing with anything in other headers. --- src/input_common/drivers/tas_input.cpp | 14 +++++++++----- src/input_common/drivers/tas_input.h | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..1a38616b4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -15,7 +15,7 @@ namespace InputCommon::TasInput { -enum TasAxes : u8 { +enum class Tas::TasAxis : u8 { StickX, StickY, SubstickX, @@ -205,10 +205,10 @@ void Tas::UpdateThread() { const int button = static_cast(i); SetButton(identifier, button, button_status); } - SetAxis(identifier, TasAxes::StickX, command.l_axis.x); - SetAxis(identifier, TasAxes::StickY, command.l_axis.y); - SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); - SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); + SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x); + SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y); + SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x); + SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y); } } else { is_running = Settings::values.tas_loop.GetValue(); @@ -267,6 +267,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const { return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); } +void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) { + SetAxis(identifier, static_cast(axis), value); +} + void Tas::StartStop() { if (!Settings::values.tas_enable) { return; diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..c44c39da9 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -128,6 +128,8 @@ public: std::tuple GetStatus() const; private: + enum class TasAxis : u8; + struct TASCommand { u64 buttons{}; TasAnalog l_axis{}; @@ -182,6 +184,9 @@ private: */ std::string WriteCommandAxis(TasAnalog data) const; + /// Sets an axis for a particular pad to the given value. + void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); + size_t script_length{0}; bool is_recording{false}; bool is_running{false}; From d52ad96ce348656b2ea7de8b8a85badfa86d2860 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:49:06 -0500 Subject: [PATCH 265/291] tas_input: Amend -Wdocumentation warnings Parameters shouldn't have the colon by their name. --- src/input_common/drivers/tas_input.cpp | 10 +++--- src/input_common/drivers/tas_input.h | 48 ++++++++++++++------------ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1a38616b4..19d8ccae3 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -238,13 +238,13 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { return {x, y}; } -u64 Tas::ReadCommandButtons(const std::string& data) const { - std::stringstream button_text(data); - std::string line; +u64 Tas::ReadCommandButtons(const std::string& line) const { + std::stringstream button_text(line); + std::string button_line; u64 buttons = 0; - while (std::getline(button_text, line, ';')) { + while (std::getline(button_text, button_line, ';')) { for (auto [text, tas_button] : text_to_tas_button) { - if (text == line) { + if (text == button_line) { buttons |= static_cast(tas_button); break; } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c44c39da9..7c2c4a21b 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -88,39 +88,39 @@ public: /** * Changes the input status that will be stored in each frame - * @param buttons: bitfield with the status of the buttons - * @param left_axis: value of the left axis - * @param right_axis: value of the right axis + * @param buttons Bitfield with the status of the buttons + * @param left_axis Value of the left axis + * @param right_axis Value of the right axis */ void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); // Main loop that records or executes input void UpdateThread(); - // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles + // Sets the flag to start or stop the TAS command execution and swaps controllers profiles void StartStop(); - // Stop the TAS and reverts any controller profile + // Stop the TAS and reverts any controller profile void Stop(); - // Sets the flag to reload the file and start from the begining in the next update + // Sets the flag to reload the file and start from the beginning in the next update void Reset(); /** * Sets the flag to enable or disable recording of inputs - * @return Returns true if the current recording status is enabled + * @returns true if the current recording status is enabled */ bool Record(); /** * Saves contents of record_commands on a file - * @param overwrite_file: Indicates if player 1 should be overwritten + * @param overwrite_file Indicates if player 1 should be overwritten */ void SaveRecording(bool overwrite_file); /** * Returns the current status values of TAS playback/recording - * @return Tuple of + * @returns A Tuple of * TasState indicating the current state out of Running ; * Current playback progress ; * Total length of script file currently loaded or being recorded @@ -139,29 +139,31 @@ private: /// Loads TAS files from all players void LoadTasFiles(); - /** Loads TAS file from the specified player - * @param player_index: player number to save the script - * @param file_index: script number of the file + /** + * Loads TAS file from the specified player + * @param player_index Player number to save the script + * @param file_index Script number of the file */ void LoadTasFile(size_t player_index, size_t file_index); - /** Writes a TAS file from the recorded commands - * @param file_name: name of the file to be written + /** + * Writes a TAS file from the recorded commands + * @param file_name Name of the file to be written */ void WriteTasFile(std::u8string file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 - * @param line: string containing axis values with the following format "x;y" - * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 + * @param line String containing axis values with the following format "x;y" + * @returns A TAS analog object with axis values with range from -1.0 to 1.0 */ TasAnalog ReadCommandAxis(const std::string& line) const; /** * Parses a string containing the button values. Each button is represented by it's text format * specified in text_to_tas_button array - * @param line: string containing button name with the following format "a;b;c;d..." - * @return Returns a u64 with each bit representing the status of a button + * @param line string containing button name with the following format "a;b;c;d..." + * @returns A u64 with each bit representing the status of a button */ u64 ReadCommandButtons(const std::string& line) const; @@ -172,17 +174,17 @@ private: /** * Converts an u64 containing the button status into the text equivalent - * @param buttons: bitfield with the status of the buttons - * @return Returns a string with the name of the buttons to be written to the file + * @param buttons Bitfield with the status of the buttons + * @returns A string with the name of the buttons to be written to the file */ std::string WriteCommandButtons(u64 buttons) const; /** * Converts an TAS analog object containing the axis status into the text equivalent - * @param data: value of the axis - * @return A string with the value of the axis to be written to the file + * @param analog Value of the axis + * @returns A string with the value of the axis to be written to the file */ - std::string WriteCommandAxis(TasAnalog data) const; + std::string WriteCommandAxis(TasAnalog analog) const; /// Sets an axis for a particular pad to the given value. void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); From 37a8e2a67eae239b13f10ac56bc42932e9a25b25 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:50:22 -0500 Subject: [PATCH 266/291] tas_input: Remove unused std::smatch variable This also means we can get rid of the dependency on --- src/input_common/drivers/tas_input.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 19d8ccae3..0a504c484 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include -#include #include #include "common/fs/file.h" @@ -93,7 +92,6 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (line.empty()) { continue; } - std::smatch m; std::stringstream linestream(line); std::string segment; From 6be730bdcdf875655973b1a39576e6933fd93eab Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:54:05 -0500 Subject: [PATCH 267/291] tas_input: Use u8string_view instead of u8string Same behavior, but without the potential for extra allocations. --- src/input_common/drivers/tas_input.cpp | 11 ++++++----- src/input_common/drivers/tas_input.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0a504c484..3fdd3649b 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -121,16 +121,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); } -void Tas::WriteTasFile(std::u8string file_name) { +void Tas::WriteTasFile(std::u8string_view file_name) { std::string output_text; for (size_t frame = 0; frame < record_commands.size(); frame++) { const TASCommand& line = record_commands[frame]; output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); } - const auto bytes_written = Common::FS::WriteStringToFile( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, - Common::FS::FileType::TextFile, output_text); + + const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name; + const auto bytes_written = + Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text); if (bytes_written == output_text.size()) { LOG_INFO(Input, "TAS file written to file!"); } else { @@ -252,7 +253,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { } std::string Tas::WriteCommandButtons(u64 buttons) const { - std::string returns = ""; + std::string returns; for (auto [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast(tas_button)) != 0) { returns += fmt::format("{};", text_button); diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 7c2c4a21b..68970dcec 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -150,7 +150,7 @@ private: * Writes a TAS file from the recorded commands * @param file_name Name of the file to be written */ - void WriteTasFile(std::u8string file_name); + void WriteTasFile(std::u8string_view file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 From a515ede2af822a337b95ed0b3987a197664d5180 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:57:51 -0500 Subject: [PATCH 268/291] tas_input: Use istringstream over stringstream This is only using the input facilities, so we don't need to use the fully-fleged stringstream. --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 3fdd3649b..a7d3d0b47 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -85,7 +85,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), Common::FS::FileType::BinaryFile); - std::stringstream command_line(file); + std::istringstream command_line(file); std::string line; int frame_no = 0; while (std::getline(command_line, line, '\n')) { @@ -93,7 +93,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::stringstream linestream(line); + std::istringstream linestream(line); std::string segment; std::vector seglist; From 26ef76213c81b6c2dc8eeeae11e9586f22a76011 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:07:26 -0500 Subject: [PATCH 269/291] tas_input: std::move strings into vector While we're in the same area, we can also avoid performing std::stoi in a loop when it only needs to be performed once. --- src/input_common/drivers/tas_input.cpp | 45 ++++++++++++++------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index a7d3d0b47..d14a43b9e 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -93,27 +93,29 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::istringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ' ')) { - seglist.push_back(segment); + std::vector seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ' ')) { + seg_list.push_back(std::move(segment)); + } } - if (seglist.size() < 4) { + if (seg_list.size() < 4) { continue; } - while (frame_no < std::stoi(seglist.at(0))) { - commands[player_index].push_back({}); + const auto num_frames = std::stoi(seg_list[0]); + while (frame_no < num_frames) { + commands[player_index].emplace_back(); frame_no++; } TASCommand command = { - .buttons = ReadCommandButtons(seglist.at(1)), - .l_axis = ReadCommandAxis(seglist.at(2)), - .r_axis = ReadCommandAxis(seglist.at(3)), + .buttons = ReadCommandButtons(seg_list[1]), + .l_axis = ReadCommandAxis(seg_list[2]), + .r_axis = ReadCommandAxis(seg_list[3]), }; commands[player_index].push_back(command); frame_no++; @@ -223,22 +225,23 @@ void Tas::ClearInput() { } TasAnalog Tas::ReadCommandAxis(const std::string& line) const { - std::stringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ';')) { - seglist.push_back(segment); + std::vector seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ';')) { + seg_list.push_back(std::move(segment)); + } } - const float x = std::stof(seglist.at(0)) / 32767.0f; - const float y = std::stof(seglist.at(1)) / 32767.0f; + const float x = std::stof(seg_list.at(0)) / 32767.0f; + const float y = std::stof(seg_list.at(1)) / 32767.0f; return {x, y}; } u64 Tas::ReadCommandButtons(const std::string& line) const { - std::stringstream button_text(line); + std::istringstream button_text(line); std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { From db9320e7541430dc487e85f40912725bd5b66c8a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:10:56 -0500 Subject: [PATCH 270/291] tas_input: Remove unnecessary includes Gets rid of indirect includes and includes only what the interface needs. --- src/input_common/drivers/tas_input.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 68970dcec..3996fe3a8 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -5,11 +5,11 @@ #pragma once #include +#include +#include #include "common/common_types.h" -#include "common/settings_input.h" #include "input_common/input_engine.h" -#include "input_common/main.h" /* To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below From ddda6ae776e0fab22a3cf70a9f4f5a87df86fda8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:19:24 -0500 Subject: [PATCH 271/291] tas_input: Execute clear() even if empty clear() when empty is simply a no-op, so we can get rid of the check here and let the stdlib do it for us. --- src/input_common/drivers/tas_input.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d14a43b9e..bd4e411c9 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -78,9 +78,8 @@ void Tas::LoadTasFiles() { } void Tas::LoadTasFile(size_t player_index, size_t file_index) { - if (!commands[player_index].empty()) { - commands[player_index].clear(); - } + commands[player_index].clear(); + std::string file = Common::FS::ReadStringFromFile( Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), From 734fb180bb42d361f05d1fab02323de5095e2d8d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:20:23 -0500 Subject: [PATCH 272/291] tas_input: Remove unnecessary semicolon Resolves a -Wextra-semi warning --- src/input_common/drivers/tas_input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index bd4e411c9..1617ba1d4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -65,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi Tas::~Tas() { Stop(); -}; +} void Tas::LoadTasFiles() { script_length = 0; From 54ca48e8b772453814d2e4d49a4ba29a1b46b32d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:36:48 -0500 Subject: [PATCH 273/291] tas_input: Avoid minor copies in Read/WriteCommandButtons() We don't need to copy the whole pair --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1617ba1d4..2094c1feb 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -244,7 +244,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { - for (auto [text, tas_button] : text_to_tas_button) { + for (const auto& [text, tas_button] : text_to_tas_button) { if (text == button_line) { buttons |= static_cast(tas_button); break; @@ -256,7 +256,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string Tas::WriteCommandButtons(u64 buttons) const { std::string returns; - for (auto [text_button, tas_button] : text_to_tas_button) { + for (const auto& [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast(tas_button)) != 0) { returns += fmt::format("{};", text_button); } From 96579e515a8da3eb6c1aab13a4d4ff5d9577605a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 13 Dec 2021 19:04:07 -0500 Subject: [PATCH 274/291] qt_software_keyboard: Fix out of bounds array access We were unconditionally accessing the keyboard_buttons array, even if the bottom_osk_index was for the numberpad, leading to an out of bounds array access. Fix this by accessing the proper array for the current button when the index is for the numberpad. --- src/yuzu/applets/qt_software_keyboard.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index de7f98c4f..c3857fc98 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -475,11 +475,26 @@ void QtSoftwareKeyboardDialog::open() { row = 0; column = 0; - const auto* const curr_button = - keyboard_buttons[static_cast(bottom_osk_index)][row][column]; + switch (bottom_osk_index) { + case BottomOSKIndex::LowerCase: + case BottomOSKIndex::UpperCase: { + const auto* const curr_button = + keyboard_buttons[static_cast(bottom_osk_index)][row][column]; - // This is a workaround for setFocus() randomly not showing focus in the UI - QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); + // This is a workaround for setFocus() randomly not showing focus in the UI + QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); + break; + } + case BottomOSKIndex::NumberPad: { + const auto* const curr_button = numberpad_buttons[row][column]; + + // This is a workaround for setFocus() randomly not showing focus in the UI + QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); + break; + } + default: + break; + } StartInputThread(); } From ccc0a1e621b32827dc6ebf9c0b54a58778cbab52 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Fri, 10 Dec 2021 21:04:18 -0700 Subject: [PATCH 275/291] cmake: refactor ffmpeg searching and handling logic on Linux --- CMakeLists.txt | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a810e11c2..34ba67993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -514,7 +514,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") endif() if (NOT YUZU_USE_BUNDLED_FFMPEG) # Use system installed FFmpeg - find_package(FFmpeg QUIET COMPONENTS ${FFmpeg_COMPONENTS}) + find_package(FFmpeg 4.3 QUIET COMPONENTS ${FFmpeg_COMPONENTS}) if (FFmpeg_FOUND) # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries. @@ -527,7 +527,7 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE) endforeach() else() - message(WARNING "FFmpeg not found, falling back to externals") + message(WARNING "FFmpeg not found or too old, falling back to externals") set(YUZU_USE_BUNDLED_FFMPEG ON) endif() endif() @@ -615,7 +615,7 @@ if (YUZU_USE_BUNDLED_FFMPEG) set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) endif() - if (FFNVCODEC_FOUND AND CUDA_FOUND) + if (FFNVCODEC_FOUND) list(APPEND FFmpeg_HWACCEL_FLAGS --enable-cuvid --enable-ffnvcodec @@ -623,21 +623,20 @@ if (YUZU_USE_BUNDLED_FFMPEG) --enable-hwaccel=h264_nvdec --enable-hwaccel=vp8_nvdec --enable-hwaccel=vp9_nvdec - --extra-cflags=-I${CUDA_INCLUDE_DIRS} - ) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${FFNVCODEC_LIBRARIES} - ${CUDA_LIBRARIES} - ) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${FFNVCODEC_INCLUDE_DIRS} - ${CUDA_INCLUDE_DIRS} - ) - list(APPEND FFmpeg_HWACCEL_LDFLAGS - ${FFNVCODEC_LDFLAGS} - ${CUDA_LDFLAGS} ) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") + # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress + # here we handle the hard-linking senario where CUDA is linked during compilation + if (CUDA_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) + message(STATUS "CUDA libraries found, hard-linking will be performed") + endif(CUDA_FOUND) endif() if (VDPAU_FOUND) From f91b6fbbcb56870f912540550c9517800c152a46 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Fri, 10 Dec 2021 21:26:43 -0700 Subject: [PATCH 276/291] ffmpeg: move the whole tree into externals/ffmpeg/ffmpeg ... * this resolves the todo items in the CMakeLists.txt * a version requirement check for ffmpeg is added to catch issues early * for future-proof reasons, nasm/yasm is now only required when build on x86/AMD64 systems --- .gitmodules | 6 +- CMakeLists.txt | 213 -------------------------------- externals/CMakeLists.txt | 5 + externals/ffmpeg | 1 - externals/ffmpeg/CMakeLists.txt | 209 +++++++++++++++++++++++++++++++ externals/ffmpeg/ffmpeg | 1 + 6 files changed, 218 insertions(+), 217 deletions(-) delete mode 160000 externals/ffmpeg create mode 100644 externals/ffmpeg/CMakeLists.txt create mode 160000 externals/ffmpeg/ffmpeg diff --git a/.gitmodules b/.gitmodules index dc6ed500f..a9cf9a24a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,12 +34,12 @@ [submodule "opus"] path = externals/opus/opus url = https://github.com/xiph/opus.git -[submodule "ffmpeg"] - path = externals/ffmpeg - url = https://git.ffmpeg.org/ffmpeg.git [submodule "SDL"] path = externals/SDL url = https://github.com/libsdl-org/SDL.git [submodule "externals/cpp-httplib"] path = externals/cpp-httplib url = https://github.com/yhirose/cpp-httplib.git +[submodule "externals/ffmpeg/ffmpeg"] + path = externals/ffmpeg/ffmpeg + url = https://git.ffmpeg.org/ffmpeg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 34ba67993..18d553f4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,219 +532,6 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) endif() endif() -if (YUZU_USE_BUNDLED_FFMPEG) - if (NOT WIN32) - # TODO(lat9nq): Move this to externals/ffmpeg/CMakeLists.txt (and move externals/ffmpeg to - # externals/ffmpeg/ffmpeg) - - # Build FFmpeg from externals - message(STATUS "Using FFmpeg from externals") - - # FFmpeg has source that requires one of nasm or yasm to assemble it. - # REQUIRED throws an error if not found here during configuration rather than during compilation. - find_program(ASSEMBLER NAMES nasm yasm) - if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") - message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") - endif() - - find_program(AUTOCONF autoconf) - if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") - message(FATAL_ERROR "Required program `autoconf` not found.") - endif() - - set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg) - set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg) - set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) - make_directory(${FFmpeg_BUILD_DIR}) - - # Read version string from external - file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) - set(FFmpeg_FOUND NO) - if (NOT FFmpeg_VERSION STREQUAL "") - set(FFmpeg_FOUND YES) - endif() - - unset(FFmpeg_LIBRARIES CACHE) - foreach(COMPONENT ${FFmpeg_COMPONENTS}) - set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") - set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") - set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") - - set(FFmpeg_LIBRARIES - ${FFmpeg_LIBRARIES} - ${FFmpeg_${COMPONENT}_LIBRARY} - CACHE PATH "Paths to FFmpeg libraries" FORCE) - endforeach() - - Include(FindPkgConfig REQUIRED) - pkg_check_modules(LIBVA libva) - pkg_check_modules(CUDA cuda) - pkg_check_modules(FFNVCODEC ffnvcodec) - pkg_check_modules(VDPAU vdpau) - - set(FFmpeg_HWACCEL_LIBRARIES) - set(FFmpeg_HWACCEL_FLAGS) - set(FFmpeg_HWACCEL_INCLUDE_DIRS) - set(FFmpeg_HWACCEL_LDFLAGS) - - if(LIBVA_FOUND) - pkg_check_modules(LIBDRM libdrm REQUIRED) - find_package(X11 REQUIRED) - pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) - pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES} - ${X11_LIBRARIES} - ${LIBVA-DRM_LIBRARIES} - ${LIBVA-X11_LIBRARIES} - ${LIBVA_LIBRARIES}) - set(FFmpeg_HWACCEL_FLAGS - --enable-hwaccel=h264_vaapi - --enable-hwaccel=vp8_vaapi - --enable-hwaccel=vp9_vaapi - --enable-libdrm) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS} - ${X11_INCLUDE_DIRS} - ${LIBVA-DRM_INCLUDE_DIRS} - ${LIBVA-X11_INCLUDE_DIRS} - ${LIBVA_INCLUDE_DIRS} - ) - message(STATUS "VA-API found") - else() - set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) - endif() - - if (FFNVCODEC_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-cuvid - --enable-ffnvcodec - --enable-nvdec - --enable-hwaccel=h264_nvdec - --enable-hwaccel=vp8_nvdec - --enable-hwaccel=vp9_nvdec - ) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) - message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") - # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress - # here we handle the hard-linking senario where CUDA is linked during compilation - if (CUDA_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) - message(STATUS "CUDA libraries found, hard-linking will be performed") - endif(CUDA_FOUND) - endif() - - if (VDPAU_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-vdpau - --enable-hwaccel=h264_vdpau - --enable-hwaccel=vp9_vdpau - ) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) - message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") - else() - list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) - endif() - - # `configure` parameters builds only exactly what yuzu needs from FFmpeg - # `--disable-vdpau` is needed to avoid linking issues - add_custom_command( - OUTPUT - ${FFmpeg_MAKEFILE} - COMMAND - /bin/bash ${FFmpeg_PREFIX}/configure - --disable-avdevice - --disable-avfilter - --disable-avformat - --disable-doc - --disable-everything - --disable-ffmpeg - --disable-ffprobe - --disable-network - --disable-postproc - --disable-swresample - --enable-decoder=h264 - --enable-decoder=vp8 - --enable-decoder=vp9 - --cc="${CMAKE_C_COMPILER}" - --cxx="${CMAKE_CXX_COMPILER}" - ${FFmpeg_HWACCEL_FLAGS} - WORKING_DIRECTORY - ${FFmpeg_BUILD_DIR} - ) - unset(FFmpeg_HWACCEL_FLAGS) - - # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child - # with context of the jobserver. Also helps ninja users. - execute_process( - COMMAND - nproc - OUTPUT_VARIABLE - SYSTEM_THREADS) - - set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) - add_custom_command( - OUTPUT - ${FFmpeg_BUILD_LIBRARIES} - COMMAND - make -j${SYSTEM_THREADS} - WORKING_DIRECTORY - ${FFmpeg_BUILD_DIR} - ) - - set(FFmpeg_INCLUDE_DIR - "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" - CACHE PATH "Path to FFmpeg headers" FORCE) - - set(FFmpeg_LDFLAGS - "${FFmpeg_HWACCEL_LDFLAGS}" - CACHE STRING "FFmpeg linker flags" FORCE) - - # ALL makes this custom target build every time - # but it won't actually build if the DEPENDS parameter is up to date - add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) - add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) - link_libraries(${FFmpeg_LIBVA_LIBRARIES}) - set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} - CACHE PATH "Paths to FFmpeg libraries" FORCE) - unset(FFmpeg_BUILD_LIBRARIES) - unset(FFmpeg_HWACCEL_FLAGS) - unset(FFmpeg_HWACCEL_INCLUDE_DIRS) - unset(FFmpeg_HWACCEL_LDFLAGS) - unset(FFmpeg_HWACCEL_LIBRARIES) - - if (FFmpeg_FOUND) - message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") - else() - message(FATAL_ERROR "FFmpeg not found") - endif() - else() # WIN32 - # Use yuzu FFmpeg binaries - set(FFmpeg_EXT_NAME "ffmpeg-4.4") - set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") - download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") - set(FFmpeg_FOUND YES) - set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) - set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) - set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) - set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) - set(FFmpeg_LIBRARIES - ${FFmpeg_LIBRARY_DIR}/swscale.lib - ${FFmpeg_LIBRARY_DIR}/avcodec.lib - ${FFmpeg_LIBRARY_DIR}/avutil.lib - CACHE PATH "Paths to FFmpeg libraries" FORCE) - endif() -endif() - -unset(FFmpeg_COMPONENTS) - # Prefer the -pthread flag on Linux. set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 64d1e6aec..bbbe6667d 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -121,3 +121,8 @@ if (NOT opus_FOUND) message(STATUS "opus 1.3 or newer not found, falling back to externals") add_subdirectory(opus EXCLUDE_FROM_ALL) endif() + +# FFMpeg +if (YUZU_USE_BUNDLED_FFMPEG) + add_subdirectory(ffmpeg) +endif() diff --git a/externals/ffmpeg b/externals/ffmpeg deleted file mode 160000 index 79e8d1702..000000000 --- a/externals/ffmpeg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 79e8d17024e6c6328a40fcee191ffd70798a9c6e diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt new file mode 100644 index 000000000..63896edd5 --- /dev/null +++ b/externals/ffmpeg/CMakeLists.txt @@ -0,0 +1,209 @@ +if (NOT WIN32) + # Build FFmpeg from externals + message(STATUS "Using FFmpeg from externals") + + if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)") + # FFmpeg has source that requires one of nasm or yasm to assemble it. + # REQUIRED throws an error if not found here during configuration rather than during compilation. + find_program(ASSEMBLER NAMES nasm yasm) + if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") + message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") + endif() + endif() + + find_program(AUTOCONF autoconf) + if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") + message(FATAL_ERROR "Required program `autoconf` not found.") + endif() + + set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg) + set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg) + set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) + make_directory(${FFmpeg_BUILD_DIR}) + + # Read version string from external + file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) + set(FFmpeg_FOUND NO) + if (NOT FFmpeg_VERSION STREQUAL "") + set(FFmpeg_FOUND YES) + endif() + + unset(FFmpeg_LIBRARIES CACHE) + foreach(COMPONENT ${FFmpeg_COMPONENTS}) + set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") + set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") + set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") + + set(FFmpeg_LIBRARIES + ${FFmpeg_LIBRARIES} + ${FFmpeg_${COMPONENT}_LIBRARY} + CACHE PATH "Paths to FFmpeg libraries" FORCE) + endforeach() + + Include(FindPkgConfig REQUIRED) + pkg_check_modules(LIBVA libva) + pkg_check_modules(CUDA cuda) + pkg_check_modules(FFNVCODEC ffnvcodec) + pkg_check_modules(VDPAU vdpau) + + set(FFmpeg_HWACCEL_LIBRARIES) + set(FFmpeg_HWACCEL_FLAGS) + set(FFmpeg_HWACCEL_INCLUDE_DIRS) + set(FFmpeg_HWACCEL_LDFLAGS) + + if(LIBVA_FOUND) + pkg_check_modules(LIBDRM libdrm REQUIRED) + find_package(X11 REQUIRED) + pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) + pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES} + ${X11_LIBRARIES} + ${LIBVA-DRM_LIBRARIES} + ${LIBVA-X11_LIBRARIES} + ${LIBVA_LIBRARIES}) + set(FFmpeg_HWACCEL_FLAGS + --enable-hwaccel=h264_vaapi + --enable-hwaccel=vp8_vaapi + --enable-hwaccel=vp9_vaapi + --enable-libdrm) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS} + ${X11_INCLUDE_DIRS} + ${LIBVA-DRM_INCLUDE_DIRS} + ${LIBVA-X11_INCLUDE_DIRS} + ${LIBVA_INCLUDE_DIRS} + ) + message(STATUS "VA-API found") + else() + set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) + endif() + + if (FFNVCODEC_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-cuvid + --enable-ffnvcodec + --enable-nvdec + --enable-hwaccel=h264_nvdec + --enable-hwaccel=vp8_nvdec + --enable-hwaccel=vp9_nvdec + ) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) + message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") + # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress + # here we handle the hard-linking senario where CUDA is linked during compilation + if (CUDA_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) + message(STATUS "CUDA libraries found, hard-linking will be performed") + endif(CUDA_FOUND) + endif() + + if (VDPAU_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-vdpau + --enable-hwaccel=h264_vdpau + --enable-hwaccel=vp9_vdpau + ) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) + message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") + else() + list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) + endif() + + # `configure` parameters builds only exactly what yuzu needs from FFmpeg + # `--disable-vdpau` is needed to avoid linking issues + add_custom_command( + OUTPUT + ${FFmpeg_MAKEFILE} + COMMAND + /bin/bash ${FFmpeg_PREFIX}/configure + --disable-avdevice + --disable-avfilter + --disable-avformat + --disable-doc + --disable-everything + --disable-ffmpeg + --disable-ffprobe + --disable-network + --disable-postproc + --disable-swresample + --enable-decoder=h264 + --enable-decoder=vp8 + --enable-decoder=vp9 + --cc="${CMAKE_C_COMPILER}" + --cxx="${CMAKE_CXX_COMPILER}" + ${FFmpeg_HWACCEL_FLAGS} + WORKING_DIRECTORY + ${FFmpeg_BUILD_DIR} + ) + unset(FFmpeg_HWACCEL_FLAGS) + + # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child + # with context of the jobserver. Also helps ninja users. + execute_process( + COMMAND + nproc + OUTPUT_VARIABLE + SYSTEM_THREADS) + + set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) + add_custom_command( + OUTPUT + ${FFmpeg_BUILD_LIBRARIES} + COMMAND + make -j${SYSTEM_THREADS} + WORKING_DIRECTORY + ${FFmpeg_BUILD_DIR} + ) + + set(FFmpeg_INCLUDE_DIR + "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" + CACHE PATH "Path to FFmpeg headers" FORCE) + + set(FFmpeg_LDFLAGS + "${FFmpeg_HWACCEL_LDFLAGS}" + CACHE STRING "FFmpeg linker flags" FORCE) + + # ALL makes this custom target build every time + # but it won't actually build if the DEPENDS parameter is up to date + add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) + add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) + link_libraries(${FFmpeg_LIBVA_LIBRARIES}) + set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} + CACHE PATH "Paths to FFmpeg libraries" FORCE) + unset(FFmpeg_BUILD_LIBRARIES) + unset(FFmpeg_HWACCEL_FLAGS) + unset(FFmpeg_HWACCEL_INCLUDE_DIRS) + unset(FFmpeg_HWACCEL_LDFLAGS) + unset(FFmpeg_HWACCEL_LIBRARIES) + + if (FFmpeg_FOUND) + message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") + else() + message(FATAL_ERROR "FFmpeg not found") + endif() +else(WIN32) + # Use yuzu FFmpeg binaries + set(FFmpeg_EXT_NAME "ffmpeg-4.4") + set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") + download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") + set(FFmpeg_FOUND YES) + set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) + set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) + set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) + set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) + set(FFmpeg_LIBRARIES + ${FFmpeg_LIBRARY_DIR}/swscale.lib + ${FFmpeg_LIBRARY_DIR}/avcodec.lib + ${FFmpeg_LIBRARY_DIR}/avutil.lib + CACHE PATH "Paths to FFmpeg libraries" FORCE) +endif(WIN32) + +unset(FFmpeg_COMPONENTS) diff --git a/externals/ffmpeg/ffmpeg b/externals/ffmpeg/ffmpeg new file mode 160000 index 000000000..dc91b913b --- /dev/null +++ b/externals/ffmpeg/ffmpeg @@ -0,0 +1 @@ +Subproject commit dc91b913b6260e85e1304c74ff7bb3c22a8c9fb1 From 37f1c766135557387777c3a3f011f824c36015c5 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 12 Dec 2021 02:56:18 -0700 Subject: [PATCH 277/291] CI: fix MinGW installation step --- .ci/scripts/windows/docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index 155d8a5c8..298421a1a 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh @@ -46,7 +46,7 @@ python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/" # copy FFmpeg libraries EXTERNALS_PATH="$(pwd)/build/externals" -FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin" +FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/ffmpeg/bin" find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' # copy libraries from yuzu.exe path From 7783c0aaeffe6cb814fd985afd242a03d533f47f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 20:28:27 -0500 Subject: [PATCH 278/291] input_poller: Remove several unnecessary @param tags Silences quite a bit of -Wdocumentation warnings, given the @param tag is only intended to be used to identify function parameters, not what it contains. --- src/input_common/input_poller.h | 212 ++++++++++++++++---------------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 573f09fde..8a0977d58 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -13,9 +13,6 @@ class Factory; namespace InputCommon { class InputEngine; -/** - * An Input factory. It receives input events and forward them to all input devices it created. - */ class OutputFactory final : public Common::Input::Factory { public: @@ -24,10 +21,10 @@ public: /** * Creates an output device from the parameters given. * @param params contains parameters for creating the device: - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique ouput device with the parameters specified + * - "guid" text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique output device with the parameters specified */ std::unique_ptr Create( const Common::ParamPackage& params) override; @@ -36,6 +33,9 @@ private: std::shared_ptr input_engine; }; +/** + * An Input factory. It receives input events and forward them to all input devices it created. + */ class InputFactory final : public Common::Input::Factory { public: explicit InputFactory(std::shared_ptr input_engine_); @@ -54,16 +54,16 @@ public: * - battery: Contains "battery" * - output: Contains "output" * @param params contains parameters for creating the device: - * @param - "code": the code of the keyboard key to bind with the input - * @param - "button": same as "code" but for controller buttons - * @param - "hat": similar as "button" but it's a group of hat buttons from SDL - * @param - "axis": the axis number of the axis to bind with the input - * @param - "motion": the motion number of the motion to bind with the input - * @param - "axis_x": same as axis but specifing horizontal direction - * @param - "axis_y": same as axis but specifing vertical direction - * @param - "axis_z": same as axis but specifing forward direction - * @param - "battery": Only used as a placeholder to set the input type - * @return an unique input device with the parameters specified + * - "code": the code of the keyboard key to bind with the input + * - "button": same as "code" but for controller buttons + * - "hat": similar as "button" but it's a group of hat buttons from SDL + * - "axis": the axis number of the axis to bind with the input + * - "motion": the motion number of the motion to bind with the input + * - "axis_x": same as axis but specifying horizontal direction + * - "axis_y": same as axis but specifying vertical direction + * - "axis_z": same as axis but specifying forward direction + * - "battery": Only used as a placeholder to set the input type + * @returns a unique input device with the parameters specified */ std::unique_ptr Create(const Common::ParamPackage& params) override; @@ -71,14 +71,14 @@ private: /** * Creates a button device from the parameters given. * @param params contains parameters for creating the device: - * @param - "code": the code of the keyboard key to bind with the input - * @param - "button": same as "code" but for controller buttons - * @param - "toggle": press once to enable, press again to disable - * @param - "inverted": inverts the output of the button - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "code": the code of the keyboard key to bind with the input + * - "button": same as "code" but for controller buttons + * - "toggle": press once to enable, press again to disable + * - "inverted": inverts the output of the button + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateButtonDevice( const Common::ParamPackage& params); @@ -86,14 +86,14 @@ private: /** * Creates a hat button device from the parameters given. * @param params contains parameters for creating the device: - * @param - "button": the controller hat id to bind with the input - * @param - "direction": the direction id to be detected - * @param - "toggle": press once to enable, press again to disable - * @param - "inverted": inverts the output of the button - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "button": the controller hat id to bind with the input + * - "direction": the direction id to be detected + * - "toggle": press once to enable, press again to disable + * - "inverted": inverts the output of the button + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateHatButtonDevice( const Common::ParamPackage& params); @@ -101,19 +101,19 @@ private: /** * Creates a stick device from the parameters given. * @param params contains parameters for creating the device: - * @param - "axis_x": the controller horizontal axis id to bind with the input - * @param - "axis_y": the controller vertical axis id to bind with the input - * @param - "deadzone": the mimimum required value to be detected - * @param - "range": the maximum value required to reach 100% - * @param - "threshold": the mimimum required value to considered pressed - * @param - "offset_x": the amount of offset in the x axis - * @param - "offset_y": the amount of offset in the y axis - * @param - "invert_x": inverts the sign of the horizontal axis - * @param - "invert_y": inverts the sign of the vertical axis - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "axis_x": the controller horizontal axis id to bind with the input + * - "axis_y": the controller vertical axis id to bind with the input + * - "deadzone": the minimum required value to be detected + * - "range": the maximum value required to reach 100% + * - "threshold": the minimum required value to considered pressed + * - "offset_x": the amount of offset in the x axis + * - "offset_y": the amount of offset in the y axis + * - "invert_x": inverts the sign of the horizontal axis + * - "invert_y": inverts the sign of the vertical axis + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateStickDevice( const Common::ParamPackage& params); @@ -121,16 +121,16 @@ private: /** * Creates an analog device from the parameters given. * @param params contains parameters for creating the device: - * @param - "axis": the controller axis id to bind with the input - * @param - "deadzone": the mimimum required value to be detected - * @param - "range": the maximum value required to reach 100% - * @param - "threshold": the mimimum required value to considered pressed - * @param - "offset": the amount of offset in the axis - * @param - "invert": inverts the sign of the axis - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "axis": the controller axis id to bind with the input + * - "deadzone": the minimum required value to be detected + * - "range": the maximum value required to reach 100% + * - "threshold": the minimum required value to considered pressed + * - "offset": the amount of offset in the axis + * - "invert": inverts the sign of the axis + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateAnalogDevice( const Common::ParamPackage& params); @@ -138,20 +138,20 @@ private: /** * Creates a trigger device from the parameters given. * @param params contains parameters for creating the device: - * @param - "button": the controller hat id to bind with the input - * @param - "direction": the direction id to be detected - * @param - "toggle": press once to enable, press again to disable - * @param - "inverted": inverts the output of the button - * @param - "axis": the controller axis id to bind with the input - * @param - "deadzone": the mimimum required value to be detected - * @param - "range": the maximum value required to reach 100% - * @param - "threshold": the mimimum required value to considered pressed - * @param - "offset": the amount of offset in the axis - * @param - "invert": inverts the sign of the axis - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "button": the controller hat id to bind with the input + * - "direction": the direction id to be detected + * - "toggle": press once to enable, press again to disable + * - "inverted": inverts the output of the button + * - "axis": the controller axis id to bind with the input + * - "deadzone": the minimum required value to be detected + * - "range": the maximum value required to reach 100% + * - "threshold": the minimum required value to considered pressed + * - "offset": the amount of offset in the axis + * - "invert": inverts the sign of the axis + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateTriggerDevice( const Common::ParamPackage& params); @@ -159,23 +159,23 @@ private: /** * Creates a touch device from the parameters given. * @param params contains parameters for creating the device: - * @param - "button": the controller hat id to bind with the input - * @param - "direction": the direction id to be detected - * @param - "toggle": press once to enable, press again to disable - * @param - "inverted": inverts the output of the button - * @param - "axis_x": the controller horizontal axis id to bind with the input - * @param - "axis_y": the controller vertical axis id to bind with the input - * @param - "deadzone": the mimimum required value to be detected - * @param - "range": the maximum value required to reach 100% - * @param - "threshold": the mimimum required value to considered pressed - * @param - "offset_x": the amount of offset in the x axis - * @param - "offset_y": the amount of offset in the y axis - * @param - "invert_x": inverts the sign of the horizontal axis - * @param - "invert_y": inverts the sign of the vertical axis - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "button": the controller hat id to bind with the input + * - "direction": the direction id to be detected + * - "toggle": press once to enable, press again to disable + * - "inverted": inverts the output of the button + * - "axis_x": the controller horizontal axis id to bind with the input + * - "axis_y": the controller vertical axis id to bind with the input + * - "deadzone": the minimum required value to be detected + * - "range": the maximum value required to reach 100% + * - "threshold": the minimum required value to considered pressed + * - "offset_x": the amount of offset in the x axis + * - "offset_y": the amount of offset in the y axis + * - "invert_x": inverts the sign of the horizontal axis + * - "invert_y": inverts the sign of the vertical axis + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateTouchDevice( const Common::ParamPackage& params); @@ -183,10 +183,10 @@ private: /** * Creates a battery device from the parameters given. * @param params contains parameters for creating the device: - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateBatteryDevice( const Common::ParamPackage& params); @@ -194,21 +194,21 @@ private: /** * Creates a motion device from the parameters given. * @param params contains parameters for creating the device: - * @param - "axis_x": the controller horizontal axis id to bind with the input - * @param - "axis_y": the controller vertical axis id to bind with the input - * @param - "axis_z": the controller fordward axis id to bind with the input - * @param - "deadzone": the mimimum required value to be detected - * @param - "range": the maximum value required to reach 100% - * @param - "offset_x": the amount of offset in the x axis - * @param - "offset_y": the amount of offset in the y axis - * @param - "offset_z": the amount of offset in the z axis - * @param - "invert_x": inverts the sign of the horizontal axis - * @param - "invert_y": inverts the sign of the vertical axis - * @param - "invert_z": inverts the sign of the fordward axis - * @param - "guid": text string for identifing controllers - * @param - "port": port of the connected device - * @param - "pad": slot of the connected controller - * @return an unique input device with the parameters specified + * - "axis_x": the controller horizontal axis id to bind with the input + * - "axis_y": the controller vertical axis id to bind with the input + * - "axis_z": the controller forward axis id to bind with the input + * - "deadzone": the minimum required value to be detected + * - "range": the maximum value required to reach 100% + * - "offset_x": the amount of offset in the x axis + * - "offset_y": the amount of offset in the y axis + * - "offset_z": the amount of offset in the z axis + * - "invert_x": inverts the sign of the horizontal axis + * - "invert_y": inverts the sign of the vertical axis + * - "invert_z": inverts the sign of the forward axis + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified */ std::unique_ptr CreateMotionDevice(Common::ParamPackage params); From 6497fbfa96d7c9ee5e0a18d6eccc9cc137991d1a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 20:31:57 -0500 Subject: [PATCH 279/291] input_mapping: Amend specification of parameters param tags are supposed to specify the parameter name without any quoting. Silences several -Wdocumentation warnings. --- src/input_common/input_mapping.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h index 44eb8ad9a..93564b5f8 100644 --- a/src/input_common/input_mapping.h +++ b/src/input_common/input_mapping.h @@ -14,8 +14,8 @@ public: MappingFactory(); /** - * Resets all varables to beggin the mapping process - * @param "type": type of input desired to be returned + * Resets all variables to begin the mapping process + * @param type type of input desired to be returned */ void BeginMapping(Polling::InputType type); @@ -24,8 +24,8 @@ public: /** * Registers mapping input data from the driver - * @param "data": An struct containing all the information needed to create a proper - * ParamPackage + * @param data A struct containing all the information needed to create a proper + * ParamPackage */ void RegisterInput(const MappingData& data); @@ -34,42 +34,42 @@ public: private: /** - * If provided data satisfies the requeriments it will push an element to the input_queue + * If provided data satisfies the requirements it will push an element to the input_queue * Supported input: * - Button: Creates a basic button ParamPackage * - HatButton: Creates a basic hat button ParamPackage * - Analog: Creates a basic analog ParamPackage - * @param "data": An struct containing all the information needed to create a proper + * @param data A struct containing all the information needed to create a proper * ParamPackage */ void RegisterButton(const MappingData& data); /** - * If provided data satisfies the requeriments it will push an element to the input_queue + * If provided data satisfies the requirements it will push an element to the input_queue * Supported input: * - Button, HatButton: Pass the data to RegisterButton * - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage - * @param "data": An struct containing all the information needed to create a proper - * ParamPackage + * @param data A struct containing all the information needed to create a proper + * ParamPackage */ void RegisterStick(const MappingData& data); /** - * If provided data satisfies the requeriments it will push an element to the input_queue + * If provided data satisfies the requirements it will push an element to the input_queue * Supported input: * - Button, HatButton: Pass the data to RegisterButton * - Analog: Stores the first two axis and on the third axis creates a basic Motion * ParamPackage * - Motion: Creates a basic Motion ParamPackage - * @param "data": An struct containing all the information needed to create a proper - * ParamPackage + * @param data A struct containing all the information needed to create a proper + * ParamPackage */ void RegisterMotion(const MappingData& data); /** * Returns true if driver can be mapped - * @param "data": An struct containing all the information needed to create a proper - * ParamPackage + * @param data A struct containing all the information needed to create a proper + * ParamPackage */ bool IsDriverValid(const MappingData& data) const; From 5e7e38ac72853eb8477913fb2dda0a2b3f61f85f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 20:37:45 -0500 Subject: [PATCH 280/291] input_poller: Add missing override specifiers --- src/input_common/input_poller.cpp | 39 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index c56d5e0c2..7b370335f 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -12,8 +12,7 @@ namespace InputCommon { class DummyInput final : public Common::Input::InputDevice { public: - explicit DummyInput() {} - ~DummyInput() {} + explicit DummyInput() = default; }; class InputFromButton final : public Common::Input::InputDevice { @@ -33,7 +32,7 @@ public: callback_key = input_engine->SetCallback(input_identifier); } - ~InputFromButton() { + ~InputFromButton() override { input_engine->DeleteCallback(callback_key); } @@ -45,7 +44,7 @@ public: }; } - void ForceUpdate() { + void ForceUpdate() override { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Button, .button_status = GetStatus(), @@ -94,7 +93,7 @@ public: callback_key = input_engine->SetCallback(input_identifier); } - ~InputFromHatButton() { + ~InputFromHatButton() override { input_engine->DeleteCallback(callback_key); } @@ -106,7 +105,7 @@ public: }; } - void ForceUpdate() { + void ForceUpdate() override { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Button, .button_status = GetStatus(), @@ -167,7 +166,7 @@ public: callback_key_y = input_engine->SetCallback(y_input_identifier); } - ~InputFromStick() { + ~InputFromStick() override { input_engine->DeleteCallback(callback_key_x); input_engine->DeleteCallback(callback_key_y); } @@ -190,7 +189,7 @@ public: return status; } - void ForceUpdate() { + void ForceUpdate() override { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), @@ -266,7 +265,7 @@ public: callback_key_y = input_engine->SetCallback(y_input_identifier); } - ~InputFromTouch() { + ~InputFromTouch() override { input_engine->DeleteCallback(callback_key_button); input_engine->DeleteCallback(callback_key_x); input_engine->DeleteCallback(callback_key_y); @@ -352,7 +351,7 @@ public: axis_callback_key = input_engine->SetCallback(axis_input_identifier); } - ~InputFromTrigger() { + ~InputFromTrigger() override { input_engine->DeleteCallback(callback_key_button); input_engine->DeleteCallback(axis_callback_key); } @@ -419,7 +418,7 @@ public: callback_key = input_engine->SetCallback(input_identifier); } - ~InputFromAnalog() { + ~InputFromAnalog() override { input_engine->DeleteCallback(callback_key); } @@ -466,7 +465,7 @@ public: callback_key = input_engine->SetCallback(input_identifier); } - ~InputFromBattery() { + ~InputFromBattery() override { input_engine->DeleteCallback(callback_key); } @@ -474,7 +473,7 @@ public: return static_cast(input_engine->GetBattery(identifier)); } - void ForceUpdate() { + void ForceUpdate() override { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Battery, .battery_status = GetStatus(), @@ -518,7 +517,7 @@ public: callback_key = input_engine->SetCallback(input_identifier); } - ~InputFromMotion() { + ~InputFromMotion() override { input_engine->DeleteCallback(callback_key); } @@ -593,7 +592,7 @@ public: callback_key_z = input_engine->SetCallback(z_input_identifier); } - ~InputFromAxisMotion() { + ~InputFromAxisMotion() override { input_engine->DeleteCallback(callback_key_x); input_engine->DeleteCallback(callback_key_y); input_engine->DeleteCallback(callback_key_z); @@ -618,7 +617,7 @@ public: return status; } - void ForceUpdate() { + void ForceUpdate() override { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), @@ -668,16 +667,16 @@ public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED(const Common::Input::LedStatus& led_status) { + void SetLED(const Common::Input::LedStatus& led_status) override { input_engine->SetLeds(identifier, led_status); } - virtual Common::Input::VibrationError SetVibration( - const Common::Input::VibrationStatus& vibration_status) { + Common::Input::VibrationError SetVibration( + const Common::Input::VibrationStatus& vibration_status) override { return input_engine->SetRumble(identifier, vibration_status); } - virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) { + Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override { return input_engine->SetPollingMode(identifier, polling_mode); } From 54eafbaf172309d92c6b2c5069de23fc534dd2d2 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 20:43:09 -0500 Subject: [PATCH 281/291] common/input: Remove unnecessary returns Given these return void, these can be omitted. --- src/common/input.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 0b92449bc..848ad7b81 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -236,14 +236,10 @@ public: virtual ~InputDevice() = default; // Request input device to update if necessary - virtual void SoftUpdate() { - return; - } + virtual void SoftUpdate() {} // Force input device to update data regardless of the current state - virtual void ForceUpdate() { - return; - } + virtual void ForceUpdate() {} // Sets the function to be triggered when input changes void SetCallback(InputCallback callback_) { From 4af413623b4551d5c8c5ab223250427ce8a0beaf Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 13 Dec 2021 20:45:18 -0500 Subject: [PATCH 282/291] common/cpu_detect: Remove CPU family and model We currently do not make use of these fields, remove them for now. --- src/common/x64/cpu_detect.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index fccd2eee5..fbeacc7e2 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -71,9 +71,6 @@ static CPUCaps Detect() { else caps.manufacturer = Manufacturer::Unknown; - u32 family = {}; - u32 model = {}; - __cpuid(cpu_id, 0x80000000); u32 max_ex_fn = cpu_id[0]; @@ -84,15 +81,6 @@ static CPUCaps Detect() { // Detect family and other miscellaneous features if (max_std_fn >= 1) { __cpuid(cpu_id, 0x00000001); - family = (cpu_id[0] >> 8) & 0xf; - model = (cpu_id[0] >> 4) & 0xf; - if (family == 0xf) { - family += (cpu_id[0] >> 20) & 0xff; - } - if (family >= 6) { - model += ((cpu_id[0] >> 16) & 0xf) << 4; - } - if ((cpu_id[3] >> 25) & 1) caps.sse = true; if ((cpu_id[3] >> 26) & 1) From e05d2a70b24e550d67fcdd24aae7094ad41745f8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 21:09:28 -0500 Subject: [PATCH 283/291] common/input: Avoid numerous large copies of CallbackStatus CallbackStatus instances aren't the cheapest things to copy around (relative to everything else), given that they're currently 520 bytes in size and are currently copied numerous times when callbacks are invoked. Instead, we can pass the status by const reference to avoid all the copying. --- src/common/input.h | 4 +- src/core/hid/emulated_console.cpp | 21 ++-- src/core/hid/emulated_console.h | 4 +- src/core/hid/emulated_controller.cpp | 95 +++++++++++-------- src/core/hid/emulated_controller.h | 13 ++- src/core/hid/emulated_devices.cpp | 66 +++++++------ src/core/hid/emulated_devices.h | 11 +-- .../helpers/stick_from_buttons.cpp | 75 +++++++++------ .../helpers/touch_from_buttons.cpp | 11 ++- 9 files changed, 171 insertions(+), 129 deletions(-) diff --git a/src/common/input.h b/src/common/input.h index 848ad7b81..f775a4c01 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -227,7 +227,7 @@ struct CallbackStatus { // Triggered once every input change struct InputCallback { - std::function on_change; + std::function on_change; }; /// An abstract class template for an input device (a button, an analog input, etc.). @@ -247,7 +247,7 @@ public: } // Triggers the function set in the callback - void TriggerOnChange(CallbackStatus status) { + void TriggerOnChange(const CallbackStatus& status) { if (callback.on_change) { callback.on_change(status); } diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 80db8e9c6..685ec080c 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -66,9 +66,10 @@ void EmulatedConsole::ReloadInput() { motion_devices = Common::Input::CreateDevice(motion_params); if (motion_devices) { - Common::Input::InputCallback motion_callback{ - [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; - motion_devices->SetCallback(motion_callback); + motion_devices->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); }, + }); } // Unique index for identifying touch device source @@ -78,9 +79,12 @@ void EmulatedConsole::ReloadInput() { if (!touch_device) { continue; } - Common::Input::InputCallback touch_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; - touch_device->SetCallback(touch_callback); + touch_device->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetTouch(callback, index); + }, + }); index++; } } @@ -127,7 +131,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { ReloadInput(); } -void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { +void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { std::lock_guard lock{mutex}; auto& raw_status = console.motion_values.raw_status; auto& emulated = console.motion_values.emulated; @@ -162,8 +166,7 @@ void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { TriggerOnChange(ConsoleTriggerType::Motion); } -void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, - [[maybe_unused]] std::size_t index) { +void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= console.touch_values.size()) { return; } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index bb3d7ab90..3afd284d5 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -155,14 +155,14 @@ private: * Updates the motion status of the console * @param callback A CallbackStatus containing gyro and accelerometer data */ - void SetMotion(Common::Input::CallbackStatus callback); + void SetMotion(const Common::Input::CallbackStatus& callback); /** * Updates the touch status of the console * @param callback A CallbackStatus containing the touch position * @param index Finger ID to be updated */ - void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); + void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Triggers a callback that something has changed on the console status diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index fbb19f230..eb2e0ab4f 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -205,11 +205,12 @@ void EmulatedController::ReloadInput() { continue; } const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; - Common::Input::InputCallback button_callback{ - [this, index, uuid](Common::Input::CallbackStatus callback) { - SetButton(callback, index, uuid); - }}; - button_devices[index]->SetCallback(button_callback); + button_devices[index]->SetCallback({ + .on_change = + [this, index, uuid](const Common::Input::CallbackStatus& callback) { + SetButton(callback, index, uuid); + }, + }); button_devices[index]->ForceUpdate(); } @@ -218,11 +219,12 @@ void EmulatedController::ReloadInput() { continue; } const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; - Common::Input::InputCallback stick_callback{ - [this, index, uuid](Common::Input::CallbackStatus callback) { - SetStick(callback, index, uuid); - }}; - stick_devices[index]->SetCallback(stick_callback); + stick_devices[index]->SetCallback({ + .on_change = + [this, index, uuid](const Common::Input::CallbackStatus& callback) { + SetStick(callback, index, uuid); + }, + }); stick_devices[index]->ForceUpdate(); } @@ -231,11 +233,12 @@ void EmulatedController::ReloadInput() { continue; } const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; - Common::Input::InputCallback trigger_callback{ - [this, index, uuid](Common::Input::CallbackStatus callback) { - SetTrigger(callback, index, uuid); - }}; - trigger_devices[index]->SetCallback(trigger_callback); + trigger_devices[index]->SetCallback({ + .on_change = + [this, index, uuid](const Common::Input::CallbackStatus& callback) { + SetTrigger(callback, index, uuid); + }, + }); trigger_devices[index]->ForceUpdate(); } @@ -243,9 +246,12 @@ void EmulatedController::ReloadInput() { if (!battery_devices[index]) { continue; } - Common::Input::InputCallback battery_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }}; - battery_devices[index]->SetCallback(battery_callback); + battery_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetBattery(callback, index); + }, + }); battery_devices[index]->ForceUpdate(); } @@ -253,9 +259,12 @@ void EmulatedController::ReloadInput() { if (!motion_devices[index]) { continue; } - Common::Input::InputCallback motion_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }}; - motion_devices[index]->SetCallback(motion_callback); + motion_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetMotion(callback, index); + }, + }); motion_devices[index]->ForceUpdate(); } @@ -267,22 +276,24 @@ void EmulatedController::ReloadInput() { if (!tas_button_devices[index]) { continue; } - Common::Input::InputCallback button_callback{ - [this, index, tas_uuid](Common::Input::CallbackStatus callback) { - SetButton(callback, index, tas_uuid); - }}; - tas_button_devices[index]->SetCallback(button_callback); + tas_button_devices[index]->SetCallback({ + .on_change = + [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { + SetButton(callback, index, tas_uuid); + }, + }); } for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) { if (!tas_stick_devices[index]) { continue; } - Common::Input::InputCallback stick_callback{ - [this, index, tas_uuid](Common::Input::CallbackStatus callback) { - SetStick(callback, index, tas_uuid); - }}; - tas_stick_devices[index]->SetCallback(stick_callback); + tas_stick_devices[index]->SetCallback({ + .on_change = + [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { + SetStick(callback, index, tas_uuid); + }, + }); } } @@ -440,7 +451,7 @@ void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage if (index >= button_params.size()) { return; } - button_params[index] = param; + button_params[index] = std::move(param); ReloadInput(); } @@ -448,7 +459,7 @@ void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage p if (index >= stick_params.size()) { return; } - stick_params[index] = param; + stick_params[index] = std::move(param); ReloadInput(); } @@ -456,11 +467,11 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage if (index >= motion_params.size()) { return; } - motion_params[index] = param; + motion_params[index] = std::move(param); ReloadInput(); } -void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, +void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, Common::UUID uuid) { if (index >= controller.button_values.size()) { return; @@ -600,7 +611,7 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, +void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, Common::UUID uuid) { if (index >= controller.stick_values.size()) { return; @@ -650,8 +661,8 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, - Common::UUID uuid) { +void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback, + std::size_t index, Common::UUID uuid) { if (index >= controller.trigger_values.size()) { return; } @@ -692,7 +703,8 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std: TriggerOnChange(ControllerTriggerType::Trigger, true); } -void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback, + std::size_t index) { if (index >= controller.motion_values.size()) { return; } @@ -730,7 +742,8 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std:: TriggerOnChange(ControllerTriggerType::Motion, true); } -void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback, + std::size_t index) { if (index >= controller.battery_values.size()) { return; } @@ -1110,7 +1123,7 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { std::lock_guard lock{mutex}; - callback_list.insert_or_assign(last_callback_key, update_callback); + callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); return last_callback_key++; } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 425b3e7c4..e42aafebc 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -328,35 +328,38 @@ private: * @param callback A CallbackStatus containing the button status * @param index Button ID of the to be updated */ - void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); + void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, + Common::UUID uuid); /** * Updates the analog stick status of the controller * @param callback A CallbackStatus containing the analog stick status * @param index stick ID of the to be updated */ - void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); + void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, + Common::UUID uuid); /** * Updates the trigger status of the controller * @param callback A CallbackStatus containing the trigger status * @param index trigger ID of the to be updated */ - void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); + void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index, + Common::UUID uuid); /** * Updates the motion status of the controller * @param callback A CallbackStatus containing gyro and accelerometer data * @param index motion ID of the to be updated */ - void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); + void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Updates the battery status of the controller * @param callback A CallbackStatus containing the battery status * @param index Button ID of the to be updated */ - void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); + void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Triggers a callback that something has changed on the controller status diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 874780ec2..708480f2d 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -70,50 +70,55 @@ void EmulatedDevices::ReloadInput() { if (!mouse_button_devices[index]) { continue; } - Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { - SetMouseButton(callback, index); - }}; - mouse_button_devices[index]->SetCallback(button_callback); + mouse_button_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetMouseButton(callback, index); + }, + }); } for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) { if (!mouse_analog_devices[index]) { continue; } - Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { - SetMouseAnalog(callback, index); - }}; - mouse_analog_devices[index]->SetCallback(button_callback); + mouse_analog_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetMouseAnalog(callback, index); + }, + }); } if (mouse_stick_device) { - Common::Input::InputCallback button_callback{ - [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }}; - mouse_stick_device->SetCallback(button_callback); + mouse_stick_device->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); }, + }); } for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { if (!keyboard_devices[index]) { continue; } - Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { - SetKeyboardButton(callback, index); - }}; - keyboard_devices[index]->SetCallback(button_callback); + keyboard_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetKeyboardButton(callback, index); + }, + }); } for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) { if (!keyboard_modifier_devices[index]) { continue; } - Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { - SetKeyboardModifier(callback, index); - }}; - keyboard_modifier_devices[index]->SetCallback(button_callback); + keyboard_modifier_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetKeyboardModifier(callback, index); + }, + }); } } @@ -159,7 +164,8 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } -void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, + std::size_t index) { if (index >= device_status.keyboard_values.size()) { return; } @@ -216,7 +222,7 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { } } -void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, +void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= device_status.keyboard_moddifier_values.size()) { return; @@ -286,7 +292,8 @@ void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback TriggerOnChange(DeviceTriggerType::KeyboardModdifier); } -void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback, + std::size_t index) { if (index >= device_status.mouse_button_values.size()) { return; } @@ -347,7 +354,8 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std TriggerOnChange(DeviceTriggerType::Mouse); } -void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback, + std::size_t index) { if (index >= device_status.mouse_analog_values.size()) { return; } @@ -374,7 +382,7 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std TriggerOnChange(DeviceTriggerType::Mouse); } -void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { +void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) { std::lock_guard lock{mutex}; const auto touch_value = TransformToTouch(callback); @@ -435,7 +443,7 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { std::lock_guard lock{mutex}; - callback_list.insert_or_assign(last_callback_key, update_callback); + callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); return last_callback_key++; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index c72327681..790d3b411 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -156,35 +156,34 @@ private: * @param callback A CallbackStatus containing the key status * @param index key ID to be updated */ - void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); + void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Updates the keyboard status of the keyboard device * @param callback A CallbackStatus containing the modifier key status * @param index modifier key ID to be updated */ - void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); + void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Updates the mouse button status of the mouse device * @param callback A CallbackStatus containing the button status * @param index Button ID to be updated */ - void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); + void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Updates the mouse wheel status of the mouse device * @param callback A CallbackStatus containing the wheel status * @param index wheel ID to be updated */ - void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); + void SetMouseAnalog(const Common::Input::CallbackStatus& callback, std::size_t index); /** * Updates the mouse position status of the mouse device * @param callback A CallbackStatus containing the position status - * @param index stick ID to be updated */ - void SetMouseStick(Common::Input::CallbackStatus callback); + void SetMouseStick(const Common::Input::CallbackStatus& callback); /** * Triggers a callback that something has changed on the device status diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 77fcd655e..e23394f5f 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -19,23 +19,36 @@ public: : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { - Common::Input::InputCallback button_up_callback{ - [this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; - Common::Input::InputCallback button_down_callback{ - [this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; - Common::Input::InputCallback button_left_callback{ - [this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; - Common::Input::InputCallback button_right_callback{ - [this](Common::Input::CallbackStatus callback_) { - UpdateRightButtonStatus(callback_); - }}; - Common::Input::InputCallback button_modifier_callback{ - [this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; - up->SetCallback(button_up_callback); - down->SetCallback(button_down_callback); - left->SetCallback(button_left_callback); - right->SetCallback(button_right_callback); - modifier->SetCallback(button_modifier_callback); + up->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateUpButtonStatus(callback_); + }, + }); + down->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateDownButtonStatus(callback_); + }, + }); + left->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateLeftButtonStatus(callback_); + }, + }); + right->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateRightButtonStatus(callback_); + }, + }); + modifier->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateModButtonStatus(callback_); + }, + }); last_x_axis_value = 0.0f; last_y_axis_value = 0.0f; } @@ -133,27 +146,27 @@ public: } } - void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateUpButtonStatus(const Common::Input::CallbackStatus& button_callback) { up_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateDownButtonStatus(const Common::Input::CallbackStatus& button_callback) { down_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateLeftButtonStatus(const Common::Input::CallbackStatus& button_callback) { left_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateRightButtonStatus(const Common::Input::CallbackStatus& button_callback) { right_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) { modifier_status = button_callback.button_status.value; UpdateStatus(); } @@ -265,18 +278,18 @@ private: Button left; Button right; Button modifier; - float modifier_scale; - float modifier_angle; + float modifier_scale{}; + float modifier_angle{}; float angle{}; float goal_angle{}; float amplitude{}; - bool up_status; - bool down_status; - bool left_status; - bool right_status; - bool modifier_status; - float last_x_axis_value; - float last_y_axis_value; + bool up_status{}; + bool down_status{}; + bool left_status{}; + bool right_status{}; + bool modifier_status{}; + float last_x_axis_value{}; + float last_y_axis_value{}; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point last_update; }; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 35d60bc90..ece1e3b32 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -14,10 +14,13 @@ public: using Button = std::unique_ptr; TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { - Common::Input::InputCallback button_up_callback{ - [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; last_button_value = false; - button->SetCallback(button_up_callback); + button->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + UpdateButtonStatus(callback_); + }, + }); button->ForceUpdate(); } @@ -47,7 +50,7 @@ public: return status; } - void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) { + void UpdateButtonStatus(const Common::Input::CallbackStatus& button_callback) { const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Touch, .touch_status = GetStatus(button_callback.button_status.value), From a2d73eaa107bb5e3cd570e522fc69311468c2c89 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 12 Dec 2021 17:43:10 -0700 Subject: [PATCH 284/291] video_core/codecs: skip decoders that use hw frames ... ... this would resolve some edge-cases where multiple devices are present and ffmpeg is unable to auto-supply the hw surfaces --- src/video_core/command_classes/codecs/codec.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 2a532b883..439c47209 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -130,6 +130,12 @@ bool Codec::CreateGpuAvDevice() { } if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { av_codec_ctx->pix_fmt = config->pix_fmt; + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { + // skip zero-copy decoders, we don't currently support them + LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.", + av_hwdevice_get_type_name(type), config->methods); + continue; + } LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); return true; } @@ -251,6 +257,9 @@ void Codec::Decode() { final_frame->format = PREFERRED_GPU_FMT; const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0); ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret); + // null the hw frame context to prevent the buffer from being deleted + // and leaving a dangling reference in the av_codec_ctx + initial_frame->hw_frames_ctx = nullptr; } else { final_frame = std::move(initial_frame); } From dd72e4dce4641498bd7e73f09afd7d90961c435d Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 12 Dec 2021 18:28:52 -0700 Subject: [PATCH 285/291] CI: fix CI on Linux --- .ci/scripts/windows/docker.sh | 5 ++--- externals/ffmpeg/CMakeLists.txt | 2 +- src/video_core/command_classes/codecs/codec.cpp | 3 --- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index 298421a1a..584b9b39f 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh @@ -41,12 +41,11 @@ for i in package/*.exe; do done pip3 install pefile -python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/" -python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/" +python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" # copy FFmpeg libraries EXTERNALS_PATH="$(pwd)/build/externals" -FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/ffmpeg/bin" +FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' # copy libraries from yuzu.exe path diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 63896edd5..7da89d2c5 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -17,7 +17,7 @@ if (NOT WIN32) endif() set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg) - set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg) + set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build) set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) make_directory(${FFmpeg_BUILD_DIR}) diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 439c47209..868b82f9b 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -257,9 +257,6 @@ void Codec::Decode() { final_frame->format = PREFERRED_GPU_FMT; const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0); ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret); - // null the hw frame context to prevent the buffer from being deleted - // and leaving a dangling reference in the av_codec_ctx - initial_frame->hw_frames_ctx = nullptr; } else { final_frame = std::move(initial_frame); } From 7f965172c5cd4f891e1f2025050cbf9492dbf5c8 Mon Sep 17 00:00:00 2001 From: Valeri Date: Mon, 13 Dec 2021 23:23:34 +0300 Subject: [PATCH 286/291] input/SDL: Update SDL hints SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED is no longer needed thanks to new default in SDL 2.0.18. SDL_HINT_JOYSTICK_HIDAPI_XBOX is reported to cause conflicts with native driver Xbox driver on Linux, and Xbox controllers don't benefit from hidapi anyways. --- src/input_common/drivers/sdl_driver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1052ed394..24fd3ab92 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -403,10 +403,11 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and // not a generic one - SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - // Turn off Pro controller home led - SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native + // driver on Linux. + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; From 6aac5d4c27411a43200e0a9c0f96b2ec7fac9b7c Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 14 Dec 2021 19:20:07 -0600 Subject: [PATCH 287/291] core/hid: Fix faulty analog triggers --- src/core/hid/emulated_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index eb2e0ab4f..93372445b 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -670,7 +670,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac const auto trigger_value = TransformToTrigger(callback); // Only read trigger values that have the same uuid or are pressed once - if (controller.stick_values[index].uuid != uuid) { + if (controller.trigger_values[index].uuid != uuid) { if (!trigger_value.pressed.value) { return; } @@ -686,7 +686,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac return; } - const auto trigger = controller.trigger_values[index]; + const auto& trigger = controller.trigger_values[index]; switch (index) { case Settings::NativeTrigger::LTrigger: From 44b3abdfc0d746a13443b3c386f0ce971d0148ce Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Tue, 14 Dec 2021 23:49:25 -0800 Subject: [PATCH 288/291] yuzu/main: Fix host memory byte units. GB to GiB I have `134850146304` bytes of ram and Yuzu was saying that I had `125.59 GB` of ram. But `125.59` is actually the amount of gi**bi**bytes I have. In gi**ga**bytes I would have `134.9`. Additionally, I changed the `1024 / 1024 / 1024` here into the `_GiB` user-literals that I added a while ago(#6519). https://www.wolframalpha.com/input/?i=134850146304+bytes --- src/yuzu/main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index cc84ea11c..df736513b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -77,6 +77,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/fs/fs.h" #include "common/fs/fs_paths.h" #include "common/fs/path_util.h" +#include "common/literals.h" #include "common/logging/backend.h" #include "common/logging/filter.h" #include "common/logging/log.h" @@ -134,6 +135,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/main.h" #include "yuzu/uisettings.h" +using namespace Common::Literals; + #ifdef USE_DISCORD_PRESENCE #include "yuzu/discord_impl.h" #endif @@ -259,10 +262,9 @@ GMainWindow::GMainWindow() LOG_INFO(Frontend, "Host CPU: {}", cpu_string); #endif LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); - LOG_INFO(Frontend, "Host RAM: {:.2f} GB", - Common::GetMemInfo().TotalPhysicalMemory / 1024.0f / 1024 / 1024); - LOG_INFO(Frontend, "Host Swap: {:.2f} GB", - Common::GetMemInfo().TotalSwapMemory / 1024.0f / 1024 / 1024); + LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", + Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); + LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); UpdateWindowTitle(); show(); From 2f32133ad5e13503c56bc5c910407a27cc23908b Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 15 Dec 2021 00:02:53 -0800 Subject: [PATCH 289/291] Revert "video_core/codecs: refactor ffmpeg searching and handling in cmake" --- .ci/scripts/windows/docker.sh | 5 +- .gitmodules | 6 +- CMakeLists.txt | 218 +++++++++++++++++- externals/CMakeLists.txt | 5 - externals/ffmpeg | 1 + externals/ffmpeg/CMakeLists.txt | 209 ----------------- externals/ffmpeg/ffmpeg | 1 - .../command_classes/codecs/codec.cpp | 6 - 8 files changed, 223 insertions(+), 228 deletions(-) create mode 160000 externals/ffmpeg delete mode 100644 externals/ffmpeg/CMakeLists.txt delete mode 160000 externals/ffmpeg/ffmpeg diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index 584b9b39f..155d8a5c8 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh @@ -41,11 +41,12 @@ for i in package/*.exe; do done pip3 install pefile -python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" +python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/" +python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/" # copy FFmpeg libraries EXTERNALS_PATH="$(pwd)/build/externals" -FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" +FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin" find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' # copy libraries from yuzu.exe path diff --git a/.gitmodules b/.gitmodules index a9cf9a24a..dc6ed500f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,12 +34,12 @@ [submodule "opus"] path = externals/opus/opus url = https://github.com/xiph/opus.git +[submodule "ffmpeg"] + path = externals/ffmpeg + url = https://git.ffmpeg.org/ffmpeg.git [submodule "SDL"] path = externals/SDL url = https://github.com/libsdl-org/SDL.git [submodule "externals/cpp-httplib"] path = externals/cpp-httplib url = https://github.com/yhirose/cpp-httplib.git -[submodule "externals/ffmpeg/ffmpeg"] - path = externals/ffmpeg/ffmpeg - url = https://git.ffmpeg.org/ffmpeg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 18d553f4d..a810e11c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -514,7 +514,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") endif() if (NOT YUZU_USE_BUNDLED_FFMPEG) # Use system installed FFmpeg - find_package(FFmpeg 4.3 QUIET COMPONENTS ${FFmpeg_COMPONENTS}) + find_package(FFmpeg QUIET COMPONENTS ${FFmpeg_COMPONENTS}) if (FFmpeg_FOUND) # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries. @@ -527,11 +527,225 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE) endforeach() else() - message(WARNING "FFmpeg not found or too old, falling back to externals") + message(WARNING "FFmpeg not found, falling back to externals") set(YUZU_USE_BUNDLED_FFMPEG ON) endif() endif() +if (YUZU_USE_BUNDLED_FFMPEG) + if (NOT WIN32) + # TODO(lat9nq): Move this to externals/ffmpeg/CMakeLists.txt (and move externals/ffmpeg to + # externals/ffmpeg/ffmpeg) + + # Build FFmpeg from externals + message(STATUS "Using FFmpeg from externals") + + # FFmpeg has source that requires one of nasm or yasm to assemble it. + # REQUIRED throws an error if not found here during configuration rather than during compilation. + find_program(ASSEMBLER NAMES nasm yasm) + if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") + message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") + endif() + + find_program(AUTOCONF autoconf) + if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") + message(FATAL_ERROR "Required program `autoconf` not found.") + endif() + + set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg) + set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg) + set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) + make_directory(${FFmpeg_BUILD_DIR}) + + # Read version string from external + file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) + set(FFmpeg_FOUND NO) + if (NOT FFmpeg_VERSION STREQUAL "") + set(FFmpeg_FOUND YES) + endif() + + unset(FFmpeg_LIBRARIES CACHE) + foreach(COMPONENT ${FFmpeg_COMPONENTS}) + set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") + set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") + set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") + + set(FFmpeg_LIBRARIES + ${FFmpeg_LIBRARIES} + ${FFmpeg_${COMPONENT}_LIBRARY} + CACHE PATH "Paths to FFmpeg libraries" FORCE) + endforeach() + + Include(FindPkgConfig REQUIRED) + pkg_check_modules(LIBVA libva) + pkg_check_modules(CUDA cuda) + pkg_check_modules(FFNVCODEC ffnvcodec) + pkg_check_modules(VDPAU vdpau) + + set(FFmpeg_HWACCEL_LIBRARIES) + set(FFmpeg_HWACCEL_FLAGS) + set(FFmpeg_HWACCEL_INCLUDE_DIRS) + set(FFmpeg_HWACCEL_LDFLAGS) + + if(LIBVA_FOUND) + pkg_check_modules(LIBDRM libdrm REQUIRED) + find_package(X11 REQUIRED) + pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) + pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES} + ${X11_LIBRARIES} + ${LIBVA-DRM_LIBRARIES} + ${LIBVA-X11_LIBRARIES} + ${LIBVA_LIBRARIES}) + set(FFmpeg_HWACCEL_FLAGS + --enable-hwaccel=h264_vaapi + --enable-hwaccel=vp8_vaapi + --enable-hwaccel=vp9_vaapi + --enable-libdrm) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS} + ${X11_INCLUDE_DIRS} + ${LIBVA-DRM_INCLUDE_DIRS} + ${LIBVA-X11_INCLUDE_DIRS} + ${LIBVA_INCLUDE_DIRS} + ) + message(STATUS "VA-API found") + else() + set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) + endif() + + if (FFNVCODEC_FOUND AND CUDA_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-cuvid + --enable-ffnvcodec + --enable-nvdec + --enable-hwaccel=h264_nvdec + --enable-hwaccel=vp8_nvdec + --enable-hwaccel=vp9_nvdec + --extra-cflags=-I${CUDA_INCLUDE_DIRS} + ) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${FFNVCODEC_LIBRARIES} + ${CUDA_LIBRARIES} + ) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${FFNVCODEC_INCLUDE_DIRS} + ${CUDA_INCLUDE_DIRS} + ) + list(APPEND FFmpeg_HWACCEL_LDFLAGS + ${FFNVCODEC_LDFLAGS} + ${CUDA_LDFLAGS} + ) + message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") + endif() + + if (VDPAU_FOUND) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-vdpau + --enable-hwaccel=h264_vdpau + --enable-hwaccel=vp9_vdpau + ) + list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) + message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") + else() + list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) + endif() + + # `configure` parameters builds only exactly what yuzu needs from FFmpeg + # `--disable-vdpau` is needed to avoid linking issues + add_custom_command( + OUTPUT + ${FFmpeg_MAKEFILE} + COMMAND + /bin/bash ${FFmpeg_PREFIX}/configure + --disable-avdevice + --disable-avfilter + --disable-avformat + --disable-doc + --disable-everything + --disable-ffmpeg + --disable-ffprobe + --disable-network + --disable-postproc + --disable-swresample + --enable-decoder=h264 + --enable-decoder=vp8 + --enable-decoder=vp9 + --cc="${CMAKE_C_COMPILER}" + --cxx="${CMAKE_CXX_COMPILER}" + ${FFmpeg_HWACCEL_FLAGS} + WORKING_DIRECTORY + ${FFmpeg_BUILD_DIR} + ) + unset(FFmpeg_HWACCEL_FLAGS) + + # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child + # with context of the jobserver. Also helps ninja users. + execute_process( + COMMAND + nproc + OUTPUT_VARIABLE + SYSTEM_THREADS) + + set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) + add_custom_command( + OUTPUT + ${FFmpeg_BUILD_LIBRARIES} + COMMAND + make -j${SYSTEM_THREADS} + WORKING_DIRECTORY + ${FFmpeg_BUILD_DIR} + ) + + set(FFmpeg_INCLUDE_DIR + "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" + CACHE PATH "Path to FFmpeg headers" FORCE) + + set(FFmpeg_LDFLAGS + "${FFmpeg_HWACCEL_LDFLAGS}" + CACHE STRING "FFmpeg linker flags" FORCE) + + # ALL makes this custom target build every time + # but it won't actually build if the DEPENDS parameter is up to date + add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) + add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) + link_libraries(${FFmpeg_LIBVA_LIBRARIES}) + set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} + CACHE PATH "Paths to FFmpeg libraries" FORCE) + unset(FFmpeg_BUILD_LIBRARIES) + unset(FFmpeg_HWACCEL_FLAGS) + unset(FFmpeg_HWACCEL_INCLUDE_DIRS) + unset(FFmpeg_HWACCEL_LDFLAGS) + unset(FFmpeg_HWACCEL_LIBRARIES) + + if (FFmpeg_FOUND) + message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") + else() + message(FATAL_ERROR "FFmpeg not found") + endif() + else() # WIN32 + # Use yuzu FFmpeg binaries + set(FFmpeg_EXT_NAME "ffmpeg-4.4") + set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") + download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") + set(FFmpeg_FOUND YES) + set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) + set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) + set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) + set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) + set(FFmpeg_LIBRARIES + ${FFmpeg_LIBRARY_DIR}/swscale.lib + ${FFmpeg_LIBRARY_DIR}/avcodec.lib + ${FFmpeg_LIBRARY_DIR}/avutil.lib + CACHE PATH "Paths to FFmpeg libraries" FORCE) + endif() +endif() + +unset(FFmpeg_COMPONENTS) + # Prefer the -pthread flag on Linux. set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index bbbe6667d..64d1e6aec 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -121,8 +121,3 @@ if (NOT opus_FOUND) message(STATUS "opus 1.3 or newer not found, falling back to externals") add_subdirectory(opus EXCLUDE_FROM_ALL) endif() - -# FFMpeg -if (YUZU_USE_BUNDLED_FFMPEG) - add_subdirectory(ffmpeg) -endif() diff --git a/externals/ffmpeg b/externals/ffmpeg new file mode 160000 index 000000000..79e8d1702 --- /dev/null +++ b/externals/ffmpeg @@ -0,0 +1 @@ +Subproject commit 79e8d17024e6c6328a40fcee191ffd70798a9c6e diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt deleted file mode 100644 index 7da89d2c5..000000000 --- a/externals/ffmpeg/CMakeLists.txt +++ /dev/null @@ -1,209 +0,0 @@ -if (NOT WIN32) - # Build FFmpeg from externals - message(STATUS "Using FFmpeg from externals") - - if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)") - # FFmpeg has source that requires one of nasm or yasm to assemble it. - # REQUIRED throws an error if not found here during configuration rather than during compilation. - find_program(ASSEMBLER NAMES nasm yasm) - if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") - message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") - endif() - endif() - - find_program(AUTOCONF autoconf) - if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") - message(FATAL_ERROR "Required program `autoconf` not found.") - endif() - - set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg) - set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build) - set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) - make_directory(${FFmpeg_BUILD_DIR}) - - # Read version string from external - file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) - set(FFmpeg_FOUND NO) - if (NOT FFmpeg_VERSION STREQUAL "") - set(FFmpeg_FOUND YES) - endif() - - unset(FFmpeg_LIBRARIES CACHE) - foreach(COMPONENT ${FFmpeg_COMPONENTS}) - set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") - set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") - set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") - - set(FFmpeg_LIBRARIES - ${FFmpeg_LIBRARIES} - ${FFmpeg_${COMPONENT}_LIBRARY} - CACHE PATH "Paths to FFmpeg libraries" FORCE) - endforeach() - - Include(FindPkgConfig REQUIRED) - pkg_check_modules(LIBVA libva) - pkg_check_modules(CUDA cuda) - pkg_check_modules(FFNVCODEC ffnvcodec) - pkg_check_modules(VDPAU vdpau) - - set(FFmpeg_HWACCEL_LIBRARIES) - set(FFmpeg_HWACCEL_FLAGS) - set(FFmpeg_HWACCEL_INCLUDE_DIRS) - set(FFmpeg_HWACCEL_LDFLAGS) - - if(LIBVA_FOUND) - pkg_check_modules(LIBDRM libdrm REQUIRED) - find_package(X11 REQUIRED) - pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) - pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES} - ${X11_LIBRARIES} - ${LIBVA-DRM_LIBRARIES} - ${LIBVA-X11_LIBRARIES} - ${LIBVA_LIBRARIES}) - set(FFmpeg_HWACCEL_FLAGS - --enable-hwaccel=h264_vaapi - --enable-hwaccel=vp8_vaapi - --enable-hwaccel=vp9_vaapi - --enable-libdrm) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS} - ${X11_INCLUDE_DIRS} - ${LIBVA-DRM_INCLUDE_DIRS} - ${LIBVA-X11_INCLUDE_DIRS} - ${LIBVA_INCLUDE_DIRS} - ) - message(STATUS "VA-API found") - else() - set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) - endif() - - if (FFNVCODEC_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-cuvid - --enable-ffnvcodec - --enable-nvdec - --enable-hwaccel=h264_nvdec - --enable-hwaccel=vp8_nvdec - --enable-hwaccel=vp9_nvdec - ) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) - message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") - # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress - # here we handle the hard-linking senario where CUDA is linked during compilation - if (CUDA_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) - message(STATUS "CUDA libraries found, hard-linking will be performed") - endif(CUDA_FOUND) - endif() - - if (VDPAU_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-vdpau - --enable-hwaccel=h264_vdpau - --enable-hwaccel=vp9_vdpau - ) - list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) - list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) - message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") - else() - list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) - endif() - - # `configure` parameters builds only exactly what yuzu needs from FFmpeg - # `--disable-vdpau` is needed to avoid linking issues - add_custom_command( - OUTPUT - ${FFmpeg_MAKEFILE} - COMMAND - /bin/bash ${FFmpeg_PREFIX}/configure - --disable-avdevice - --disable-avfilter - --disable-avformat - --disable-doc - --disable-everything - --disable-ffmpeg - --disable-ffprobe - --disable-network - --disable-postproc - --disable-swresample - --enable-decoder=h264 - --enable-decoder=vp8 - --enable-decoder=vp9 - --cc="${CMAKE_C_COMPILER}" - --cxx="${CMAKE_CXX_COMPILER}" - ${FFmpeg_HWACCEL_FLAGS} - WORKING_DIRECTORY - ${FFmpeg_BUILD_DIR} - ) - unset(FFmpeg_HWACCEL_FLAGS) - - # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child - # with context of the jobserver. Also helps ninja users. - execute_process( - COMMAND - nproc - OUTPUT_VARIABLE - SYSTEM_THREADS) - - set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) - add_custom_command( - OUTPUT - ${FFmpeg_BUILD_LIBRARIES} - COMMAND - make -j${SYSTEM_THREADS} - WORKING_DIRECTORY - ${FFmpeg_BUILD_DIR} - ) - - set(FFmpeg_INCLUDE_DIR - "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" - CACHE PATH "Path to FFmpeg headers" FORCE) - - set(FFmpeg_LDFLAGS - "${FFmpeg_HWACCEL_LDFLAGS}" - CACHE STRING "FFmpeg linker flags" FORCE) - - # ALL makes this custom target build every time - # but it won't actually build if the DEPENDS parameter is up to date - add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) - add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) - link_libraries(${FFmpeg_LIBVA_LIBRARIES}) - set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} - CACHE PATH "Paths to FFmpeg libraries" FORCE) - unset(FFmpeg_BUILD_LIBRARIES) - unset(FFmpeg_HWACCEL_FLAGS) - unset(FFmpeg_HWACCEL_INCLUDE_DIRS) - unset(FFmpeg_HWACCEL_LDFLAGS) - unset(FFmpeg_HWACCEL_LIBRARIES) - - if (FFmpeg_FOUND) - message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") - else() - message(FATAL_ERROR "FFmpeg not found") - endif() -else(WIN32) - # Use yuzu FFmpeg binaries - set(FFmpeg_EXT_NAME "ffmpeg-4.4") - set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") - download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") - set(FFmpeg_FOUND YES) - set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) - set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) - set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) - set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) - set(FFmpeg_LIBRARIES - ${FFmpeg_LIBRARY_DIR}/swscale.lib - ${FFmpeg_LIBRARY_DIR}/avcodec.lib - ${FFmpeg_LIBRARY_DIR}/avutil.lib - CACHE PATH "Paths to FFmpeg libraries" FORCE) -endif(WIN32) - -unset(FFmpeg_COMPONENTS) diff --git a/externals/ffmpeg/ffmpeg b/externals/ffmpeg/ffmpeg deleted file mode 160000 index dc91b913b..000000000 --- a/externals/ffmpeg/ffmpeg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dc91b913b6260e85e1304c74ff7bb3c22a8c9fb1 diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 868b82f9b..2a532b883 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -130,12 +130,6 @@ bool Codec::CreateGpuAvDevice() { } if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { av_codec_ctx->pix_fmt = config->pix_fmt; - if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { - // skip zero-copy decoders, we don't currently support them - LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.", - av_hwdevice_get_type_name(type), config->methods); - continue; - } LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); return true; } From 1cdddd17d2b8b9a3889012c9d12324934492acc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Thu, 16 Dec 2021 02:40:30 -0300 Subject: [PATCH 290/291] Changed link --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 691fa71e3..56a9c75da 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1305,7 +1305,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p "this is usually caused by outdated GPU drivers, including integrated ones. " "Please see the log for more details. " "For more information on accessing the log, please see the following page: " - "" + "" "How to Upload the Log File. ")); break; default: From 333ccf23f8aedc6900131f6aa2720d61a01c73fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Thu, 16 Dec 2021 02:57:45 -0300 Subject: [PATCH 291/291] Suggestions from CrusadingNinja --- src/yuzu/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 56a9c75da..d012477e4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1301,8 +1301,8 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p case Core::SystemResultStatus::ErrorVideoCore: QMessageBox::critical( this, tr("An error occurred initializing the video core."), - tr("yuzu has encountered an error while running the video core, " - "this is usually caused by outdated GPU drivers, including integrated ones. " + tr("yuzu has encountered an error while running the video core. " + "This is usually caused by outdated GPU drivers, including integrated ones. " "Please see the log for more details. " "For more information on accessing the log, please see the following page: " ""