summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2019-01-10 23:04:38 +0100
committerGitHub <noreply@github.com>2019-01-10 23:04:38 +0100
commit83e8ad23310937bb72f4412c15f45231a19202f7 (patch)
tree80301af69b14a701f16e21d41ced436850085031 /src
parentMerge pull request #2010 from ReinUsesLisp/gmem (diff)
parentbuild: Copy web engine resources to correct location (diff)
downloadyuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.gz
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.bz2
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.lz
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.xz
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.zst
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.zip
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp18
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/file_sys/romfs.cpp3
-rw-r--r--src/core/file_sys/romfs.h5
-rw-r--r--src/core/frontend/applets/web_browser.cpp24
-rw-r--r--src/core/frontend/applets/web_browser.h28
-rw-r--r--src/core/hle/service/am/am.cpp12
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp2
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp184
-rw-r--r--src/core/hle/service/am/applets/web_browser.h44
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
-rw-r--r--src/core/hle/service/hid/hid.cpp1117
-rw-r--r--src/core/hle/service/hid/hid.h110
-rw-r--r--src/core/loader/loader.h9
-rw-r--r--src/core/loader/nsp.cpp8
-rw-r--r--src/core/loader/nsp.h1
-rw-r--r--src/core/loader/xci.cpp9
-rw-r--r--src/core/loader/xci.h1
-rw-r--r--src/yuzu/CMakeLists.txt7
-rw-r--r--src/yuzu/applets/web_browser.cpp113
-rw-r--r--src/yuzu/applets/web_browser.h53
-rw-r--r--src/yuzu/main.cpp151
-rw-r--r--src/yuzu/main.h7
25 files changed, 1343 insertions, 586 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..715172771 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -31,7 +31,9 @@
#include "core/loader/loader.h"
#include "core/perf_stats.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"
@@ -103,6 +105,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 +203,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 +242,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;
@@ -443,6 +453,14 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
return *impl->software_keyboard;
}
+void System::SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet) {
+ impl->web_browser = std::move(applet);
+}
+
+const Core::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..a53dbb4d4 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 {
@@ -250,6 +251,10 @@ public:
const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
+ void SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet);
+
+ const Core::Frontend::WebBrowserApplet& GetWebBrowser() const;
+
private:
System();
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..6a36b4b8f
--- /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) const {
+ 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..41d272d26
--- /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) const = 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) const 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..d975207f5
--- /dev/null
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -0,0 +1,184 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_paths.h"
+#include "common/hex_util.h"
+#include "common/logging/backend.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/romfs_factory.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;
+ }
+
+ const 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/loader/loader.h b/src/core/loader/loader.h
index 30eacd803..01f984098 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -259,6 +259,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/nsp.cpp b/src/core/loader/nsp.cpp
index 4d4b44571..7fcb12aa2 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -158,4 +158,12 @@ 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;
+}
} // namespace Loader
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 32eb0193d..b6b309400 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -44,6 +44,7 @@ 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;
private:
std::unique_ptr<FileSys::NSP> nsp;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index e67e43c69..ff60a3756 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -128,4 +128,13 @@ 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;
+}
+
} // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 9d3923f62..e18531c93 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -44,6 +44,7 @@ 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;
private:
std::unique_ptr<FileSys::XCI> xci;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 5446be6be..1f852df4b 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -11,6 +11,8 @@ add_executable(yuzu
applets/profile_select.h
applets/software_keyboard.cpp
applets/software_keyboard.h
+ applets/web_browser.cpp
+ applets/web_browser.h
bootmanager.cpp
bootmanager.h
compatibility_list.cpp
@@ -157,6 +159,11 @@ if (USE_DISCORD_PRESENCE)
target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
endif()
+if (YUZU_USE_QT_WEB_ENGINE)
+ target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets)
+ target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
+endif ()
+
if(UNIX AND NOT APPLE)
install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
new file mode 100644
index 000000000..c59b7ade1
--- /dev/null
+++ b/src/yuzu/applets/web_browser.cpp
@@ -0,0 +1,113 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <mutex>
+
+#include <QKeyEvent>
+
+#include "core/hle/lock.h"
+#include "yuzu/applets/web_browser.h"
+#include "yuzu/main.h"
+
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
+constexpr char NX_SHIM_INJECT_SCRIPT[] = R"(
+ window.nx = {};
+ window.nx.playReport = {};
+ window.nx.playReport.setCounterSetIdentifier = function () {
+ console.log("nx.playReport.setCounterSetIdentifier called - unimplemented");
+ };
+
+ window.nx.playReport.incrementCounter = function () {
+ console.log("nx.playReport.incrementCounter called - unimplemented");
+ };
+
+ window.nx.footer = {};
+ window.nx.footer.unsetAssign = function () {
+ console.log("nx.footer.unsetAssign called - unimplemented");
+ };
+
+ var yuzu_key_callbacks = [];
+ window.nx.footer.setAssign = function(key, discard1, func, discard2) {
+ switch (key) {
+ case 'A':
+ yuzu_key_callbacks[0] = func;
+ break;
+ case 'B':
+ yuzu_key_callbacks[1] = func;
+ break;
+ case 'X':
+ yuzu_key_callbacks[2] = func;
+ break;
+ case 'Y':
+ yuzu_key_callbacks[3] = func;
+ break;
+ case 'L':
+ yuzu_key_callbacks[6] = func;
+ break;
+ case 'R':
+ yuzu_key_callbacks[7] = func;
+ break;
+ }
+ };
+
+ var applet_done = false;
+ window.nx.endApplet = function() {
+ applet_done = true;
+ };
+)";
+
+QString GetNXShimInjectionScript() {
+ return QString::fromStdString(NX_SHIM_INJECT_SCRIPT);
+}
+
+NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {}
+
+void NXInputWebEngineView::keyPressEvent(QKeyEvent* event) {
+ parent()->event(event);
+}
+
+void NXInputWebEngineView::keyReleaseEvent(QKeyEvent* event) {
+ parent()->event(event);
+}
+
+#endif
+
+QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
+ connect(this, &QtWebBrowser::MainWindowOpenPage, &main_window, &GMainWindow::WebBrowserOpenPage,
+ Qt::QueuedConnection);
+ connect(&main_window, &GMainWindow::WebBrowserUnpackRomFS, this,
+ &QtWebBrowser::MainWindowUnpackRomFS, Qt::QueuedConnection);
+ connect(&main_window, &GMainWindow::WebBrowserFinishedBrowsing, this,
+ &QtWebBrowser::MainWindowFinishedBrowsing, Qt::QueuedConnection);
+}
+
+QtWebBrowser::~QtWebBrowser() = default;
+
+void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+ std::function<void()> finished_callback) const {
+ this->unpack_romfs_callback = unpack_romfs_callback;
+ this->finished_callback = finished_callback;
+
+ const auto index = url.find('?');
+ if (index == std::string::npos) {
+ emit MainWindowOpenPage(url, "");
+ } else {
+ const auto front = url.substr(0, index);
+ const auto back = url.substr(index);
+ emit MainWindowOpenPage(front, back);
+ }
+}
+
+void QtWebBrowser::MainWindowUnpackRomFS() {
+ // Acquire the HLE mutex
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+ unpack_romfs_callback();
+}
+
+void QtWebBrowser::MainWindowFinishedBrowsing() {
+ // Acquire the HLE mutex
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+ finished_callback();
+}
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
new file mode 100644
index 000000000..bba273767
--- /dev/null
+++ b/src/yuzu/applets/web_browser.h
@@ -0,0 +1,53 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <QObject>
+
+#ifdef YUZU_USE_QT_WEB_ENGINE
+#include <QWebEngineView>
+#endif
+
+#include "core/frontend/applets/web_browser.h"
+
+class GMainWindow;
+
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
+QString GetNXShimInjectionScript();
+
+class NXInputWebEngineView : public QWebEngineView {
+public:
+ explicit NXInputWebEngineView(QWidget* parent = nullptr);
+
+protected:
+ void keyPressEvent(QKeyEvent* event) override;
+ void keyReleaseEvent(QKeyEvent* event) override;
+};
+
+#endif
+
+class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet {
+ Q_OBJECT
+
+public:
+ explicit QtWebBrowser(GMainWindow& main_window);
+ ~QtWebBrowser() override;
+
+ void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+ std::function<void()> finished_callback) const override;
+
+signals:
+ void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;
+
+public slots:
+ void MainWindowUnpackRomFS();
+ void MainWindowFinishedBrowsing();
+
+private:
+ mutable std::function<void()> unpack_romfs_callback;
+ mutable std::function<void()> finished_callback;
+};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1d5a2b51a..f564de994 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -10,11 +10,14 @@
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
#include "applets/profile_select.h"
#include "applets/software_keyboard.h"
+#include "applets/web_browser.h"
#include "configuration/configure_per_general.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
// defines.
@@ -96,6 +99,14 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/discord_impl.h"
#endif
+#ifdef YUZU_USE_QT_WEB_ENGINE
+#include <QWebEngineProfile>
+#include <QWebEngineScript>
+#include <QWebEngineScriptCollection>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+#endif
+
#ifdef QT_STATICPLUGIN
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#endif
@@ -252,6 +263,144 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message
emit SoftwareKeyboardFinishedCheckDialog();
}
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+ NXInputWebEngineView web_browser_view(this);
+
+ // Scope to contain the QProgressDialog for initalization
+ {
+ QProgressDialog progress(this);
+ progress.setMinimumDuration(200);
+ progress.setLabelText(tr("Loading Web Applet..."));
+ progress.setRange(0, 4);
+ progress.setValue(0);
+ progress.show();
+
+ auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); });
+
+ while (!future.isFinished())
+ QApplication::processEvents();
+
+ progress.setValue(1);
+
+ // Load the special shim script to handle input and exit.
+ QWebEngineScript nx_shim;
+ nx_shim.setSourceCode(GetNXShimInjectionScript());
+ nx_shim.setWorldId(QWebEngineScript::MainWorld);
+ nx_shim.setName("nx_inject.js");
+ nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation);
+ nx_shim.setRunsOnSubFrames(true);
+ web_browser_view.page()->profile()->scripts()->insert(nx_shim);
+
+ web_browser_view.load(
+ QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() +
+ QString::fromStdString(std::string(additional_args))));
+
+ progress.setValue(2);
+
+ render_window->hide();
+ web_browser_view.setFocus();
+
+ const auto& layout = render_window->GetFramebufferLayout();
+ web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight());
+ web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height());
+ web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) /
+ Layout::ScreenUndocked::Width);
+ web_browser_view.settings()->setAttribute(
+ QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
+
+ web_browser_view.show();
+
+ progress.setValue(3);
+
+ QApplication::processEvents();
+
+ progress.setValue(4);
+ }
+
+ bool finished = false;
+ QAction* exit_action = new QAction(tr("Exit Web Applet"), this);
+ connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; });
+ ui.menubar->addAction(exit_action);
+
+ auto& npad =
+ Core::System::GetInstance()
+ .ServiceManager()
+ .GetService<Service::HID::Hid>("hid")
+ ->GetAppletResource()
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+ const auto fire_js_keypress = [&web_browser_view](u32 key_code) {
+ web_browser_view.page()->runJavaScript(
+ QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));")
+ .arg(QString::fromStdString(std::to_string(key_code))));
+ };
+
+ bool running_exit_check = false;
+ while (!finished) {
+ QApplication::processEvents();
+
+ if (!running_exit_check) {
+ web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"),
+ [&](const QVariant& res) {
+ running_exit_check = false;
+ if (res.toBool())
+ finished = true;
+ });
+ running_exit_check = true;
+ }
+
+ const auto input = npad.GetAndResetPressState();
+ for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+ if ((input & (1 << i)) != 0) {
+ LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);
+ web_browser_view.page()->runJavaScript(
+ QStringLiteral("yuzu_key_callbacks[%1]();").arg(i));
+ }
+ }
+
+ if (input & 0x00888000) // RStick Down | LStick Down | DPad Down
+ fire_js_keypress(40); // Down Arrow Key
+ else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
+ fire_js_keypress(39); // Right Arrow Key
+ else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
+ fire_js_keypress(38); // Up Arrow Key
+ else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
+ fire_js_keypress(37); // Left Arrow Key
+ else if (input & 0x00000001) // A Button
+ fire_js_keypress(13); // Enter Key
+ }
+
+ web_browser_view.hide();
+ render_window->show();
+ render_window->setFocus();
+ ui.menubar->removeAction(exit_action);
+
+ // Needed to update render window focus/show and remove menubar action
+ QApplication::processEvents();
+ emit WebBrowserFinishedBrowsing();
+}
+
+#else
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+ QMessageBox::warning(
+ this, tr("Web Applet"),
+ tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
+ "properly display the game manual or web page requested."),
+ QMessageBox::Ok, QMessageBox::Ok);
+
+ LOG_INFO(Frontend,
+ "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
+ "'{}' with arguments '{}'!",
+ filename, additional_args);
+
+ emit WebBrowserFinishedBrowsing();
+}
+
+#endif
+
void GMainWindow::InitializeWidgets() {
#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
ui.action_Report_Compatibility->setVisible(true);
@@ -612,6 +761,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this));
system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
+ system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this));
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
@@ -1325,6 +1475,7 @@ void GMainWindow::OnStartGame() {
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
+ qRegisterMetaType<std::string_view>("std::string_view");
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index d560bf75b..2d705ad54 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -13,6 +13,7 @@
#include "common/common_types.h"
#include "core/core.h"
+#include "core/hle/service/acc/profile_manager.h"
#include "ui_main.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/hotkeys.h"
@@ -26,6 +27,7 @@ class GraphicsSurfaceWidget;
class GRenderWindow;
class MicroProfileDialog;
class ProfilerWidget;
+class QLabel;
class WaitTreeWidget;
enum class GameListOpenTarget;
@@ -103,11 +105,16 @@ signals:
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
void SoftwareKeyboardFinishedCheckDialog();
+ void WebBrowserUnpackRomFS();
+ void WebBrowserFinishedBrowsing();
+
public slots:
void ProfileSelectorSelectProfile();
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
+ void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
+
private:
void InitializeWidgets();
void InitializeDebugWidgets();