diff options
Diffstat (limited to 'src/core')
30 files changed, 1187 insertions, 663 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8f2db5bea..aa9e05089 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -88,6 +88,8 @@ add_library(core STATIC frontend/applets/profile_select.h frontend/applets/software_keyboard.cpp frontend/applets/software_keyboard.h + frontend/applets/web_browser.cpp + frontend/applets/web_browser.h frontend/emu_window.cpp frontend/emu_window.h frontend/framebuffer_layout.cpp @@ -173,6 +175,8 @@ add_library(core STATIC hle/service/am/applets/software_keyboard.h hle/service/am/applets/stub_applet.cpp hle/service/am/applets/stub_applet.h + hle/service/am/applets/web_browser.cpp + hle/service/am/applets/web_browser.h hle/service/am/idle.cpp hle/service/am/idle.h hle/service/am/omm.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index fd10199ec..572814e4b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -30,8 +30,11 @@ #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" #include "core/perf_stats.h" +#include "core/settings.h" #include "core/telemetry_session.h" +#include "frontend/applets/profile_select.h" #include "frontend/applets/software_keyboard.h" +#include "frontend/applets/web_browser.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/gpu.h" #include "video_core/renderer_base.h" @@ -94,6 +97,11 @@ struct System::Impl { CoreTiming::Init(); kernel.Initialize(); + const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()); + Settings::values.custom_rtc_differential = + Settings::values.custom_rtc.value_or(current_time) - current_time; + // Create a default fs if one doesn't already exist. if (virtual_filesystem == nullptr) virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); @@ -103,6 +111,8 @@ struct System::Impl { profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); if (software_keyboard == nullptr) software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); + if (web_browser == nullptr) + web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); auto main_process = Kernel::Process::Create(kernel, "main"); kernel.MakeCurrentProcess(main_process.get()); @@ -199,6 +209,11 @@ struct System::Impl { // Close app loader app_loader.reset(); + // Clear all applets + profile_selector.reset(); + software_keyboard.reset(); + web_browser.reset(); + LOG_DEBUG(Core, "Shutdown OK"); } @@ -233,6 +248,7 @@ struct System::Impl { /// Frontend applets std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; + std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; /// Service manager std::shared_ptr<Service::SM::ServiceManager> service_manager; @@ -427,22 +443,34 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const { return impl->virtual_filesystem; } -void System::SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet) { +void System::SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet) { impl->profile_selector = std::move(applet); } -const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const { +const Frontend::ProfileSelectApplet& System::GetProfileSelector() const { return *impl->profile_selector; } -void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) { +void System::SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet) { impl->software_keyboard = std::move(applet); } -const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const { +const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const { return *impl->software_keyboard; } +void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) { + impl->web_browser = std::move(applet); +} + +Frontend::WebBrowserApplet& System::GetWebBrowser() { + return *impl->web_browser; +} + +const Frontend::WebBrowserApplet& System::GetWebBrowser() const { + return *impl->web_browser; +} + System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { return impl->Init(*this, emu_window); } diff --git a/src/core/core.h b/src/core/core.h index 869921493..511a5ad3a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -11,11 +11,12 @@ #include "common/common_types.h" #include "core/file_sys/vfs_types.h" #include "core/hle/kernel/object.h" -#include "frontend/applets/profile_select.h" namespace Core::Frontend { class EmuWindow; +class ProfileSelectApplet; class SoftwareKeyboardApplet; +class WebBrowserApplet; } // namespace Core::Frontend namespace FileSys { @@ -242,13 +243,18 @@ public: std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; - void SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet); + void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet); - const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const; + const Frontend::ProfileSelectApplet& GetProfileSelector() const; - void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet); + void SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet); - const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; + const Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; + + void SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet); + + Frontend::WebBrowserApplet& GetWebBrowser(); + const Frontend::WebBrowserApplet& GetWebBrowser() const; private: System(); diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 19b6f8600..5aa3b600b 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -359,6 +359,8 @@ bool NCA::ReadPFS0Section(const NCASectionHeader& section, const NCASectionTable dirs.push_back(std::move(npfs)); if (IsDirectoryExeFS(dirs.back())) exefs = dirs.back(); + else if (IsDirectoryLogoPartition(dirs.back())) + logo = dirs.back(); } else { if (has_rights_id) status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek; @@ -546,4 +548,8 @@ u64 NCA::GetBaseIVFCOffset() const { return ivfc_offset; } +VirtualDir NCA::GetLogoPartition() const { + return logo; +} + } // namespace FileSys diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 99294cbb4..5d4d05c82 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -74,6 +74,13 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) { return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; } +inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) { + // NintendoLogo is the static image in the top left corner while StartupMovie is the animation + // in the bottom right corner. + return pfs->GetFile("NintendoLogo.png") != nullptr && + pfs->GetFile("StartupMovie.gif") != nullptr; +} + // An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner. // After construction, use GetStatus to determine if the file is valid and ready to be used. class NCA : public ReadOnlyVfsDirectory { @@ -102,6 +109,8 @@ public: // Returns the base ivfc offset used in BKTR patching. u64 GetBaseIVFCOffset() const; + VirtualDir GetLogoPartition() const; + private: bool CheckSupportedNCA(const NCAHeader& header); bool HandlePotentialHeaderDecryption(); @@ -122,6 +131,7 @@ private: VirtualFile romfs = nullptr; VirtualDir exefs = nullptr; + VirtualDir logo = nullptr; VirtualFile file; VirtualFile bktr_base_romfs; u64 ivfc_offset = 0; diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 6690aa575..7b5c509fb 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h @@ -39,27 +39,4 @@ static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x31 static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); -class DirectoryBackend : NonCopyable { -public: - DirectoryBackend() {} - virtual ~DirectoryBackend() {} - - /** - * List files contained in the directory - * @param count Number of entries to return at once in entries - * @param entries Buffer to read data into - * @return Number of entries listed - */ - virtual u64 Read(const u64 count, Entry* entries) = 0; - - /// Returns the number of entries still left to read. - virtual u64 GetEntryCount() const = 0; - - /** - * Close the directory - * @return true if the directory closed correctly - */ - virtual bool Close() const = 0; -}; - } // namespace FileSys diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 81e1f66ac..ebbdf081e 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -119,6 +119,9 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { VirtualDir out = std::move(root); + if (type == RomFSExtractionType::SingleDiscard) + return out->GetSubdirectories().front(); + while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { if (out->GetSubdirectories().front()->GetName() == "data" && type == RomFSExtractionType::Truncated) diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 0ec404731..0f35639bc 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h @@ -33,8 +33,9 @@ struct IVFCHeader { static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); enum class RomFSExtractionType { - Full, // Includes data directory - Truncated, // Traverses into data directory + Full, // Includes data directory + Truncated, // Traverses into data directory + SingleDiscard, // Traverses into the first subdirectory of root }; // Converts a RomFS binary blob to VFS Filesystem diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp new file mode 100644 index 000000000..3a3d3d0bf --- /dev/null +++ b/src/core/frontend/applets/web_browser.cpp @@ -0,0 +1,24 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/frontend/applets/web_browser.h" + +namespace Core::Frontend { + +WebBrowserApplet::~WebBrowserApplet() = default; + +DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; + +void DefaultWebBrowserApplet::OpenPage(std::string_view filename, + std::function<void()> unpack_romfs_callback, + std::function<void()> finished_callback) { + LOG_INFO(Service_AM, + "(STUBBED) called - No suitable web browser implementation found to open website page " + "at '{}'!", + filename); + finished_callback(); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h new file mode 100644 index 000000000..f952856af --- /dev/null +++ b/src/core/frontend/applets/web_browser.h @@ -0,0 +1,28 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <string_view> + +namespace Core::Frontend { + +class WebBrowserApplet { +public: + virtual ~WebBrowserApplet(); + + virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, + std::function<void()> finished_callback) = 0; +}; + +class DefaultWebBrowserApplet final : public WebBrowserApplet { +public: + ~DefaultWebBrowserApplet() override; + + void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, + std::function<void()> finished_callback) override; +}; + +} // namespace Core::Frontend diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 7a5e9d216..d1cbe0e44 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -23,6 +23,7 @@ #include "core/hle/service/am/applets/profile_select.h" #include "core/hle/service/am/applets/software_keyboard.h" #include "core/hle/service/am/applets/stub_applet.h" +#include "core/hle/service/am/applets/web_browser.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" @@ -44,6 +45,7 @@ constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; enum class AppletId : u32 { ProfileSelect = 0x10, SoftwareKeyboard = 0x11, + LibAppletOff = 0x17, }; constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; @@ -730,10 +732,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - LOG_DEBUG(Service_AM, "called, offset={}", offset); - const std::vector<u8> data{ctx.ReadBuffer()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + if (data.size() > backing.buffer.size() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", @@ -753,10 +755,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - LOG_DEBUG(Service_AM, "called, offset={}", offset); - const std::size_t size{ctx.GetWriteBufferSize()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + if (size > backing.buffer.size() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", backing.buffer.size(), size, offset); @@ -791,6 +793,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { return std::make_shared<Applets::ProfileSelect>(); case AppletId::SoftwareKeyboard: return std::make_shared<Applets::SoftwareKeyboard>(); + case AppletId::LibAppletOff: + return std::make_shared<Applets::WebBrowser>(); default: LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", static_cast<u32>(id)); diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 4c7b45454..14e2a1fee 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -7,7 +7,7 @@ #include "common/assert.h" #include "common/string_util.h" #include "core/core.h" -#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/profile_select.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/profile_select.h" diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp new file mode 100644 index 000000000..9b0aa7f5f --- /dev/null +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -0,0 +1,190 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include <cstring> +#include <vector> + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_paths.h" +#include "common/file_util.h" +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/mode.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/vfs_types.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/kernel/process.h" +#include "core/hle/service/am/applets/web_browser.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace Service::AM::Applets { + +// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not +// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, +// but some may be worth an implementation. +constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; + +struct WebBufferHeader { + u16 count; + INSERT_PADDING_BYTES(6); +}; +static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); + +struct WebArgumentHeader { + u16 type; + u16 size; + u32 offset; +}; +static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); + +struct WebArgumentResult { + u32 result_code; + std::array<char, 0x1000> last_url; + u64 last_url_size; +}; +static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); + +static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { + WebBufferHeader header; + ASSERT(sizeof(WebBufferHeader) <= data.size()); + std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); + + u64 offset = sizeof(WebBufferHeader); + for (u16 i = 0; i < header.count; ++i) { + WebArgumentHeader arg; + ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); + std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); + offset += sizeof(WebArgumentHeader); + + if (arg.type == type) { + std::vector<u8> out(arg.size); + offset += arg.offset; + ASSERT(offset + arg.size <= data.size()); + std::memcpy(out.data(), data.data() + offset, out.size()); + return out; + } + + offset += arg.offset + arg.size; + } + + return {}; +} + +static FileSys::VirtualFile GetManualRomFS() { + auto& loader{Core::System::GetInstance().GetAppLoader()}; + + FileSys::VirtualFile out; + if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) + return out; + + const auto& installed{FileSystem::GetUnionContents()}; + const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), + FileSys::ContentRecordType::Manual); + + if (res != nullptr) + return res->GetRomFS(); + return nullptr; +} + +WebBrowser::WebBrowser() = default; + +WebBrowser::~WebBrowser() = default; + +void WebBrowser::Initialize() { + Applet::Initialize(); + + complete = false; + temporary_dir.clear(); + filename.clear(); + status = RESULT_SUCCESS; + + const auto web_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(web_arg_storage != nullptr); + const auto& web_arg = web_arg_storage->GetData(); + + const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); + filename = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast<const char*>(url_data.data()), url_data.size()); + + temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + + "web_applet_manual", + FileUtil::DirectorySeparator::PlatformDefault); + FileUtil::DeleteDirRecursively(temporary_dir); + + manual_romfs = GetManualRomFS(); + if (manual_romfs == nullptr) { + status = ResultCode(-1); + LOG_ERROR(Service_AM, "Failed to find manual for current process!"); + } + + filename = + FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, + FileUtil::DirectorySeparator::PlatformDefault); +} + +bool WebBrowser::TransactionComplete() const { + return complete; +} + +ResultCode WebBrowser::GetStatus() const { + return status; +} + +void WebBrowser::ExecuteInteractive() { + UNIMPLEMENTED_MSG("Unexpected interactive data recieved!"); +} + +void WebBrowser::Execute() { + if (complete) + return; + + if (status != RESULT_SUCCESS) { + complete = true; + return; + } + + auto& frontend{Core::System::GetInstance().GetWebBrowser()}; + + frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); +} + +void WebBrowser::UnpackRomFS() { + if (unpacked) + return; + + ASSERT(manual_romfs != nullptr); + const auto dir = + FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); + const auto& vfs{Core::System::GetInstance().GetFilesystem()}; + const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); + FileSys::VfsRawCopyD(dir, temp_dir); + + unpacked = true; +} + +void WebBrowser::Finalize() { + complete = true; + + WebArgumentResult out{}; + out.result_code = 0; + out.last_url_size = 0; + + std::vector<u8> data(sizeof(WebArgumentResult)); + std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); + + broker.PushNormalDataFromApplet(IStorage{data}); + broker.SignalStateChanged(); + + FileUtil::DeleteDirRecursively(temporary_dir); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h new file mode 100644 index 000000000..b9e228fac --- /dev/null +++ b/src/core/hle/service/am/applets/web_browser.h @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs_types.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +class WebBrowser final : public Applet { +public: + WebBrowser(); + ~WebBrowser() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary + // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in + // size. Attempting to access files at filename before invocation is likely to not work. + void UnpackRomFS(); + + // Callback to be fired when the frontend is finished browsing. This will delete the temporary + // manual RomFS extracted files, so ensure this is only called at actual finalization. + void Finalize(); + +private: + bool complete = false; + bool unpacked = false; + ResultCode status = RESULT_SUCCESS; + + FileSys::VirtualFile manual_romfs; + std::string temporary_dir; + std::string filename; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 75fdb861a..04c8c35a8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -410,6 +410,8 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { 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; + + press_state |= static_cast<u32>(pad_state.pad_states.raw); } std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), shared_memory_entries.size() * sizeof(NPadEntry)); @@ -636,6 +638,10 @@ void Controller_NPad::ClearAllControllers() { }); } +u32 Controller_NPad::GetAndResetPressState() { + return std::exchange(press_state, 0); +} + bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 29851f16a..106cf58c8 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -124,6 +124,10 @@ public: void ConnectAllDisconnectedControllers(); void ClearAllControllers(); + // 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); @@ -292,6 +296,8 @@ private: bool is_connected; }; + u32 press_state{}; + NPadType style{}; std::array<NPadEntry, 10> shared_memory_entries{}; std::array< diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 268409257..008bf3f02 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -40,119 +40,82 @@ constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66; constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; -enum class HidController : std::size_t { - DebugPad, - Touchscreen, - Mouse, - Keyboard, - XPad, - Unknown1, - Unknown2, - Unknown3, - SixAxisSensor, - NPad, - Gesture, - - MaxControllers, -}; - -class IAppletResource final : public ServiceFramework<IAppletResource> { -public: - IAppletResource() : ServiceFramework("IAppletResource") { - static const FunctionInfo functions[] = { - {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, - }; - RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); - shared_mem = Kernel::SharedMemory::Create( - kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, - Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); - - MakeController<Controller_DebugPad>(HidController::DebugPad); - MakeController<Controller_Touchscreen>(HidController::Touchscreen); - MakeController<Controller_Mouse>(HidController::Mouse); - MakeController<Controller_Keyboard>(HidController::Keyboard); - MakeController<Controller_XPad>(HidController::XPad); - MakeController<Controller_Stubbed>(HidController::Unknown1); - MakeController<Controller_Stubbed>(HidController::Unknown2); - MakeController<Controller_Stubbed>(HidController::Unknown3); - MakeController<Controller_Stubbed>(HidController::SixAxisSensor); - MakeController<Controller_NPad>(HidController::NPad); - MakeController<Controller_Gesture>(HidController::Gesture); - - // Homebrew doesn't try to activate some controllers, so we activate them by default - GetController<Controller_NPad>(HidController::NPad).ActivateController(); - GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); - - GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); - GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); - GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); - - // Register update callbacks - pad_update_event = CoreTiming::RegisterEvent( - "HID::UpdatePadCallback", - [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); - - // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) - - CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); - - ReloadInputDevices(); - } - - void ActivateController(HidController controller) { - controllers[static_cast<size_t>(controller)]->ActivateController(); - } - - void DeactivateController(HidController controller) { - controllers[static_cast<size_t>(controller)]->DeactivateController(); - } +IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { + static const FunctionInfo functions[] = { + {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, + }; + RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + shared_mem = Kernel::SharedMemory::Create( + kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, + Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); + + MakeController<Controller_DebugPad>(HidController::DebugPad); + MakeController<Controller_Touchscreen>(HidController::Touchscreen); + MakeController<Controller_Mouse>(HidController::Mouse); + MakeController<Controller_Keyboard>(HidController::Keyboard); + MakeController<Controller_XPad>(HidController::XPad); + MakeController<Controller_Stubbed>(HidController::Unknown1); + MakeController<Controller_Stubbed>(HidController::Unknown2); + MakeController<Controller_Stubbed>(HidController::Unknown3); + MakeController<Controller_Stubbed>(HidController::SixAxisSensor); + MakeController<Controller_NPad>(HidController::NPad); + MakeController<Controller_Gesture>(HidController::Gesture); + + // Homebrew doesn't try to activate some controllers, so we activate them by default + GetController<Controller_NPad>(HidController::NPad).ActivateController(); + GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); + + GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); + GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); + GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); + + // Register update callbacks + pad_update_event = + CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) { + UpdateControllers(userdata, cycles_late); + }); + + // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) + + CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); + + ReloadInputDevices(); +} - template <typename T> - void MakeController(HidController controller) { - controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); - } +void IAppletResource::ActivateController(HidController controller) { + controllers[static_cast<size_t>(controller)]->ActivateController(); +} - template <typename T> - T& GetController(HidController controller) { - return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); - } +void IAppletResource::DeactivateController(HidController controller) { + controllers[static_cast<size_t>(controller)]->DeactivateController(); +} - ~IAppletResource() { - CoreTiming::UnscheduleEvent(pad_update_event, 0); - } +IAppletResource ::~IAppletResource() { + CoreTiming::UnscheduleEvent(pad_update_event, 0); +} -private: - void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_mem); - } + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(shared_mem); +} - void UpdateControllers(u64 userdata, int cycles_late) { - const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); - for (const auto& controller : controllers) { - if (should_reload) { - controller->OnLoadInputDevices(); - } - controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); +void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { + const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); + for (const auto& controller : controllers) { + if (should_reload) { + controller->OnLoadInputDevices(); } - - CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); + controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); } - // Handle to shared memory region designated to HID service - Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; - - // CoreTiming update events - CoreTiming::EventType* pad_update_event; - - std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> - controllers{}; -}; + CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); +} class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { public: @@ -172,599 +135,597 @@ private: } }; -class Hid final : public ServiceFramework<Hid> { -public: - Hid() : ServiceFramework("hid") { - // clang-format off - static const FunctionInfo functions[] = { - {0, &Hid::CreateAppletResource, "CreateAppletResource"}, - {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, - {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, - {21, &Hid::ActivateMouse, "ActivateMouse"}, - {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, - {32, nullptr, "SendKeyboardLockKeyEvent"}, - {40, nullptr, "AcquireXpadIdEventHandle"}, - {41, nullptr, "ReleaseXpadIdEventHandle"}, - {51, &Hid::ActivateXpad, "ActivateXpad"}, - {55, nullptr, "GetXpadIds"}, - {56, nullptr, "ActivateJoyXpad"}, - {58, nullptr, "GetJoyXpadLifoHandle"}, - {59, nullptr, "GetJoyXpadIds"}, - {60, nullptr, "ActivateSixAxisSensor"}, - {61, nullptr, "DeactivateSixAxisSensor"}, - {62, nullptr, "GetSixAxisSensorLifoHandle"}, - {63, nullptr, "ActivateJoySixAxisSensor"}, - {64, nullptr, "DeactivateJoySixAxisSensor"}, - {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, - {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, - {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, - {68, nullptr, "IsSixAxisSensorFusionEnabled"}, - {69, nullptr, "EnableSixAxisSensorFusion"}, - {70, nullptr, "SetSixAxisSensorFusionParameters"}, - {71, nullptr, "GetSixAxisSensorFusionParameters"}, - {72, nullptr, "ResetSixAxisSensorFusionParameters"}, - {73, nullptr, "SetAccelerometerParameters"}, - {74, nullptr, "GetAccelerometerParameters"}, - {75, nullptr, "ResetAccelerometerParameters"}, - {76, nullptr, "SetAccelerometerPlayMode"}, - {77, nullptr, "GetAccelerometerPlayMode"}, - {78, nullptr, "ResetAccelerometerPlayMode"}, - {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, - {80, nullptr, "GetGyroscopeZeroDriftMode"}, - {81, nullptr, "ResetGyroscopeZeroDriftMode"}, - {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, - {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"}, - {91, &Hid::ActivateGesture, "ActivateGesture"}, - {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, - {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, - {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, - {103, &Hid::ActivateNpad, "ActivateNpad"}, - {104, nullptr, "DeactivateNpad"}, - {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, - {107, &Hid::DisconnectNpad, "DisconnectNpad"}, - {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, - {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, - {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, - {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, - {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, - {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, - {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, - {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, - {126, nullptr, "StartLrAssignmentMode"}, - {127, nullptr, "StopLrAssignmentMode"}, - {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, - {129, nullptr, "GetNpadHandheldActivationMode"}, - {130, nullptr, "SwapNpadAssignment"}, - {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, - {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, - {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, - {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, - {201, &Hid::SendVibrationValue, "SendVibrationValue"}, - {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, - {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, - {204, nullptr, "PermitVibration"}, - {205, nullptr, "IsVibrationPermitted"}, - {206, &Hid::SendVibrationValues, "SendVibrationValues"}, - {207, nullptr, "SendVibrationGcErmCommand"}, - {208, nullptr, "GetActualVibrationGcErmCommand"}, - {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, - {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, - {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, - {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, - {302, nullptr, "StopConsoleSixAxisSensor"}, - {303, nullptr, "ActivateSevenSixAxisSensor"}, - {304, nullptr, "StartSevenSixAxisSensor"}, - {305, nullptr, "StopSevenSixAxisSensor"}, - {306, nullptr, "InitializeSevenSixAxisSensor"}, - {307, nullptr, "FinalizeSevenSixAxisSensor"}, - {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, - {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, - {310, nullptr, "ResetSevenSixAxisSensorTimestamp"}, - {400, nullptr, "IsUsbFullKeyControllerEnabled"}, - {401, nullptr, "EnableUsbFullKeyController"}, - {402, nullptr, "IsUsbFullKeyControllerConnected"}, - {403, nullptr, "HasBattery"}, - {404, nullptr, "HasLeftRightBattery"}, - {405, nullptr, "GetNpadInterfaceType"}, - {406, nullptr, "GetNpadLeftRightInterfaceType"}, - {500, nullptr, "GetPalmaConnectionHandle"}, - {501, nullptr, "InitializePalma"}, - {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, - {503, nullptr, "GetPalmaOperationInfo"}, - {504, nullptr, "PlayPalmaActivity"}, - {505, nullptr, "SetPalmaFrModeType"}, - {506, nullptr, "ReadPalmaStep"}, - {507, nullptr, "EnablePalmaStep"}, - {508, nullptr, "ResetPalmaStep"}, - {509, nullptr, "ReadPalmaApplicationSection"}, - {510, nullptr, "WritePalmaApplicationSection"}, - {511, nullptr, "ReadPalmaUniqueCode"}, - {512, nullptr, "SetPalmaUniqueCodeInvalid"}, - {513, nullptr, "WritePalmaActivityEntry"}, - {514, nullptr, "WritePalmaRgbLedPatternEntry"}, - {515, nullptr, "WritePalmaWaveEntry"}, - {516, nullptr, "SetPalmaDataBaseIdentificationVersion"}, - {517, nullptr, "GetPalmaDataBaseIdentificationVersion"}, - {518, nullptr, "SuspendPalmaFeature"}, - {519, nullptr, "GetPalmaOperationResult"}, - {520, nullptr, "ReadPalmaPlayLog"}, - {521, nullptr, "ResetPalmaPlayLog"}, - {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"}, - {523, nullptr, "SetIsPalmaPairedConnectable"}, - {524, nullptr, "PairPalma"}, - {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, - {1000, nullptr, "SetNpadCommunicationMode"}, - {1001, nullptr, "GetNpadCommunicationMode"}, - }; - // clang-format on - - RegisterHandlers(functions); +std::shared_ptr<IAppletResource> Hid::GetAppletResource() { + if (applet_resource == nullptr) { + applet_resource = std::make_shared<IAppletResource>(); } - ~Hid() = default; -private: - std::shared_ptr<IAppletResource> applet_resource; + return applet_resource; +} - void CreateAppletResource(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; +Hid::Hid() : ServiceFramework("hid") { + // clang-format off + static const FunctionInfo functions[] = { + {0, &Hid::CreateAppletResource, "CreateAppletResource"}, + {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, + {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, + {21, &Hid::ActivateMouse, "ActivateMouse"}, + {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, + {32, nullptr, "SendKeyboardLockKeyEvent"}, + {40, nullptr, "AcquireXpadIdEventHandle"}, + {41, nullptr, "ReleaseXpadIdEventHandle"}, + {51, &Hid::ActivateXpad, "ActivateXpad"}, + {55, nullptr, "GetXpadIds"}, + {56, nullptr, "ActivateJoyXpad"}, + {58, nullptr, "GetJoyXpadLifoHandle"}, + {59, nullptr, "GetJoyXpadIds"}, + {60, nullptr, "ActivateSixAxisSensor"}, + {61, nullptr, "DeactivateSixAxisSensor"}, + {62, nullptr, "GetSixAxisSensorLifoHandle"}, + {63, nullptr, "ActivateJoySixAxisSensor"}, + {64, nullptr, "DeactivateJoySixAxisSensor"}, + {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, + {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, + {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, + {68, nullptr, "IsSixAxisSensorFusionEnabled"}, + {69, nullptr, "EnableSixAxisSensorFusion"}, + {70, nullptr, "SetSixAxisSensorFusionParameters"}, + {71, nullptr, "GetSixAxisSensorFusionParameters"}, + {72, nullptr, "ResetSixAxisSensorFusionParameters"}, + {73, nullptr, "SetAccelerometerParameters"}, + {74, nullptr, "GetAccelerometerParameters"}, + {75, nullptr, "ResetAccelerometerParameters"}, + {76, nullptr, "SetAccelerometerPlayMode"}, + {77, nullptr, "GetAccelerometerPlayMode"}, + {78, nullptr, "ResetAccelerometerPlayMode"}, + {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, + {80, nullptr, "GetGyroscopeZeroDriftMode"}, + {81, nullptr, "ResetGyroscopeZeroDriftMode"}, + {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, + {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"}, + {91, &Hid::ActivateGesture, "ActivateGesture"}, + {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, + {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, + {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, + {103, &Hid::ActivateNpad, "ActivateNpad"}, + {104, nullptr, "DeactivateNpad"}, + {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, + {107, &Hid::DisconnectNpad, "DisconnectNpad"}, + {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, + {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, + {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, + {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, + {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, + {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, + {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, + {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, + {126, nullptr, "StartLrAssignmentMode"}, + {127, nullptr, "StopLrAssignmentMode"}, + {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, + {129, nullptr, "GetNpadHandheldActivationMode"}, + {130, nullptr, "SwapNpadAssignment"}, + {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, + {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, + {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, + {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, + {201, &Hid::SendVibrationValue, "SendVibrationValue"}, + {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, + {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, + {204, nullptr, "PermitVibration"}, + {205, nullptr, "IsVibrationPermitted"}, + {206, &Hid::SendVibrationValues, "SendVibrationValues"}, + {207, nullptr, "SendVibrationGcErmCommand"}, + {208, nullptr, "GetActualVibrationGcErmCommand"}, + {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, + {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, + {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, + {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, + {302, nullptr, "StopConsoleSixAxisSensor"}, + {303, nullptr, "ActivateSevenSixAxisSensor"}, + {304, nullptr, "StartSevenSixAxisSensor"}, + {305, nullptr, "StopSevenSixAxisSensor"}, + {306, nullptr, "InitializeSevenSixAxisSensor"}, + {307, nullptr, "FinalizeSevenSixAxisSensor"}, + {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, + {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, + {310, nullptr, "ResetSevenSixAxisSensorTimestamp"}, + {400, nullptr, "IsUsbFullKeyControllerEnabled"}, + {401, nullptr, "EnableUsbFullKeyController"}, + {402, nullptr, "IsUsbFullKeyControllerConnected"}, + {403, nullptr, "HasBattery"}, + {404, nullptr, "HasLeftRightBattery"}, + {405, nullptr, "GetNpadInterfaceType"}, + {406, nullptr, "GetNpadLeftRightInterfaceType"}, + {500, nullptr, "GetPalmaConnectionHandle"}, + {501, nullptr, "InitializePalma"}, + {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, + {503, nullptr, "GetPalmaOperationInfo"}, + {504, nullptr, "PlayPalmaActivity"}, + {505, nullptr, "SetPalmaFrModeType"}, + {506, nullptr, "ReadPalmaStep"}, + {507, nullptr, "EnablePalmaStep"}, + {508, nullptr, "ResetPalmaStep"}, + {509, nullptr, "ReadPalmaApplicationSection"}, + {510, nullptr, "WritePalmaApplicationSection"}, + {511, nullptr, "ReadPalmaUniqueCode"}, + {512, nullptr, "SetPalmaUniqueCodeInvalid"}, + {513, nullptr, "WritePalmaActivityEntry"}, + {514, nullptr, "WritePalmaRgbLedPatternEntry"}, + {515, nullptr, "WritePalmaWaveEntry"}, + {516, nullptr, "SetPalmaDataBaseIdentificationVersion"}, + {517, nullptr, "GetPalmaDataBaseIdentificationVersion"}, + {518, nullptr, "SuspendPalmaFeature"}, + {519, nullptr, "GetPalmaOperationResult"}, + {520, nullptr, "ReadPalmaPlayLog"}, + {521, nullptr, "ResetPalmaPlayLog"}, + {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"}, + {523, nullptr, "SetIsPalmaPairedConnectable"}, + {524, nullptr, "PairPalma"}, + {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, + {1000, nullptr, "SetNpadCommunicationMode"}, + {1001, nullptr, "GetNpadCommunicationMode"}, + }; + // clang-format on + + RegisterHandlers(functions); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +Hid::~Hid() = default; - if (applet_resource == nullptr) { - applet_resource = std::make_shared<IAppletResource>(); - } +void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IAppletResource>(applet_resource); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + if (applet_resource == nullptr) { + applet_resource = std::make_shared<IAppletResource>(); } - void ActivateXpad(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto basic_xpad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IAppletResource>(applet_resource); +} - LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", - basic_xpad_id, applet_resource_user_id); +void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto basic_xpad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::XPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, + applet_resource_user_id); - void ActivateDebugPad(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::XPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::DebugPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::DebugPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::Touchscreen); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateMouse(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::Touchscreen); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::Mouse); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateKeyboard(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::Mouse); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::Keyboard); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateGesture(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::Keyboard); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, - applet_resource_user_id); +void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::Gesture); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); - void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { - // Should have no effect with how our npad sets up the data - IPC::RequestParser rp{ctx}; - const auto unknown{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::Gesture); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, - applet_resource_user_id); +void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { + // Should have no effect with how our npad sets up the data + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); - void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto handle{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->ActivateController(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, - applet_resource_user_id); +void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); - void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto handle{rp.Pop<u32>()}; - const auto drift_mode{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, - "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", - handle, drift_mode, applet_resource_user_id); +void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto drift_mode{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, + "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, + drift_mode, applet_resource_user_id); - void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto handle{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, - applet_resource_user_id); +void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. - rb.Push(true); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); - void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto supported_styleset{rp.Pop<u32>()}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. + rb.Push(true); +} - LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); +void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto supported_styleset{rp.Pop<u32>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedStyleSet({supported_styleset}); + LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSupportedStyleSet({supported_styleset}); - void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(controller.GetSupportedStyleSet().raw); - } + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(controller.GetSupportedStyleSet().raw); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateNpad(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - applet_resource->ActivateController(HidController::NPad); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto unknown{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + applet_resource->ActivateController(HidController::NPad); +} - LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", - npad_id, applet_resource_user_id, unknown); +void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetStyleSetChangedEvent()); - } + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, + applet_resource_user_id, unknown); - void DisconnectNpad(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .GetStyleSetChangedEvent()); +} - LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, - applet_resource_user_id); +void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .DisconnectNPad(npad_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); - void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); +void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetLedPattern(npad_id) - .raw); - } + LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); - void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto hold_type{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .GetLedPattern(npad_id) + .raw); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", - applet_resource_user_id, hold_type); +void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto hold_type{rp.Pop<u64>()}; - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", + applet_resource_user_id, hold_type); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); - void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto& controller = - applet_resource->GetController<Controller_NPad>(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); +} - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - npad_id, applet_resource_user_id); +void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); - void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetVibrationEnabled(true); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetVibrationEnabled(false); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - void SendVibrationValue(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto controller_id{rp.Pop<u32>()}; - const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", - controller_id, applet_resource_user_id); +void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto controller_id{rp.Pop<u32>()}; + const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, + applet_resource_user_id); - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .VibrateController({controller_id}, {vibration_values}); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); - void SendVibrationValues(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .VibrateController({controller_id}, {vibration_values}); +} - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto controllers = ctx.ReadBuffer(0); - const auto vibrations = ctx.ReadBuffer(1); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - std::vector<u32> controller_list(controllers.size() / sizeof(u32)); - std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / - sizeof(Controller_NPad::Vibration)); + const auto controllers = ctx.ReadBuffer(0); + const auto vibrations = ctx.ReadBuffer(1); - std::memcpy(controller_list.data(), controllers.data(), controllers.size()); - std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); - std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), - [](u32 controller_id) { return controller_id - 3; }); + std::vector<u32> controller_list(controllers.size() / sizeof(u32)); + std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / + sizeof(Controller_NPad::Vibration)); - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .VibrateController(controller_list, vibration_list); + std::memcpy(controller_list.data(), controllers.data(), controllers.size()); + std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); + std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), + [](u32 controller_id) { return controller_id - 3; }); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .VibrateController(controller_list, vibration_list); - void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto controller_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", - controller_id, applet_resource_user_id); +void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto controller_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw<Controller_NPad::Vibration>( - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetLastVibration()); - } + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, + applet_resource_user_id); - void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<Controller_NPad::Vibration>( + applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); +} - LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, - applet_resource_user_id); +void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); - void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown_1{rp.Pop<u32>()}; - const auto unknown_2{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, - "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", - unknown_1, unknown_2, applet_resource_user_id); +void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown_1{rp.Pop<u32>()}; + const auto unknown_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + unknown_1, unknown_2, applet_resource_user_id); - void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto mode{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", - applet_resource_user_id, mode); +void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto mode{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", + applet_resource_user_id, mode); - void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(1); - rb.Push<u32>(0); - } +void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); + rb.Push<u32>(0); +} - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IActiveVibrationDeviceList>(); - } +void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IActiveVibrationDeviceList>(); +} - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", - applet_resource_user_id); +void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); - void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto handle{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, - applet_resource_user_id); +void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); - void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto handle{rp.Pop<u32>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); +void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); - void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto unknown{rp.Pop<u32>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", - applet_resource_user_id, unknown); +void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u32>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", + applet_resource_user_id, unknown); - void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown{rp.Pop<u32>()}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); +void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } -}; + LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} class HidDbg final : public ServiceFramework<HidDbg> { public: diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 773035460..eca27c056 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -4,12 +4,122 @@ #pragma once +#include "controllers/controller_base.h" +#include "core/hle/service/service.h" + +namespace CoreTiming { +struct EventType; +} + +namespace Kernel { +class SharedMemory; +} + namespace SM { class ServiceManager; } namespace Service::HID { +enum class HidController : std::size_t { + DebugPad, + Touchscreen, + Mouse, + Keyboard, + XPad, + Unknown1, + Unknown2, + Unknown3, + SixAxisSensor, + NPad, + Gesture, + + MaxControllers, +}; + +class IAppletResource final : public ServiceFramework<IAppletResource> { +public: + IAppletResource(); + ~IAppletResource() override; + + void ActivateController(HidController controller); + void DeactivateController(HidController controller); + + template <typename T> + T& GetController(HidController controller) { + return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); + } + + template <typename T> + const T& GetController(HidController controller) const { + return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); + } + +private: + template <typename T> + void MakeController(HidController controller) { + controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); + } + + void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); + void UpdateControllers(u64 userdata, int cycles_late); + + Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; + + CoreTiming::EventType* pad_update_event; + + std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> + controllers{}; +}; + +class Hid final : public ServiceFramework<Hid> { +public: + Hid(); + ~Hid() override; + + std::shared_ptr<IAppletResource> GetAppletResource(); + +private: + void CreateAppletResource(Kernel::HLERequestContext& ctx); + void ActivateXpad(Kernel::HLERequestContext& ctx); + void ActivateDebugPad(Kernel::HLERequestContext& ctx); + void ActivateTouchScreen(Kernel::HLERequestContext& ctx); + void ActivateMouse(Kernel::HLERequestContext& ctx); + void ActivateKeyboard(Kernel::HLERequestContext& ctx); + void ActivateGesture(Kernel::HLERequestContext& ctx); + void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); + void StartSixAxisSensor(Kernel::HLERequestContext& ctx); + void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); + void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); + void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); + void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); + void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); + void ActivateNpad(Kernel::HLERequestContext& ctx); + void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); + void DisconnectNpad(Kernel::HLERequestContext& ctx); + void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); + void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); + void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); + void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); + void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); + void SendVibrationValue(Kernel::HLERequestContext& ctx); + void SendVibrationValues(Kernel::HLERequestContext& ctx); + void GetActualVibrationValue(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); + void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); + void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); + void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); + void StopSixAxisSensor(Kernel::HLERequestContext& ctx); + void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); + void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); + + std::shared_ptr<IAppletResource> applet_resource; +}; + /// Reload input devices. Used when input configuration changed void ReloadInputDevices(); diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 16564de24..c13640ad8 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -12,9 +12,16 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/service/time/interface.h" #include "core/hle/service/time/time.h" +#include "core/settings.h" namespace Service::Time { +static std::chrono::seconds GetSecondsSinceEpoch() { + return std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + + Settings::values.custom_rtc_differential; +} + static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, CalendarAdditionalInfo& additional_info, [[maybe_unused]] const TimeZoneRule& /*rule*/) { @@ -68,9 +75,7 @@ public: private: void GetCurrentTime(Kernel::HLERequestContext& ctx) { - const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()) - .count()}; + const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; LOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, 4}; @@ -266,10 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto initial_type = rp.PopRaw<u8>(); - const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()) - .count()}; - + const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; const std::time_t time(time_since_epoch); const std::tm* tm = std::localtime(&time); if (tm == nullptr) { diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 1bdf19e13..70c933934 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -32,6 +32,9 @@ namespace Service::VI { +constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1}; +constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6}; + struct DisplayInfo { /// The name of this particular display. char display_name[0x40]{"Default"}; @@ -874,6 +877,22 @@ public: ~IApplicationDisplayService() = default; private: + enum class ConvertedScaleMode : u64 { + Freeze = 0, + ScaleToWindow = 1, + ScaleAndCrop = 2, + None = 3, + PreserveAspectRatio = 4, + }; + + enum class NintendoScaleMode : u32 { + None = 0, + Freeze = 1, + ScaleToWindow = 2, + ScaleAndCrop = 3, + PreserveAspectRatio = 4, + }; + void GetRelayService(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); @@ -974,13 +993,27 @@ private: void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const u32 scaling_mode = rp.Pop<u32>(); + const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); const u64 unknown = rp.Pop<u64>(); - LOG_WARNING(Service_VI, "(STUBBED) called. scaling_mode=0x{:08X}, unknown=0x{:016X}", - scaling_mode, unknown); + LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", + static_cast<u32>(scaling_mode), unknown); IPC::ResponseBuilder rb{ctx, 2}; + + if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) { + LOG_ERROR(Service_VI, "Invalid scaling mode provided."); + rb.Push(ERR_OPERATION_FAILED); + return; + } + + if (scaling_mode != NintendoScaleMode::ScaleToWindow && + scaling_mode != NintendoScaleMode::PreserveAspectRatio) { + LOG_ERROR(Service_VI, "Unsupported scaling mode supplied."); + rb.Push(ERR_UNSUPPORTED); + return; + } + rb.Push(RESULT_SUCCESS); } @@ -1061,51 +1094,37 @@ private: rb.PushCopyObjects(vsync_event); } - enum class ConvertedScaleMode : u64 { - None = 0, // VI seems to name this as "Unknown" but lots of games pass it, assume it's no - // scaling/default - Freeze = 1, - ScaleToWindow = 2, - Crop = 3, - NoCrop = 4, - }; - - // This struct is different, currently it's 1:1 but this might change in the future. - enum class NintendoScaleMode : u32 { - None = 0, - Freeze = 1, - ScaleToWindow = 2, - Crop = 3, - NoCrop = 4, - }; - void ConvertScalingMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto mode = rp.PopEnum<NintendoScaleMode>(); + const auto mode = rp.PopEnum<NintendoScaleMode>(); LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode)); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); + const auto converted_mode = ConvertScalingModeImpl(mode); + + if (converted_mode.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushEnum(*converted_mode); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(converted_mode.Code()); + } + } + + static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) { switch (mode) { case NintendoScaleMode::None: - rb.PushEnum(ConvertedScaleMode::None); - break; + return MakeResult(ConvertedScaleMode::None); case NintendoScaleMode::Freeze: - rb.PushEnum(ConvertedScaleMode::Freeze); - break; + return MakeResult(ConvertedScaleMode::Freeze); case NintendoScaleMode::ScaleToWindow: - rb.PushEnum(ConvertedScaleMode::ScaleToWindow); - break; - case NintendoScaleMode::Crop: - rb.PushEnum(ConvertedScaleMode::Crop); - break; - case NintendoScaleMode::NoCrop: - rb.PushEnum(ConvertedScaleMode::NoCrop); - break; + return MakeResult(ConvertedScaleMode::ScaleToWindow); + case NintendoScaleMode::ScaleAndCrop: + return MakeResult(ConvertedScaleMode::ScaleAndCrop); + case NintendoScaleMode::PreserveAspectRatio: + return MakeResult(ConvertedScaleMode::PreserveAspectRatio); default: - UNIMPLEMENTED_MSG("Unknown scaling mode {}", static_cast<u32>(mode)); - rb.PushEnum(ConvertedScaleMode::None); - break; + return ERR_OPERATION_FAILED; } } diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 30eacd803..bb925f4a6 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -178,6 +178,8 @@ public: /** * Get the banner (typically banner section) of the application + * In the context of NX, this is the animation that displays in the bottom right of the screen + * when a game boots. Stored in GIF format. * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ @@ -187,6 +189,8 @@ public: /** * Get the logo (typically logo section) of the application + * In the context of NX, this is the static image that displays in the top left of the screen + * when a game boots. Stored in JPEG format. * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ @@ -259,6 +263,15 @@ public: return ResultStatus::ErrorNotImplemented; } + /** + * Get the RomFS of the manual of the application + * @param file The raw manual RomFS of the game + * @return ResultStatus result of function + */ + virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) { + return ResultStatus::ErrorNotImplemented; + } + protected: FileSys::VirtualFile file; bool is_loaded = false; diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index a093e3d36..93a970d10 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -79,4 +79,13 @@ u64 AppLoader_NAX::ReadRomFSIVFCOffset() const { ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) { return nca_loader->ReadProgramId(out_program_id); } + +ResultStatus AppLoader_NAX::ReadBanner(std::vector<u8>& buffer) { + return nca_loader->ReadBanner(buffer); +} + +ResultStatus AppLoader_NAX::ReadLogo(std::vector<u8>& buffer) { + return nca_loader->ReadLogo(buffer); +} + } // namespace Loader diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 0a97511b8..f40079574 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -39,6 +39,9 @@ public: u64 ReadRomFSIVFCOffset() const override; ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadBanner(std::vector<u8>& buffer) override; + ResultStatus ReadLogo(std::vector<u8>& buffer) override; + private: std::unique_ptr<FileSys::NAX> nax; std::unique_ptr<AppLoader_NCA> nca_loader; diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 7e1b0d84f..ce8196fcf 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -84,4 +84,23 @@ ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { return ResultStatus::Success; } +ResultStatus AppLoader_NCA::ReadBanner(std::vector<u8>& buffer) { + if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) + return ResultStatus::ErrorNotInitialized; + const auto logo = nca->GetLogoPartition(); + if (logo == nullptr) + return ResultStatus::ErrorNoIcon; + buffer = logo->GetFile("StartupMovie.gif")->ReadAllBytes(); + return ResultStatus::Success; +} + +ResultStatus AppLoader_NCA::ReadLogo(std::vector<u8>& buffer) { + if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) + return ResultStatus::ErrorNotInitialized; + const auto logo = nca->GetLogoPartition(); + if (logo == nullptr) + return ResultStatus::ErrorNoIcon; + buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes(); + return ResultStatus::Success; +} } // namespace Loader diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index cbbe701d2..b9f077468 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -39,6 +39,9 @@ public: u64 ReadRomFSIVFCOffset() const override; ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadBanner(std::vector<u8>& buffer) override; + ResultStatus ReadLogo(std::vector<u8>& buffer) override; + private: std::unique_ptr<FileSys::NCA> nca; std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 4d4b44571..7da1f8960 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -158,4 +158,21 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) { nacp = *nacp_file; return ResultStatus::Success; } + +ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) { + const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual); + if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr) + return ResultStatus::ErrorNoRomFS; + file = nca->GetRomFS(); + return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; +} + +ResultStatus AppLoader_NSP::ReadBanner(std::vector<u8>& buffer) { + return secondary_loader->ReadBanner(buffer); +} + +ResultStatus AppLoader_NSP::ReadLogo(std::vector<u8>& buffer) { + return secondary_loader->ReadLogo(buffer); +} + } // namespace Loader diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 32eb0193d..953a1b508 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -44,6 +44,10 @@ public: ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadTitle(std::string& title) override; ResultStatus ReadControlData(FileSys::NACP& nacp) override; + ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; + + ResultStatus ReadBanner(std::vector<u8>& buffer) override; + ResultStatus ReadLogo(std::vector<u8>& buffer) override; private: std::unique_ptr<FileSys::NSP> nsp; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index e67e43c69..89f7bbf77 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -128,4 +128,21 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { return ResultStatus::Success; } +ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) { + const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), + FileSys::ContentRecordType::Manual); + if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) + return ResultStatus::ErrorXCIMissingPartition; + file = nca->GetRomFS(); + return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; +} + +ResultStatus AppLoader_XCI::ReadBanner(std::vector<u8>& buffer) { + return nca_loader->ReadBanner(buffer); +} + +ResultStatus AppLoader_XCI::ReadLogo(std::vector<u8>& buffer) { + return nca_loader->ReadLogo(buffer); +} + } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 9d3923f62..d6995b61e 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -44,6 +44,10 @@ public: ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadTitle(std::string& title) override; ResultStatus ReadControlData(FileSys::NACP& control) override; + ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; + + ResultStatus ReadBanner(std::vector<u8>& buffer) override; + ResultStatus ReadLogo(std::vector<u8>& buffer) override; private: std::unique_ptr<FileSys::XCI> xci; diff --git a/src/core/settings.h b/src/core/settings.h index de01b05c0..29ce98983 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -6,6 +6,7 @@ #include <array> #include <atomic> +#include <chrono> #include <map> #include <optional> #include <string> @@ -350,6 +351,11 @@ struct Values { bool use_docked_mode; bool enable_nfc; std::optional<u32> rng_seed; + // Measured in seconds since epoch + std::optional<std::chrono::seconds> custom_rtc; + // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` + std::chrono::seconds custom_rtc_differential; + s32 current_user; s32 language_index; |