summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2019-01-10 17:04:38 -0500
committerGravatar GitHub2019-01-10 17:04:38 -0500
commit83e8ad23310937bb72f4412c15f45231a19202f7 (patch)
tree80301af69b14a701f16e21d41ced436850085031
parentMerge pull request #2010 from ReinUsesLisp/gmem (diff)
parentbuild: Copy web engine resources to correct location (diff)
downloadyuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.gz
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.tar.xz
yuzu-83e8ad23310937bb72f4412c15f45231a19202f7.zip
Merge pull request #1939 from DarkLordZach/web-applet
applets: Implement HLE web browser applet (LibAppletOff)
-rwxr-xr-x.travis/linux/docker.sh4
-rwxr-xr-x.travis/macos/build.sh2
-rw-r--r--CMakeLists.txt8
-rw-r--r--CMakeModules/CopyYuzuQt5Deps.cmake26
-rw-r--r--appveyor.yml3
-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
30 files changed, 1381 insertions, 591 deletions
diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index 4fe3326f9..8b7e65911 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -1,12 +1,12 @@
1#!/bin/bash -ex 1#!/bin/bash -ex
2 2
3apt-get update 3apt-get update
4apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget cmake ninja-build ccache 4apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev qtwebengine5-dev wget cmake ninja-build ccache
5 5
6cd /yuzu 6cd /yuzu
7 7
8mkdir build && cd build 8mkdir build && cd build
9cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -G Ninja 9cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -G Ninja
10ninja 10ninja
11 11
12ccache -s 12ccache -s
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index dce12099b..4a14837fc 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -9,7 +9,7 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH"
9 9
10mkdir build && cd build 10mkdir build && cd build
11cmake --version 11cmake --version
12cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON 12cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
13make -j4 13make -j4
14 14
15ccache -s 15ccache -s
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f71f9fd9..871e0ca1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
19 19
20option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON) 20option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
21 21
22option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
23
22option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) 24option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
23 25
24option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) 26option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
@@ -302,7 +304,7 @@ endif()
302if (ENABLE_QT) 304if (ENABLE_QT)
303 if (YUZU_USE_BUNDLED_QT) 305 if (YUZU_USE_BUNDLED_QT)
304 if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) 306 if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
305 set(QT_VER qt-5.10.0-msvc2015_64) 307 set(QT_VER qt-5.12.0-msvc2017_64)
306 else() 308 else()
307 message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.") 309 message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
308 endif() 310 endif()
@@ -319,6 +321,10 @@ if (ENABLE_QT)
319 endif() 321 endif()
320 322
321 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) 323 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
324
325 if (YUZU_USE_QT_WEB_ENGINE)
326 find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets ${QT_PREFIX_HINT})
327 endif ()
322endif() 328endif()
323 329
324# Platform-specific library requirements 330# Platform-specific library requirements
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index aaf80b77b..4fef66659 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -5,6 +5,7 @@ function(copy_yuzu_Qt5_deps target_dir)
5 set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") 5 set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
6 set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") 6 set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
7 set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") 7 set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
8 set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
8 set(PLATFORMS ${DLL_DEST}platforms/) 9 set(PLATFORMS ${DLL_DEST}platforms/)
9 set(STYLES ${DLL_DEST}styles/) 10 set(STYLES ${DLL_DEST}styles/)
10 set(IMAGEFORMATS ${DLL_DEST}imageformats/) 11 set(IMAGEFORMATS ${DLL_DEST}imageformats/)
@@ -17,6 +18,31 @@ function(copy_yuzu_Qt5_deps target_dir)
17 Qt5OpenGL$<$<CONFIG:Debug>:d>.* 18 Qt5OpenGL$<$<CONFIG:Debug>:d>.*
18 Qt5Widgets$<$<CONFIG:Debug>:d>.* 19 Qt5Widgets$<$<CONFIG:Debug>:d>.*
19 ) 20 )
21
22 if (YUZU_USE_QT_WEB_ENGINE)
23 windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
24 Qt5Network$<$<CONFIG:Debug>:d>.*
25 Qt5Positioning$<$<CONFIG:Debug>:d>.*
26 Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
27 Qt5Qml$<$<CONFIG:Debug>:d>.*
28 Qt5Quick$<$<CONFIG:Debug>:d>.*
29 Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
30 Qt5WebChannel$<$<CONFIG:Debug>:d>.*
31 Qt5WebEngine$<$<CONFIG:Debug>:d>.*
32 Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
33 Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
34 QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
35 )
36
37 windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
38 qtwebengine_resources.pak
39 qtwebengine_devtools_resources.pak
40 qtwebengine_resources_100p.pak
41 qtwebengine_resources_200p.pak
42 icudtl.dat
43 )
44 endif ()
45
20 windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) 46 windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
21 windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) 47 windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
22 windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) 48 windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)
diff --git a/appveyor.yml b/appveyor.yml
index d6a69fbc2..cef19c259 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -42,7 +42,7 @@ before_build:
42 $COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING} 42 $COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING}
43 if ($env:BUILD_TYPE -eq 'msvc') { 43 if ($env:BUILD_TYPE -eq 'msvc') {
44 # redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning 44 # redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
45 cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0' 45 cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
46 } else { 46 } else {
47 C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1" 47 C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1"
48 } 48 }
@@ -94,6 +94,7 @@ after_build:
94 Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse 94 Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse
95 rm "$RELEASE_DIST\*.exe" 95 rm "$RELEASE_DIST\*.exe"
96 Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST 96 Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
97 Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST
97 Copy-Item .\license.txt -Destination $RELEASE_DIST 98 Copy-Item .\license.txt -Destination $RELEASE_DIST
98 Copy-Item .\README.md -Destination $RELEASE_DIST 99 Copy-Item .\README.md -Destination $RELEASE_DIST
99 7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\* 100 7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*
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
88 frontend/applets/profile_select.h 88 frontend/applets/profile_select.h
89 frontend/applets/software_keyboard.cpp 89 frontend/applets/software_keyboard.cpp
90 frontend/applets/software_keyboard.h 90 frontend/applets/software_keyboard.h
91 frontend/applets/web_browser.cpp
92 frontend/applets/web_browser.h
91 frontend/emu_window.cpp 93 frontend/emu_window.cpp
92 frontend/emu_window.h 94 frontend/emu_window.h
93 frontend/framebuffer_layout.cpp 95 frontend/framebuffer_layout.cpp
@@ -173,6 +175,8 @@ add_library(core STATIC
173 hle/service/am/applets/software_keyboard.h 175 hle/service/am/applets/software_keyboard.h
174 hle/service/am/applets/stub_applet.cpp 176 hle/service/am/applets/stub_applet.cpp
175 hle/service/am/applets/stub_applet.h 177 hle/service/am/applets/stub_applet.h
178 hle/service/am/applets/web_browser.cpp
179 hle/service/am/applets/web_browser.h
176 hle/service/am/idle.cpp 180 hle/service/am/idle.cpp
177 hle/service/am/idle.h 181 hle/service/am/idle.h
178 hle/service/am/omm.cpp 182 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 @@
31#include "core/loader/loader.h" 31#include "core/loader/loader.h"
32#include "core/perf_stats.h" 32#include "core/perf_stats.h"
33#include "core/telemetry_session.h" 33#include "core/telemetry_session.h"
34#include "frontend/applets/profile_select.h"
34#include "frontend/applets/software_keyboard.h" 35#include "frontend/applets/software_keyboard.h"
36#include "frontend/applets/web_browser.h"
35#include "video_core/debug_utils/debug_utils.h" 37#include "video_core/debug_utils/debug_utils.h"
36#include "video_core/gpu.h" 38#include "video_core/gpu.h"
37#include "video_core/renderer_base.h" 39#include "video_core/renderer_base.h"
@@ -103,6 +105,8 @@ struct System::Impl {
103 profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); 105 profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
104 if (software_keyboard == nullptr) 106 if (software_keyboard == nullptr)
105 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); 107 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
108 if (web_browser == nullptr)
109 web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
106 110
107 auto main_process = Kernel::Process::Create(kernel, "main"); 111 auto main_process = Kernel::Process::Create(kernel, "main");
108 kernel.MakeCurrentProcess(main_process.get()); 112 kernel.MakeCurrentProcess(main_process.get());
@@ -199,6 +203,11 @@ struct System::Impl {
199 // Close app loader 203 // Close app loader
200 app_loader.reset(); 204 app_loader.reset();
201 205
206 // Clear all applets
207 profile_selector.reset();
208 software_keyboard.reset();
209 web_browser.reset();
210
202 LOG_DEBUG(Core, "Shutdown OK"); 211 LOG_DEBUG(Core, "Shutdown OK");
203 } 212 }
204 213
@@ -233,6 +242,7 @@ struct System::Impl {
233 /// Frontend applets 242 /// Frontend applets
234 std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; 243 std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
235 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; 244 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
245 std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
236 246
237 /// Service manager 247 /// Service manager
238 std::shared_ptr<Service::SM::ServiceManager> service_manager; 248 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -443,6 +453,14 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
443 return *impl->software_keyboard; 453 return *impl->software_keyboard;
444} 454}
445 455
456void System::SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet) {
457 impl->web_browser = std::move(applet);
458}
459
460const Core::Frontend::WebBrowserApplet& System::GetWebBrowser() const {
461 return *impl->web_browser;
462}
463
446System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 464System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
447 return impl->Init(*this, emu_window); 465 return impl->Init(*this, emu_window);
448} 466}
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 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/file_sys/vfs_types.h" 12#include "core/file_sys/vfs_types.h"
13#include "core/hle/kernel/object.h" 13#include "core/hle/kernel/object.h"
14#include "frontend/applets/profile_select.h"
15 14
16namespace Core::Frontend { 15namespace Core::Frontend {
17class EmuWindow; 16class EmuWindow;
17class ProfileSelectApplet;
18class SoftwareKeyboardApplet; 18class SoftwareKeyboardApplet;
19class WebBrowserApplet;
19} // namespace Core::Frontend 20} // namespace Core::Frontend
20 21
21namespace FileSys { 22namespace FileSys {
@@ -250,6 +251,10 @@ public:
250 251
251 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; 252 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
252 253
254 void SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet);
255
256 const Core::Frontend::WebBrowserApplet& GetWebBrowser() const;
257
253private: 258private:
254 System(); 259 System();
255 260
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) {
119 119
120 VirtualDir out = std::move(root); 120 VirtualDir out = std::move(root);
121 121
122 if (type == RomFSExtractionType::SingleDiscard)
123 return out->GetSubdirectories().front();
124
122 while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { 125 while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) {
123 if (out->GetSubdirectories().front()->GetName() == "data" && 126 if (out->GetSubdirectories().front()->GetName() == "data" &&
124 type == RomFSExtractionType::Truncated) 127 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 {
33static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); 33static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
34 34
35enum class RomFSExtractionType { 35enum class RomFSExtractionType {
36 Full, // Includes data directory 36 Full, // Includes data directory
37 Truncated, // Traverses into data directory 37 Truncated, // Traverses into data directory
38 SingleDiscard, // Traverses into the first subdirectory of root
38}; 39};
39 40
40// Converts a RomFS binary blob to VFS Filesystem 41// 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 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/frontend/applets/web_browser.h"
7
8namespace Core::Frontend {
9
10WebBrowserApplet::~WebBrowserApplet() = default;
11
12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
13
14void DefaultWebBrowserApplet::OpenPage(std::string_view filename,
15 std::function<void()> unpack_romfs_callback,
16 std::function<void()> finished_callback) const {
17 LOG_INFO(Service_AM,
18 "(STUBBED) called - No suitable web browser implementation found to open website page "
19 "at '{}'!",
20 filename);
21 finished_callback();
22}
23
24} // 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 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <string_view>
9
10namespace Core::Frontend {
11
12class WebBrowserApplet {
13public:
14 virtual ~WebBrowserApplet();
15
16 virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
17 std::function<void()> finished_callback) const = 0;
18};
19
20class DefaultWebBrowserApplet final : public WebBrowserApplet {
21public:
22 ~DefaultWebBrowserApplet() override;
23
24 void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
25 std::function<void()> finished_callback) const override;
26};
27
28} // 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 @@
23#include "core/hle/service/am/applets/profile_select.h" 23#include "core/hle/service/am/applets/profile_select.h"
24#include "core/hle/service/am/applets/software_keyboard.h" 24#include "core/hle/service/am/applets/software_keyboard.h"
25#include "core/hle/service/am/applets/stub_applet.h" 25#include "core/hle/service/am/applets/stub_applet.h"
26#include "core/hle/service/am/applets/web_browser.h"
26#include "core/hle/service/am/idle.h" 27#include "core/hle/service/am/idle.h"
27#include "core/hle/service/am/omm.h" 28#include "core/hle/service/am/omm.h"
28#include "core/hle/service/am/spsm.h" 29#include "core/hle/service/am/spsm.h"
@@ -44,6 +45,7 @@ constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
44enum class AppletId : u32 { 45enum class AppletId : u32 {
45 ProfileSelect = 0x10, 46 ProfileSelect = 0x10,
46 SoftwareKeyboard = 0x11, 47 SoftwareKeyboard = 0x11,
48 LibAppletOff = 0x17,
47}; 49};
48 50
49constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; 51constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
@@ -730,10 +732,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
730 IPC::RequestParser rp{ctx}; 732 IPC::RequestParser rp{ctx};
731 733
732 const u64 offset{rp.Pop<u64>()}; 734 const u64 offset{rp.Pop<u64>()};
733 LOG_DEBUG(Service_AM, "called, offset={}", offset);
734
735 const std::vector<u8> data{ctx.ReadBuffer()}; 735 const std::vector<u8> data{ctx.ReadBuffer()};
736 736
737 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
738
737 if (data.size() > backing.buffer.size() - offset) { 739 if (data.size() > backing.buffer.size() - offset) {
738 LOG_ERROR(Service_AM, 740 LOG_ERROR(Service_AM,
739 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", 741 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
@@ -753,10 +755,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
753 IPC::RequestParser rp{ctx}; 755 IPC::RequestParser rp{ctx};
754 756
755 const u64 offset{rp.Pop<u64>()}; 757 const u64 offset{rp.Pop<u64>()};
756 LOG_DEBUG(Service_AM, "called, offset={}", offset);
757
758 const std::size_t size{ctx.GetWriteBufferSize()}; 758 const std::size_t size{ctx.GetWriteBufferSize()};
759 759
760 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
761
760 if (size > backing.buffer.size() - offset) { 762 if (size > backing.buffer.size() - offset) {
761 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", 763 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
762 backing.buffer.size(), size, offset); 764 backing.buffer.size(), size, offset);
@@ -791,6 +793,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
791 return std::make_shared<Applets::ProfileSelect>(); 793 return std::make_shared<Applets::ProfileSelect>();
792 case AppletId::SoftwareKeyboard: 794 case AppletId::SoftwareKeyboard:
793 return std::make_shared<Applets::SoftwareKeyboard>(); 795 return std::make_shared<Applets::SoftwareKeyboard>();
796 case AppletId::LibAppletOff:
797 return std::make_shared<Applets::WebBrowser>();
794 default: 798 default:
795 LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", 799 LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
796 static_cast<u32>(id)); 800 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 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/string_util.h" 8#include "common/string_util.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/frontend/applets/software_keyboard.h" 10#include "core/frontend/applets/profile_select.h"
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/profile_select.h" 12#include "core/hle/service/am/applets/profile_select.h"
13 13
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 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_paths.h"
6#include "common/hex_util.h"
7#include "common/logging/backend.h"
8#include "common/string_util.h"
9#include "core/core.h"
10#include "core/file_sys/content_archive.h"
11#include "core/file_sys/mode.h"
12#include "core/file_sys/nca_metadata.h"
13#include "core/file_sys/registered_cache.h"
14#include "core/file_sys/romfs.h"
15#include "core/file_sys/romfs_factory.h"
16#include "core/file_sys/vfs_types.h"
17#include "core/frontend/applets/web_browser.h"
18#include "core/hle/kernel/process.h"
19#include "core/hle/service/am/applets/web_browser.h"
20#include "core/hle/service/filesystem/filesystem.h"
21#include "core/loader/loader.h"
22
23namespace Service::AM::Applets {
24
25// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
26// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
27// but some may be worth an implementation.
28constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6;
29
30struct WebBufferHeader {
31 u16 count;
32 INSERT_PADDING_BYTES(6);
33};
34static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
35
36struct WebArgumentHeader {
37 u16 type;
38 u16 size;
39 u32 offset;
40};
41static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
42
43struct WebArgumentResult {
44 u32 result_code;
45 std::array<char, 0x1000> last_url;
46 u64 last_url_size;
47};
48static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
49
50static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
51 WebBufferHeader header;
52 ASSERT(sizeof(WebBufferHeader) <= data.size());
53 std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
54
55 u64 offset = sizeof(WebBufferHeader);
56 for (u16 i = 0; i < header.count; ++i) {
57 WebArgumentHeader arg;
58 ASSERT(offset + sizeof(WebArgumentHeader) <= data.size());
59 std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
60 offset += sizeof(WebArgumentHeader);
61
62 if (arg.type == type) {
63 std::vector<u8> out(arg.size);
64 offset += arg.offset;
65 ASSERT(offset + arg.size <= data.size());
66 std::memcpy(out.data(), data.data() + offset, out.size());
67 return out;
68 }
69
70 offset += arg.offset + arg.size;
71 }
72
73 return {};
74}
75
76static FileSys::VirtualFile GetManualRomFS() {
77 auto& loader{Core::System::GetInstance().GetAppLoader()};
78
79 FileSys::VirtualFile out;
80 if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
81 return out;
82
83 const auto& installed{FileSystem::GetUnionContents()};
84 const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
85 FileSys::ContentRecordType::Manual);
86
87 if (res != nullptr)
88 return res->GetRomFS();
89 return nullptr;
90}
91
92WebBrowser::WebBrowser() = default;
93
94WebBrowser::~WebBrowser() = default;
95
96void WebBrowser::Initialize() {
97 Applet::Initialize();
98
99 complete = false;
100 temporary_dir.clear();
101 filename.clear();
102 status = RESULT_SUCCESS;
103
104 const auto web_arg_storage = broker.PopNormalDataToApplet();
105 ASSERT(web_arg_storage != nullptr);
106 const auto& web_arg = web_arg_storage->GetData();
107
108 const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
109 filename = Common::StringFromFixedZeroTerminatedBuffer(
110 reinterpret_cast<const char*>(url_data.data()), url_data.size());
111
112 temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
113 "web_applet_manual",
114 FileUtil::DirectorySeparator::PlatformDefault);
115 FileUtil::DeleteDirRecursively(temporary_dir);
116
117 manual_romfs = GetManualRomFS();
118 if (manual_romfs == nullptr) {
119 status = ResultCode(-1);
120 LOG_ERROR(Service_AM, "Failed to find manual for current process!");
121 }
122
123 filename =
124 FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
125 FileUtil::DirectorySeparator::PlatformDefault);
126}
127
128bool WebBrowser::TransactionComplete() const {
129 return complete;
130}
131
132ResultCode WebBrowser::GetStatus() const {
133 return status;
134}
135
136void WebBrowser::ExecuteInteractive() {
137 UNIMPLEMENTED_MSG("Unexpected interactive data recieved!");
138}
139
140void WebBrowser::Execute() {
141 if (complete)
142 return;
143
144 if (status != RESULT_SUCCESS) {
145 complete = true;
146 return;
147 }
148
149 const auto& frontend{Core::System::GetInstance().GetWebBrowser()};
150
151 frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
152}
153
154void WebBrowser::UnpackRomFS() {
155 if (unpacked)
156 return;
157
158 ASSERT(manual_romfs != nullptr);
159 const auto dir =
160 FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard);
161 const auto& vfs{Core::System::GetInstance().GetFilesystem()};
162 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
163 FileSys::VfsRawCopyD(dir, temp_dir);
164
165 unpacked = true;
166}
167
168void WebBrowser::Finalize() {
169 complete = true;
170
171 WebArgumentResult out{};
172 out.result_code = 0;
173 out.last_url_size = 0;
174
175 std::vector<u8> data(sizeof(WebArgumentResult));
176 std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
177
178 broker.PushNormalDataFromApplet(IStorage{data});
179 broker.SignalStateChanged();
180
181 FileUtil::DeleteDirRecursively(temporary_dir);
182}
183
184} // 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 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/file_sys/vfs_types.h"
8#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applets/applets.h"
10
11namespace Service::AM::Applets {
12
13class WebBrowser final : public Applet {
14public:
15 WebBrowser();
16 ~WebBrowser() override;
17
18 void Initialize() override;
19
20 bool TransactionComplete() const override;
21 ResultCode GetStatus() const override;
22 void ExecuteInteractive() override;
23 void Execute() override;
24
25 // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary
26 // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in
27 // size. Attempting to access files at filename before invocation is likely to not work.
28 void UnpackRomFS();
29
30 // Callback to be fired when the frontend is finished browsing. This will delete the temporary
31 // manual RomFS extracted files, so ensure this is only called at actual finalization.
32 void Finalize();
33
34private:
35 bool complete = false;
36 bool unpacked = false;
37 ResultCode status = RESULT_SUCCESS;
38
39 FileSys::VirtualFile manual_romfs;
40 std::string temporary_dir;
41 std::string filename;
42};
43
44} // 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) {
410 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; 410 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
411 libnx_entry.pad.l_stick = pad_state.l_stick; 411 libnx_entry.pad.l_stick = pad_state.l_stick;
412 libnx_entry.pad.r_stick = pad_state.r_stick; 412 libnx_entry.pad.r_stick = pad_state.r_stick;
413
414 press_state |= static_cast<u32>(pad_state.pad_states.raw);
413 } 415 }
414 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), 416 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
415 shared_memory_entries.size() * sizeof(NPadEntry)); 417 shared_memory_entries.size() * sizeof(NPadEntry));
@@ -636,6 +638,10 @@ void Controller_NPad::ClearAllControllers() {
636 }); 638 });
637} 639}
638 640
641u32 Controller_NPad::GetAndResetPressState() {
642 return std::exchange(press_state, 0);
643}
644
639bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { 645bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
640 const bool support_handheld = 646 const bool support_handheld =
641 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != 647 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:
124 void ConnectAllDisconnectedControllers(); 124 void ConnectAllDisconnectedControllers();
125 void ClearAllControllers(); 125 void ClearAllControllers();
126 126
127 // Logical OR for all buttons presses on all controllers
128 // Specifically for cheat engine and other features.
129 u32 GetAndResetPressState();
130
127 static std::size_t NPadIdToIndex(u32 npad_id); 131 static std::size_t NPadIdToIndex(u32 npad_id);
128 static u32 IndexToNPad(std::size_t index); 132 static u32 IndexToNPad(std::size_t index);
129 133
@@ -292,6 +296,8 @@ private:
292 bool is_connected; 296 bool is_connected;
293 }; 297 };
294 298
299 u32 press_state{};
300
295 NPadType style{}; 301 NPadType style{};
296 std::array<NPadEntry, 10> shared_memory_entries{}; 302 std::array<NPadEntry, 10> shared_memory_entries{};
297 std::array< 303 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;
40constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 40constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
41constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 41constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
42constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 42constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
43enum class HidController : std::size_t {
44 DebugPad,
45 Touchscreen,
46 Mouse,
47 Keyboard,
48 XPad,
49 Unknown1,
50 Unknown2,
51 Unknown3,
52 SixAxisSensor,
53 NPad,
54 Gesture,
55
56 MaxControllers,
57};
58
59class IAppletResource final : public ServiceFramework<IAppletResource> {
60public:
61 IAppletResource() : ServiceFramework("IAppletResource") {
62 static const FunctionInfo functions[] = {
63 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
64 };
65 RegisterHandlers(functions);
66 43
67 auto& kernel = Core::System::GetInstance().Kernel(); 44IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
68 shared_mem = Kernel::SharedMemory::Create( 45 static const FunctionInfo functions[] = {
69 kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, 46 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
70 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); 47 };
71 48 RegisterHandlers(functions);
72 MakeController<Controller_DebugPad>(HidController::DebugPad); 49
73 MakeController<Controller_Touchscreen>(HidController::Touchscreen); 50 auto& kernel = Core::System::GetInstance().Kernel();
74 MakeController<Controller_Mouse>(HidController::Mouse); 51 shared_mem = Kernel::SharedMemory::Create(
75 MakeController<Controller_Keyboard>(HidController::Keyboard); 52 kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
76 MakeController<Controller_XPad>(HidController::XPad); 53 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
77 MakeController<Controller_Stubbed>(HidController::Unknown1); 54
78 MakeController<Controller_Stubbed>(HidController::Unknown2); 55 MakeController<Controller_DebugPad>(HidController::DebugPad);
79 MakeController<Controller_Stubbed>(HidController::Unknown3); 56 MakeController<Controller_Touchscreen>(HidController::Touchscreen);
80 MakeController<Controller_Stubbed>(HidController::SixAxisSensor); 57 MakeController<Controller_Mouse>(HidController::Mouse);
81 MakeController<Controller_NPad>(HidController::NPad); 58 MakeController<Controller_Keyboard>(HidController::Keyboard);
82 MakeController<Controller_Gesture>(HidController::Gesture); 59 MakeController<Controller_XPad>(HidController::XPad);
83 60 MakeController<Controller_Stubbed>(HidController::Unknown1);
84 // Homebrew doesn't try to activate some controllers, so we activate them by default 61 MakeController<Controller_Stubbed>(HidController::Unknown2);
85 GetController<Controller_NPad>(HidController::NPad).ActivateController(); 62 MakeController<Controller_Stubbed>(HidController::Unknown3);
86 GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); 63 MakeController<Controller_Stubbed>(HidController::SixAxisSensor);
87 64 MakeController<Controller_NPad>(HidController::NPad);
88 GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); 65 MakeController<Controller_Gesture>(HidController::Gesture);
89 GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); 66
90 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); 67 // Homebrew doesn't try to activate some controllers, so we activate them by default
91 68 GetController<Controller_NPad>(HidController::NPad).ActivateController();
92 // Register update callbacks 69 GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
93 pad_update_event = CoreTiming::RegisterEvent( 70
94 "HID::UpdatePadCallback", 71 GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00);
95 [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); 72 GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00);
96 73 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
97 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 74
98 75 // Register update callbacks
99 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); 76 pad_update_event =
100 77 CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
101 ReloadInputDevices(); 78 UpdateControllers(userdata, cycles_late);
102 } 79 });
103 80
104 void ActivateController(HidController controller) { 81 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
105 controllers[static_cast<size_t>(controller)]->ActivateController(); 82
106 } 83 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
107 84
108 void DeactivateController(HidController controller) { 85 ReloadInputDevices();
109 controllers[static_cast<size_t>(controller)]->DeactivateController(); 86}
110 }
111 87
112 template <typename T> 88void IAppletResource::ActivateController(HidController controller) {
113 void MakeController(HidController controller) { 89 controllers[static_cast<size_t>(controller)]->ActivateController();
114 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); 90}
115 }
116 91
117 template <typename T> 92void IAppletResource::DeactivateController(HidController controller) {
118 T& GetController(HidController controller) { 93 controllers[static_cast<size_t>(controller)]->DeactivateController();
119 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); 94}
120 }
121 95
122 ~IAppletResource() { 96IAppletResource ::~IAppletResource() {
123 CoreTiming::UnscheduleEvent(pad_update_event, 0); 97 CoreTiming::UnscheduleEvent(pad_update_event, 0);
124 } 98}
125 99
126private: 100void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
127 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 101 LOG_DEBUG(Service_HID, "called");
128 LOG_DEBUG(Service_HID, "called");
129 102
130 IPC::ResponseBuilder rb{ctx, 2, 1}; 103 IPC::ResponseBuilder rb{ctx, 2, 1};
131 rb.Push(RESULT_SUCCESS); 104 rb.Push(RESULT_SUCCESS);
132 rb.PushCopyObjects(shared_mem); 105 rb.PushCopyObjects(shared_mem);
133 } 106}
134 107
135 void UpdateControllers(u64 userdata, int cycles_late) { 108void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
136 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 109 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
137 for (const auto& controller : controllers) { 110 for (const auto& controller : controllers) {
138 if (should_reload) { 111 if (should_reload) {
139 controller->OnLoadInputDevices(); 112 controller->OnLoadInputDevices();
140 }
141 controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
142 } 113 }
143 114 controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
144 CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
145 } 115 }
146 116
147 // Handle to shared memory region designated to HID service 117 CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
148 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; 118}
149
150 // CoreTiming update events
151 CoreTiming::EventType* pad_update_event;
152
153 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
154 controllers{};
155};
156 119
157class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 120class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
158public: 121public:
@@ -172,599 +135,597 @@ private:
172 } 135 }
173}; 136};
174 137
175class Hid final : public ServiceFramework<Hid> { 138std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
176public: 139 if (applet_resource == nullptr) {
177 Hid() : ServiceFramework("hid") { 140 applet_resource = std::make_shared<IAppletResource>();
178 // clang-format off
179 static const FunctionInfo functions[] = {
180 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
181 {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
182 {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
183 {21, &Hid::ActivateMouse, "ActivateMouse"},
184 {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
185 {32, nullptr, "SendKeyboardLockKeyEvent"},
186 {40, nullptr, "AcquireXpadIdEventHandle"},
187 {41, nullptr, "ReleaseXpadIdEventHandle"},
188 {51, &Hid::ActivateXpad, "ActivateXpad"},
189 {55, nullptr, "GetXpadIds"},
190 {56, nullptr, "ActivateJoyXpad"},
191 {58, nullptr, "GetJoyXpadLifoHandle"},
192 {59, nullptr, "GetJoyXpadIds"},
193 {60, nullptr, "ActivateSixAxisSensor"},
194 {61, nullptr, "DeactivateSixAxisSensor"},
195 {62, nullptr, "GetSixAxisSensorLifoHandle"},
196 {63, nullptr, "ActivateJoySixAxisSensor"},
197 {64, nullptr, "DeactivateJoySixAxisSensor"},
198 {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
199 {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
200 {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
201 {68, nullptr, "IsSixAxisSensorFusionEnabled"},
202 {69, nullptr, "EnableSixAxisSensorFusion"},
203 {70, nullptr, "SetSixAxisSensorFusionParameters"},
204 {71, nullptr, "GetSixAxisSensorFusionParameters"},
205 {72, nullptr, "ResetSixAxisSensorFusionParameters"},
206 {73, nullptr, "SetAccelerometerParameters"},
207 {74, nullptr, "GetAccelerometerParameters"},
208 {75, nullptr, "ResetAccelerometerParameters"},
209 {76, nullptr, "SetAccelerometerPlayMode"},
210 {77, nullptr, "GetAccelerometerPlayMode"},
211 {78, nullptr, "ResetAccelerometerPlayMode"},
212 {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
213 {80, nullptr, "GetGyroscopeZeroDriftMode"},
214 {81, nullptr, "ResetGyroscopeZeroDriftMode"},
215 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
216 {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"},
217 {91, &Hid::ActivateGesture, "ActivateGesture"},
218 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
219 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
220 {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
221 {103, &Hid::ActivateNpad, "ActivateNpad"},
222 {104, nullptr, "DeactivateNpad"},
223 {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
224 {107, &Hid::DisconnectNpad, "DisconnectNpad"},
225 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
226 {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
227 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
228 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
229 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
230 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
231 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
232 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
233 {126, nullptr, "StartLrAssignmentMode"},
234 {127, nullptr, "StopLrAssignmentMode"},
235 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
236 {129, nullptr, "GetNpadHandheldActivationMode"},
237 {130, nullptr, "SwapNpadAssignment"},
238 {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
239 {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
240 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
241 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
242 {201, &Hid::SendVibrationValue, "SendVibrationValue"},
243 {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
244 {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
245 {204, nullptr, "PermitVibration"},
246 {205, nullptr, "IsVibrationPermitted"},
247 {206, &Hid::SendVibrationValues, "SendVibrationValues"},
248 {207, nullptr, "SendVibrationGcErmCommand"},
249 {208, nullptr, "GetActualVibrationGcErmCommand"},
250 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
251 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
252 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
253 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
254 {302, nullptr, "StopConsoleSixAxisSensor"},
255 {303, nullptr, "ActivateSevenSixAxisSensor"},
256 {304, nullptr, "StartSevenSixAxisSensor"},
257 {305, nullptr, "StopSevenSixAxisSensor"},
258 {306, nullptr, "InitializeSevenSixAxisSensor"},
259 {307, nullptr, "FinalizeSevenSixAxisSensor"},
260 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
261 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
262 {310, nullptr, "ResetSevenSixAxisSensorTimestamp"},
263 {400, nullptr, "IsUsbFullKeyControllerEnabled"},
264 {401, nullptr, "EnableUsbFullKeyController"},
265 {402, nullptr, "IsUsbFullKeyControllerConnected"},
266 {403, nullptr, "HasBattery"},
267 {404, nullptr, "HasLeftRightBattery"},
268 {405, nullptr, "GetNpadInterfaceType"},
269 {406, nullptr, "GetNpadLeftRightInterfaceType"},
270 {500, nullptr, "GetPalmaConnectionHandle"},
271 {501, nullptr, "InitializePalma"},
272 {502, nullptr, "AcquirePalmaOperationCompleteEvent"},
273 {503, nullptr, "GetPalmaOperationInfo"},
274 {504, nullptr, "PlayPalmaActivity"},
275 {505, nullptr, "SetPalmaFrModeType"},
276 {506, nullptr, "ReadPalmaStep"},
277 {507, nullptr, "EnablePalmaStep"},
278 {508, nullptr, "ResetPalmaStep"},
279 {509, nullptr, "ReadPalmaApplicationSection"},
280 {510, nullptr, "WritePalmaApplicationSection"},
281 {511, nullptr, "ReadPalmaUniqueCode"},
282 {512, nullptr, "SetPalmaUniqueCodeInvalid"},
283 {513, nullptr, "WritePalmaActivityEntry"},
284 {514, nullptr, "WritePalmaRgbLedPatternEntry"},
285 {515, nullptr, "WritePalmaWaveEntry"},
286 {516, nullptr, "SetPalmaDataBaseIdentificationVersion"},
287 {517, nullptr, "GetPalmaDataBaseIdentificationVersion"},
288 {518, nullptr, "SuspendPalmaFeature"},
289 {519, nullptr, "GetPalmaOperationResult"},
290 {520, nullptr, "ReadPalmaPlayLog"},
291 {521, nullptr, "ResetPalmaPlayLog"},
292 {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
293 {523, nullptr, "SetIsPalmaPairedConnectable"},
294 {524, nullptr, "PairPalma"},
295 {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
296 {1000, nullptr, "SetNpadCommunicationMode"},
297 {1001, nullptr, "GetNpadCommunicationMode"},
298 };
299 // clang-format on
300
301 RegisterHandlers(functions);
302 } 141 }
303 ~Hid() = default;
304 142
305private: 143 return applet_resource;
306 std::shared_ptr<IAppletResource> applet_resource; 144}
307 145
308 void CreateAppletResource(Kernel::HLERequestContext& ctx) { 146Hid::Hid() : ServiceFramework("hid") {
309 IPC::RequestParser rp{ctx}; 147 // clang-format off
310 const auto applet_resource_user_id{rp.Pop<u64>()}; 148 static const FunctionInfo functions[] = {
149 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
150 {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
151 {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
152 {21, &Hid::ActivateMouse, "ActivateMouse"},
153 {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
154 {32, nullptr, "SendKeyboardLockKeyEvent"},
155 {40, nullptr, "AcquireXpadIdEventHandle"},
156 {41, nullptr, "ReleaseXpadIdEventHandle"},
157 {51, &Hid::ActivateXpad, "ActivateXpad"},
158 {55, nullptr, "GetXpadIds"},
159 {56, nullptr, "ActivateJoyXpad"},
160 {58, nullptr, "GetJoyXpadLifoHandle"},
161 {59, nullptr, "GetJoyXpadIds"},
162 {60, nullptr, "ActivateSixAxisSensor"},
163 {61, nullptr, "DeactivateSixAxisSensor"},
164 {62, nullptr, "GetSixAxisSensorLifoHandle"},
165 {63, nullptr, "ActivateJoySixAxisSensor"},
166 {64, nullptr, "DeactivateJoySixAxisSensor"},
167 {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
168 {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
169 {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
170 {68, nullptr, "IsSixAxisSensorFusionEnabled"},
171 {69, nullptr, "EnableSixAxisSensorFusion"},
172 {70, nullptr, "SetSixAxisSensorFusionParameters"},
173 {71, nullptr, "GetSixAxisSensorFusionParameters"},
174 {72, nullptr, "ResetSixAxisSensorFusionParameters"},
175 {73, nullptr, "SetAccelerometerParameters"},
176 {74, nullptr, "GetAccelerometerParameters"},
177 {75, nullptr, "ResetAccelerometerParameters"},
178 {76, nullptr, "SetAccelerometerPlayMode"},
179 {77, nullptr, "GetAccelerometerPlayMode"},
180 {78, nullptr, "ResetAccelerometerPlayMode"},
181 {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
182 {80, nullptr, "GetGyroscopeZeroDriftMode"},
183 {81, nullptr, "ResetGyroscopeZeroDriftMode"},
184 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
185 {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"},
186 {91, &Hid::ActivateGesture, "ActivateGesture"},
187 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
188 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
189 {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
190 {103, &Hid::ActivateNpad, "ActivateNpad"},
191 {104, nullptr, "DeactivateNpad"},
192 {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
193 {107, &Hid::DisconnectNpad, "DisconnectNpad"},
194 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
195 {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
196 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
197 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
198 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
199 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
200 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
201 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
202 {126, nullptr, "StartLrAssignmentMode"},
203 {127, nullptr, "StopLrAssignmentMode"},
204 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
205 {129, nullptr, "GetNpadHandheldActivationMode"},
206 {130, nullptr, "SwapNpadAssignment"},
207 {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
208 {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
209 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
210 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
211 {201, &Hid::SendVibrationValue, "SendVibrationValue"},
212 {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
213 {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
214 {204, nullptr, "PermitVibration"},
215 {205, nullptr, "IsVibrationPermitted"},
216 {206, &Hid::SendVibrationValues, "SendVibrationValues"},
217 {207, nullptr, "SendVibrationGcErmCommand"},
218 {208, nullptr, "GetActualVibrationGcErmCommand"},
219 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
220 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
221 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
222 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
223 {302, nullptr, "StopConsoleSixAxisSensor"},
224 {303, nullptr, "ActivateSevenSixAxisSensor"},
225 {304, nullptr, "StartSevenSixAxisSensor"},
226 {305, nullptr, "StopSevenSixAxisSensor"},
227 {306, nullptr, "InitializeSevenSixAxisSensor"},
228 {307, nullptr, "FinalizeSevenSixAxisSensor"},
229 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
230 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
231 {310, nullptr, "ResetSevenSixAxisSensorTimestamp"},
232 {400, nullptr, "IsUsbFullKeyControllerEnabled"},
233 {401, nullptr, "EnableUsbFullKeyController"},
234 {402, nullptr, "IsUsbFullKeyControllerConnected"},
235 {403, nullptr, "HasBattery"},
236 {404, nullptr, "HasLeftRightBattery"},
237 {405, nullptr, "GetNpadInterfaceType"},
238 {406, nullptr, "GetNpadLeftRightInterfaceType"},
239 {500, nullptr, "GetPalmaConnectionHandle"},
240 {501, nullptr, "InitializePalma"},
241 {502, nullptr, "AcquirePalmaOperationCompleteEvent"},
242 {503, nullptr, "GetPalmaOperationInfo"},
243 {504, nullptr, "PlayPalmaActivity"},
244 {505, nullptr, "SetPalmaFrModeType"},
245 {506, nullptr, "ReadPalmaStep"},
246 {507, nullptr, "EnablePalmaStep"},
247 {508, nullptr, "ResetPalmaStep"},
248 {509, nullptr, "ReadPalmaApplicationSection"},
249 {510, nullptr, "WritePalmaApplicationSection"},
250 {511, nullptr, "ReadPalmaUniqueCode"},
251 {512, nullptr, "SetPalmaUniqueCodeInvalid"},
252 {513, nullptr, "WritePalmaActivityEntry"},
253 {514, nullptr, "WritePalmaRgbLedPatternEntry"},
254 {515, nullptr, "WritePalmaWaveEntry"},
255 {516, nullptr, "SetPalmaDataBaseIdentificationVersion"},
256 {517, nullptr, "GetPalmaDataBaseIdentificationVersion"},
257 {518, nullptr, "SuspendPalmaFeature"},
258 {519, nullptr, "GetPalmaOperationResult"},
259 {520, nullptr, "ReadPalmaPlayLog"},
260 {521, nullptr, "ResetPalmaPlayLog"},
261 {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
262 {523, nullptr, "SetIsPalmaPairedConnectable"},
263 {524, nullptr, "PairPalma"},
264 {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
265 {1000, nullptr, "SetNpadCommunicationMode"},
266 {1001, nullptr, "GetNpadCommunicationMode"},
267 };
268 // clang-format on
269
270 RegisterHandlers(functions);
271}
311 272
312 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 273Hid::~Hid() = default;
313 274
314 if (applet_resource == nullptr) { 275void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
315 applet_resource = std::make_shared<IAppletResource>(); 276 IPC::RequestParser rp{ctx};
316 } 277 const auto applet_resource_user_id{rp.Pop<u64>()};
317 278
318 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 279 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
319 rb.Push(RESULT_SUCCESS); 280
320 rb.PushIpcInterface<IAppletResource>(applet_resource); 281 if (applet_resource == nullptr) {
282 applet_resource = std::make_shared<IAppletResource>();
321 } 283 }
322 284
323 void ActivateXpad(Kernel::HLERequestContext& ctx) { 285 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
324 IPC::RequestParser rp{ctx}; 286 rb.Push(RESULT_SUCCESS);
325 const auto basic_xpad_id{rp.Pop<u32>()}; 287 rb.PushIpcInterface<IAppletResource>(applet_resource);
326 const auto applet_resource_user_id{rp.Pop<u64>()}; 288}
327 289
328 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", 290void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
329 basic_xpad_id, applet_resource_user_id); 291 IPC::RequestParser rp{ctx};
292 const auto basic_xpad_id{rp.Pop<u32>()};
293 const auto applet_resource_user_id{rp.Pop<u64>()};
330 294
331 applet_resource->ActivateController(HidController::XPad); 295 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id,
332 IPC::ResponseBuilder rb{ctx, 2}; 296 applet_resource_user_id);
333 rb.Push(RESULT_SUCCESS);
334 }
335 297
336 void ActivateDebugPad(Kernel::HLERequestContext& ctx) { 298 applet_resource->ActivateController(HidController::XPad);
337 IPC::RequestParser rp{ctx}; 299 IPC::ResponseBuilder rb{ctx, 2};
338 const auto applet_resource_user_id{rp.Pop<u64>()}; 300 rb.Push(RESULT_SUCCESS);
301}
339 302
340 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 303void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
304 IPC::RequestParser rp{ctx};
305 const auto applet_resource_user_id{rp.Pop<u64>()};
341 306
342 applet_resource->ActivateController(HidController::DebugPad); 307 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
343 IPC::ResponseBuilder rb{ctx, 2};
344 rb.Push(RESULT_SUCCESS);
345 }
346 308
347 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 309 applet_resource->ActivateController(HidController::DebugPad);
348 IPC::RequestParser rp{ctx}; 310 IPC::ResponseBuilder rb{ctx, 2};
349 const auto applet_resource_user_id{rp.Pop<u64>()}; 311 rb.Push(RESULT_SUCCESS);
312}
350 313
351 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 314void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
315 IPC::RequestParser rp{ctx};
316 const auto applet_resource_user_id{rp.Pop<u64>()};
352 317
353 applet_resource->ActivateController(HidController::Touchscreen); 318 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
354 IPC::ResponseBuilder rb{ctx, 2};
355 rb.Push(RESULT_SUCCESS);
356 }
357 319
358 void ActivateMouse(Kernel::HLERequestContext& ctx) { 320 applet_resource->ActivateController(HidController::Touchscreen);
359 IPC::RequestParser rp{ctx}; 321 IPC::ResponseBuilder rb{ctx, 2};
360 const auto applet_resource_user_id{rp.Pop<u64>()}; 322 rb.Push(RESULT_SUCCESS);
323}
361 324
362 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 325void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
326 IPC::RequestParser rp{ctx};
327 const auto applet_resource_user_id{rp.Pop<u64>()};
363 328
364 applet_resource->ActivateController(HidController::Mouse); 329 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
365 IPC::ResponseBuilder rb{ctx, 2};
366 rb.Push(RESULT_SUCCESS);
367 }
368 330
369 void ActivateKeyboard(Kernel::HLERequestContext& ctx) { 331 applet_resource->ActivateController(HidController::Mouse);
370 IPC::RequestParser rp{ctx}; 332 IPC::ResponseBuilder rb{ctx, 2};
371 const auto applet_resource_user_id{rp.Pop<u64>()}; 333 rb.Push(RESULT_SUCCESS);
334}
372 335
373 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 336void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
337 IPC::RequestParser rp{ctx};
338 const auto applet_resource_user_id{rp.Pop<u64>()};
374 339
375 applet_resource->ActivateController(HidController::Keyboard); 340 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
376 IPC::ResponseBuilder rb{ctx, 2};
377 rb.Push(RESULT_SUCCESS);
378 }
379 341
380 void ActivateGesture(Kernel::HLERequestContext& ctx) { 342 applet_resource->ActivateController(HidController::Keyboard);
381 IPC::RequestParser rp{ctx}; 343 IPC::ResponseBuilder rb{ctx, 2};
382 const auto unknown{rp.Pop<u32>()}; 344 rb.Push(RESULT_SUCCESS);
383 const auto applet_resource_user_id{rp.Pop<u64>()}; 345}
384 346
385 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 347void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
386 applet_resource_user_id); 348 IPC::RequestParser rp{ctx};
349 const auto unknown{rp.Pop<u32>()};
350 const auto applet_resource_user_id{rp.Pop<u64>()};
387 351
388 applet_resource->ActivateController(HidController::Gesture); 352 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
389 IPC::ResponseBuilder rb{ctx, 2}; 353 applet_resource_user_id);
390 rb.Push(RESULT_SUCCESS);
391 }
392 354
393 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { 355 applet_resource->ActivateController(HidController::Gesture);
394 // Should have no effect with how our npad sets up the data 356 IPC::ResponseBuilder rb{ctx, 2};
395 IPC::RequestParser rp{ctx}; 357 rb.Push(RESULT_SUCCESS);
396 const auto unknown{rp.Pop<u32>()}; 358}
397 const auto applet_resource_user_id{rp.Pop<u64>()};
398 359
399 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 360void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
400 applet_resource_user_id); 361 // Should have no effect with how our npad sets up the data
362 IPC::RequestParser rp{ctx};
363 const auto unknown{rp.Pop<u32>()};
364 const auto applet_resource_user_id{rp.Pop<u64>()};
401 365
402 applet_resource->ActivateController(HidController::NPad); 366 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
403 IPC::ResponseBuilder rb{ctx, 2}; 367 applet_resource_user_id);
404 rb.Push(RESULT_SUCCESS);
405 }
406 368
407 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 369 applet_resource->ActivateController(HidController::NPad);
408 IPC::RequestParser rp{ctx}; 370 IPC::ResponseBuilder rb{ctx, 2};
409 const auto handle{rp.Pop<u32>()}; 371 rb.Push(RESULT_SUCCESS);
410 const auto applet_resource_user_id{rp.Pop<u64>()}; 372}
411 373
412 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 374void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
413 applet_resource_user_id); 375 IPC::RequestParser rp{ctx};
376 const auto handle{rp.Pop<u32>()};
377 const auto applet_resource_user_id{rp.Pop<u64>()};
414 378
415 IPC::ResponseBuilder rb{ctx, 2}; 379 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
416 rb.Push(RESULT_SUCCESS); 380 applet_resource_user_id);
417 }
418 381
419 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 382 IPC::ResponseBuilder rb{ctx, 2};
420 IPC::RequestParser rp{ctx}; 383 rb.Push(RESULT_SUCCESS);
421 const auto handle{rp.Pop<u32>()}; 384}
422 const auto drift_mode{rp.Pop<u32>()};
423 const auto applet_resource_user_id{rp.Pop<u64>()};
424 385
425 LOG_WARNING(Service_HID, 386void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
426 "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", 387 IPC::RequestParser rp{ctx};
427 handle, drift_mode, applet_resource_user_id); 388 const auto handle{rp.Pop<u32>()};
389 const auto drift_mode{rp.Pop<u32>()};
390 const auto applet_resource_user_id{rp.Pop<u64>()};
428 391
429 IPC::ResponseBuilder rb{ctx, 2}; 392 LOG_WARNING(Service_HID,
430 rb.Push(RESULT_SUCCESS); 393 "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
431 } 394 drift_mode, applet_resource_user_id);
432 395
433 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 396 IPC::ResponseBuilder rb{ctx, 2};
434 IPC::RequestParser rp{ctx}; 397 rb.Push(RESULT_SUCCESS);
435 const auto handle{rp.Pop<u32>()}; 398}
436 const auto applet_resource_user_id{rp.Pop<u64>()};
437 399
438 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 400void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
439 applet_resource_user_id); 401 IPC::RequestParser rp{ctx};
402 const auto handle{rp.Pop<u32>()};
403 const auto applet_resource_user_id{rp.Pop<u64>()};
440 404
441 IPC::ResponseBuilder rb{ctx, 3}; 405 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
442 rb.Push(RESULT_SUCCESS); 406 applet_resource_user_id);
443 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
444 rb.Push(true);
445 }
446 407
447 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 408 IPC::ResponseBuilder rb{ctx, 3};
448 IPC::RequestParser rp{ctx}; 409 rb.Push(RESULT_SUCCESS);
449 const auto supported_styleset{rp.Pop<u32>()}; 410 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
411 rb.Push(true);
412}
450 413
451 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); 414void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
415 IPC::RequestParser rp{ctx};
416 const auto supported_styleset{rp.Pop<u32>()};
452 417
453 applet_resource->GetController<Controller_NPad>(HidController::NPad) 418 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
454 .SetSupportedStyleSet({supported_styleset});
455 419
456 IPC::ResponseBuilder rb{ctx, 2}; 420 applet_resource->GetController<Controller_NPad>(HidController::NPad)
457 rb.Push(RESULT_SUCCESS); 421 .SetSupportedStyleSet({supported_styleset});
458 }
459 422
460 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 423 IPC::ResponseBuilder rb{ctx, 2};
461 IPC::RequestParser rp{ctx}; 424 rb.Push(RESULT_SUCCESS);
462 const auto applet_resource_user_id{rp.Pop<u64>()}; 425}
463 426
464 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 427void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
428 IPC::RequestParser rp{ctx};
429 const auto applet_resource_user_id{rp.Pop<u64>()};
465 430
466 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 431 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
467 432
468 IPC::ResponseBuilder rb{ctx, 3}; 433 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
469 rb.Push(RESULT_SUCCESS);
470 rb.Push<u32>(controller.GetSupportedStyleSet().raw);
471 }
472 434
473 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 435 IPC::ResponseBuilder rb{ctx, 3};
474 IPC::RequestParser rp{ctx}; 436 rb.Push(RESULT_SUCCESS);
475 const auto applet_resource_user_id{rp.Pop<u64>()}; 437 rb.Push<u32>(controller.GetSupportedStyleSet().raw);
438}
476 439
477 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 440void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
441 IPC::RequestParser rp{ctx};
442 const auto applet_resource_user_id{rp.Pop<u64>()};
478 443
479 applet_resource->GetController<Controller_NPad>(HidController::NPad) 444 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
480 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
481 IPC::ResponseBuilder rb{ctx, 2};
482 rb.Push(RESULT_SUCCESS);
483 }
484 445
485 void ActivateNpad(Kernel::HLERequestContext& ctx) { 446 applet_resource->GetController<Controller_NPad>(HidController::NPad)
486 IPC::RequestParser rp{ctx}; 447 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
487 const auto applet_resource_user_id{rp.Pop<u64>()}; 448 IPC::ResponseBuilder rb{ctx, 2};
449 rb.Push(RESULT_SUCCESS);
450}
488 451
489 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 452void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
453 IPC::RequestParser rp{ctx};
454 const auto applet_resource_user_id{rp.Pop<u64>()};
490 455
491 IPC::ResponseBuilder rb{ctx, 2}; 456 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
492 rb.Push(RESULT_SUCCESS);
493 applet_resource->ActivateController(HidController::NPad);
494 }
495 457
496 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 458 IPC::ResponseBuilder rb{ctx, 2};
497 IPC::RequestParser rp{ctx}; 459 rb.Push(RESULT_SUCCESS);
498 const auto npad_id{rp.Pop<u32>()}; 460 applet_resource->ActivateController(HidController::NPad);
499 const auto applet_resource_user_id{rp.Pop<u64>()}; 461}
500 const auto unknown{rp.Pop<u64>()};
501 462
502 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", 463void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
503 npad_id, applet_resource_user_id, unknown); 464 IPC::RequestParser rp{ctx};
465 const auto npad_id{rp.Pop<u32>()};
466 const auto applet_resource_user_id{rp.Pop<u64>()};
467 const auto unknown{rp.Pop<u64>()};
504 468
505 IPC::ResponseBuilder rb{ctx, 2, 1}; 469 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id,
506 rb.Push(RESULT_SUCCESS); 470 applet_resource_user_id, unknown);
507 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
508 .GetStyleSetChangedEvent());
509 }
510 471
511 void DisconnectNpad(Kernel::HLERequestContext& ctx) { 472 IPC::ResponseBuilder rb{ctx, 2, 1};
512 IPC::RequestParser rp{ctx}; 473 rb.Push(RESULT_SUCCESS);
513 const auto npad_id{rp.Pop<u32>()}; 474 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
514 const auto applet_resource_user_id{rp.Pop<u64>()}; 475 .GetStyleSetChangedEvent());
476}
515 477
516 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 478void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
517 applet_resource_user_id); 479 IPC::RequestParser rp{ctx};
480 const auto npad_id{rp.Pop<u32>()};
481 const auto applet_resource_user_id{rp.Pop<u64>()};
518 482
519 applet_resource->GetController<Controller_NPad>(HidController::NPad) 483 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
520 .DisconnectNPad(npad_id); 484 applet_resource_user_id);
521 IPC::ResponseBuilder rb{ctx, 2};
522 rb.Push(RESULT_SUCCESS);
523 }
524 485
525 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { 486 applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
526 IPC::RequestParser rp{ctx}; 487 IPC::ResponseBuilder rb{ctx, 2};
527 const auto npad_id{rp.Pop<u32>()}; 488 rb.Push(RESULT_SUCCESS);
489}
528 490
529 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); 491void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
492 IPC::RequestParser rp{ctx};
493 const auto npad_id{rp.Pop<u32>()};
530 494
531 IPC::ResponseBuilder rb{ctx, 4}; 495 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
532 rb.Push(RESULT_SUCCESS);
533 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
534 .GetLedPattern(npad_id)
535 .raw);
536 }
537 496
538 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 497 IPC::ResponseBuilder rb{ctx, 4};
539 IPC::RequestParser rp{ctx}; 498 rb.Push(RESULT_SUCCESS);
540 const auto applet_resource_user_id{rp.Pop<u64>()}; 499 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
541 const auto hold_type{rp.Pop<u64>()}; 500 .GetLedPattern(npad_id)
501 .raw);
502}
542 503
543 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", 504void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
544 applet_resource_user_id, hold_type); 505 IPC::RequestParser rp{ctx};
506 const auto applet_resource_user_id{rp.Pop<u64>()};
507 const auto hold_type{rp.Pop<u64>()};
545 508
546 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 509 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
547 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); 510 applet_resource_user_id, hold_type);
548 511
549 IPC::ResponseBuilder rb{ctx, 2}; 512 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
550 rb.Push(RESULT_SUCCESS); 513 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
551 }
552 514
553 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 515 IPC::ResponseBuilder rb{ctx, 2};
554 IPC::RequestParser rp{ctx}; 516 rb.Push(RESULT_SUCCESS);
555 const auto applet_resource_user_id{rp.Pop<u64>()}; 517}
556 518
557 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 519void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
520 IPC::RequestParser rp{ctx};
521 const auto applet_resource_user_id{rp.Pop<u64>()};
558 522
559 const auto& controller = 523 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
560 applet_resource->GetController<Controller_NPad>(HidController::NPad);
561 IPC::ResponseBuilder rb{ctx, 4};
562 rb.Push(RESULT_SUCCESS);
563 rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
564 }
565 524
566 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 525 const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
567 IPC::RequestParser rp{ctx}; 526 IPC::ResponseBuilder rb{ctx, 4};
568 const auto npad_id{rp.Pop<u32>()}; 527 rb.Push(RESULT_SUCCESS);
569 const auto applet_resource_user_id{rp.Pop<u64>()}; 528 rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
529}
570 530
571 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", 531void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
572 npad_id, applet_resource_user_id); 532 IPC::RequestParser rp{ctx};
533 const auto npad_id{rp.Pop<u32>()};
534 const auto applet_resource_user_id{rp.Pop<u64>()};
573 535
574 IPC::ResponseBuilder rb{ctx, 2}; 536 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
575 rb.Push(RESULT_SUCCESS); 537 applet_resource_user_id);
576 }
577 538
578 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 539 IPC::ResponseBuilder rb{ctx, 2};
579 IPC::RequestParser rp{ctx}; 540 rb.Push(RESULT_SUCCESS);
580 const auto applet_resource_user_id{rp.Pop<u64>()}; 541}
581 542
582 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 543void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
544 IPC::RequestParser rp{ctx};
545 const auto applet_resource_user_id{rp.Pop<u64>()};
583 546
584 applet_resource->GetController<Controller_NPad>(HidController::NPad) 547 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
585 .SetVibrationEnabled(true);
586 IPC::ResponseBuilder rb{ctx, 2};
587 rb.Push(RESULT_SUCCESS);
588 }
589 548
590 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { 549 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
591 LOG_DEBUG(Service_HID, "called"); 550 IPC::ResponseBuilder rb{ctx, 2};
551 rb.Push(RESULT_SUCCESS);
552}
592 553
593 applet_resource->GetController<Controller_NPad>(HidController::NPad) 554void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
594 .SetVibrationEnabled(false); 555 LOG_DEBUG(Service_HID, "called");
595 IPC::ResponseBuilder rb{ctx, 2};
596 rb.Push(RESULT_SUCCESS);
597 }
598 556
599 void SendVibrationValue(Kernel::HLERequestContext& ctx) { 557 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
600 IPC::RequestParser rp{ctx}; 558 IPC::ResponseBuilder rb{ctx, 2};
601 const auto controller_id{rp.Pop<u32>()}; 559 rb.Push(RESULT_SUCCESS);
602 const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; 560}
603 const auto applet_resource_user_id{rp.Pop<u64>()};
604 561
605 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", 562void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
606 controller_id, applet_resource_user_id); 563 IPC::RequestParser rp{ctx};
564 const auto controller_id{rp.Pop<u32>()};
565 const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
566 const auto applet_resource_user_id{rp.Pop<u64>()};
607 567
608 IPC::ResponseBuilder rb{ctx, 2}; 568 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
609 rb.Push(RESULT_SUCCESS); 569 applet_resource_user_id);
610 570
611 applet_resource->GetController<Controller_NPad>(HidController::NPad) 571 IPC::ResponseBuilder rb{ctx, 2};
612 .VibrateController({controller_id}, {vibration_values}); 572 rb.Push(RESULT_SUCCESS);
613 }
614 573
615 void SendVibrationValues(Kernel::HLERequestContext& ctx) { 574 applet_resource->GetController<Controller_NPad>(HidController::NPad)
616 IPC::RequestParser rp{ctx}; 575 .VibrateController({controller_id}, {vibration_values});
617 const auto applet_resource_user_id{rp.Pop<u64>()}; 576}
618 577
619 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 578void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
579 IPC::RequestParser rp{ctx};
580 const auto applet_resource_user_id{rp.Pop<u64>()};
620 581
621 const auto controllers = ctx.ReadBuffer(0); 582 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
622 const auto vibrations = ctx.ReadBuffer(1);
623 583
624 std::vector<u32> controller_list(controllers.size() / sizeof(u32)); 584 const auto controllers = ctx.ReadBuffer(0);
625 std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / 585 const auto vibrations = ctx.ReadBuffer(1);
626 sizeof(Controller_NPad::Vibration));
627 586
628 std::memcpy(controller_list.data(), controllers.data(), controllers.size()); 587 std::vector<u32> controller_list(controllers.size() / sizeof(u32));
629 std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); 588 std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
630 std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), 589 sizeof(Controller_NPad::Vibration));
631 [](u32 controller_id) { return controller_id - 3; });
632 590
633 applet_resource->GetController<Controller_NPad>(HidController::NPad) 591 std::memcpy(controller_list.data(), controllers.data(), controllers.size());
634 .VibrateController(controller_list, vibration_list); 592 std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
593 std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
594 [](u32 controller_id) { return controller_id - 3; });
635 595
636 IPC::ResponseBuilder rb{ctx, 2}; 596 applet_resource->GetController<Controller_NPad>(HidController::NPad)
637 rb.Push(RESULT_SUCCESS); 597 .VibrateController(controller_list, vibration_list);
638 }
639 598
640 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 599 IPC::ResponseBuilder rb{ctx, 2};
641 IPC::RequestParser rp{ctx}; 600 rb.Push(RESULT_SUCCESS);
642 const auto controller_id{rp.Pop<u32>()}; 601}
643 const auto applet_resource_user_id{rp.Pop<u64>()};
644 602
645 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", 603void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
646 controller_id, applet_resource_user_id); 604 IPC::RequestParser rp{ctx};
605 const auto controller_id{rp.Pop<u32>()};
606 const auto applet_resource_user_id{rp.Pop<u64>()};
647 607
648 IPC::ResponseBuilder rb{ctx, 6}; 608 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
649 rb.Push(RESULT_SUCCESS); 609 applet_resource_user_id);
650 rb.PushRaw<Controller_NPad::Vibration>(
651 applet_resource->GetController<Controller_NPad>(HidController::NPad)
652 .GetLastVibration());
653 }
654 610
655 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 611 IPC::ResponseBuilder rb{ctx, 6};
656 IPC::RequestParser rp{ctx}; 612 rb.Push(RESULT_SUCCESS);
657 const auto npad_id{rp.Pop<u32>()}; 613 rb.PushRaw<Controller_NPad::Vibration>(
658 const auto applet_resource_user_id{rp.Pop<u64>()}; 614 applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
615}
659 616
660 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 617void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
661 applet_resource_user_id); 618 IPC::RequestParser rp{ctx};
619 const auto npad_id{rp.Pop<u32>()};
620 const auto applet_resource_user_id{rp.Pop<u64>()};
662 621
663 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 622 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
664 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); 623 applet_resource_user_id);
665 624
666 IPC::ResponseBuilder rb{ctx, 2}; 625 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
667 rb.Push(RESULT_SUCCESS); 626 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
668 }
669 627
670 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 628 IPC::ResponseBuilder rb{ctx, 2};
671 IPC::RequestParser rp{ctx}; 629 rb.Push(RESULT_SUCCESS);
672 const auto unknown_1{rp.Pop<u32>()}; 630}
673 const auto unknown_2{rp.Pop<u32>()};
674 const auto applet_resource_user_id{rp.Pop<u64>()};
675 631
676 LOG_WARNING(Service_HID, 632void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
677 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", 633 IPC::RequestParser rp{ctx};
678 unknown_1, unknown_2, applet_resource_user_id); 634 const auto unknown_1{rp.Pop<u32>()};
635 const auto unknown_2{rp.Pop<u32>()};
636 const auto applet_resource_user_id{rp.Pop<u64>()};
679 637
680 IPC::ResponseBuilder rb{ctx, 2}; 638 LOG_WARNING(Service_HID,
681 rb.Push(RESULT_SUCCESS); 639 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
682 } 640 unknown_1, unknown_2, applet_resource_user_id);
683 641
684 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 642 IPC::ResponseBuilder rb{ctx, 2};
685 IPC::RequestParser rp{ctx}; 643 rb.Push(RESULT_SUCCESS);
686 const auto applet_resource_user_id{rp.Pop<u64>()}; 644}
687 const auto mode{rp.Pop<u64>()};
688 645
689 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", 646void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
690 applet_resource_user_id, mode); 647 IPC::RequestParser rp{ctx};
648 const auto applet_resource_user_id{rp.Pop<u64>()};
649 const auto mode{rp.Pop<u64>()};
691 650
692 IPC::ResponseBuilder rb{ctx, 2}; 651 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}",
693 rb.Push(RESULT_SUCCESS); 652 applet_resource_user_id, mode);
694 }
695 653
696 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 654 IPC::ResponseBuilder rb{ctx, 2};
697 LOG_DEBUG(Service_HID, "called"); 655 rb.Push(RESULT_SUCCESS);
656}
698 657
699 IPC::ResponseBuilder rb{ctx, 4}; 658void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
700 rb.Push(RESULT_SUCCESS); 659 LOG_DEBUG(Service_HID, "called");
701 rb.Push<u32>(1);
702 rb.Push<u32>(0);
703 }
704 660
705 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 661 IPC::ResponseBuilder rb{ctx, 4};
706 LOG_DEBUG(Service_HID, "called"); 662 rb.Push(RESULT_SUCCESS);
663 rb.Push<u32>(1);
664 rb.Push<u32>(0);
665}
707 666
708 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 667void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
709 rb.Push(RESULT_SUCCESS); 668 LOG_DEBUG(Service_HID, "called");
710 rb.PushIpcInterface<IActiveVibrationDeviceList>();
711 }
712 669
713 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 670 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
714 IPC::RequestParser rp{ctx}; 671 rb.Push(RESULT_SUCCESS);
715 const auto applet_resource_user_id{rp.Pop<u64>()}; 672 rb.PushIpcInterface<IActiveVibrationDeviceList>();
673}
716 674
717 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", 675void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
718 applet_resource_user_id); 676 IPC::RequestParser rp{ctx};
677 const auto applet_resource_user_id{rp.Pop<u64>()};
719 678
720 IPC::ResponseBuilder rb{ctx, 2}; 679 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
721 rb.Push(RESULT_SUCCESS); 680 applet_resource_user_id);
722 }
723 681
724 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 682 IPC::ResponseBuilder rb{ctx, 2};
725 IPC::RequestParser rp{ctx}; 683 rb.Push(RESULT_SUCCESS);
726 const auto handle{rp.Pop<u32>()}; 684}
727 const auto applet_resource_user_id{rp.Pop<u64>()};
728 685
729 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 686void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
730 applet_resource_user_id); 687 IPC::RequestParser rp{ctx};
688 const auto handle{rp.Pop<u32>()};
689 const auto applet_resource_user_id{rp.Pop<u64>()};
731 690
732 IPC::ResponseBuilder rb{ctx, 2}; 691 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
733 rb.Push(RESULT_SUCCESS); 692 applet_resource_user_id);
734 }
735 693
736 void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 694 IPC::ResponseBuilder rb{ctx, 2};
737 IPC::RequestParser rp{ctx}; 695 rb.Push(RESULT_SUCCESS);
738 const auto handle{rp.Pop<u32>()}; 696}
739 697
740 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); 698void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
699 IPC::RequestParser rp{ctx};
700 const auto handle{rp.Pop<u32>()};
741 701
742 IPC::ResponseBuilder rb{ctx, 2}; 702 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle);
743 rb.Push(RESULT_SUCCESS);
744 }
745 703
746 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { 704 IPC::ResponseBuilder rb{ctx, 2};
747 IPC::RequestParser rp{ctx}; 705 rb.Push(RESULT_SUCCESS);
748 const auto applet_resource_user_id{rp.Pop<u64>()}; 706}
749 const auto unknown{rp.Pop<u32>()};
750 707
751 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", 708void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
752 applet_resource_user_id, unknown); 709 IPC::RequestParser rp{ctx};
710 const auto applet_resource_user_id{rp.Pop<u64>()};
711 const auto unknown{rp.Pop<u32>()};
753 712
754 IPC::ResponseBuilder rb{ctx, 2}; 713 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}",
755 rb.Push(RESULT_SUCCESS); 714 applet_resource_user_id, unknown);
756 }
757 715
758 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { 716 IPC::ResponseBuilder rb{ctx, 2};
759 IPC::RequestParser rp{ctx}; 717 rb.Push(RESULT_SUCCESS);
760 const auto unknown{rp.Pop<u32>()}; 718}
761 719
762 LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); 720void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
721 IPC::RequestParser rp{ctx};
722 const auto unknown{rp.Pop<u32>()};
763 723
764 IPC::ResponseBuilder rb{ctx, 2}; 724 LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown);
765 rb.Push(RESULT_SUCCESS); 725
766 } 726 IPC::ResponseBuilder rb{ctx, 2};
767}; 727 rb.Push(RESULT_SUCCESS);
728}
768 729
769class HidDbg final : public ServiceFramework<HidDbg> { 730class HidDbg final : public ServiceFramework<HidDbg> {
770public: 731public:
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 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "controllers/controller_base.h"
8#include "core/hle/service/service.h"
9
10namespace CoreTiming {
11struct EventType;
12}
13
14namespace Kernel {
15class SharedMemory;
16}
17
7namespace SM { 18namespace SM {
8class ServiceManager; 19class ServiceManager;
9} 20}
10 21
11namespace Service::HID { 22namespace Service::HID {
12 23
24enum class HidController : std::size_t {
25 DebugPad,
26 Touchscreen,
27 Mouse,
28 Keyboard,
29 XPad,
30 Unknown1,
31 Unknown2,
32 Unknown3,
33 SixAxisSensor,
34 NPad,
35 Gesture,
36
37 MaxControllers,
38};
39
40class IAppletResource final : public ServiceFramework<IAppletResource> {
41public:
42 IAppletResource();
43 ~IAppletResource() override;
44
45 void ActivateController(HidController controller);
46 void DeactivateController(HidController controller);
47
48 template <typename T>
49 T& GetController(HidController controller) {
50 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
51 }
52
53 template <typename T>
54 const T& GetController(HidController controller) const {
55 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
56 }
57
58private:
59 template <typename T>
60 void MakeController(HidController controller) {
61 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
62 }
63
64 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
65 void UpdateControllers(u64 userdata, int cycles_late);
66
67 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
68
69 CoreTiming::EventType* pad_update_event;
70
71 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
72 controllers{};
73};
74
75class Hid final : public ServiceFramework<Hid> {
76public:
77 Hid();
78 ~Hid() override;
79
80 std::shared_ptr<IAppletResource> GetAppletResource();
81
82private:
83 void CreateAppletResource(Kernel::HLERequestContext& ctx);
84 void ActivateXpad(Kernel::HLERequestContext& ctx);
85 void ActivateDebugPad(Kernel::HLERequestContext& ctx);
86 void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
87 void ActivateMouse(Kernel::HLERequestContext& ctx);
88 void ActivateKeyboard(Kernel::HLERequestContext& ctx);
89 void ActivateGesture(Kernel::HLERequestContext& ctx);
90 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
91 void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
92 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
93 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
94 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
95 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
96 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
97 void ActivateNpad(Kernel::HLERequestContext& ctx);
98 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
99 void DisconnectNpad(Kernel::HLERequestContext& ctx);
100 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
101 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
102 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
103 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
104 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
105 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
106 void SendVibrationValue(Kernel::HLERequestContext& ctx);
107 void SendVibrationValues(Kernel::HLERequestContext& ctx);
108 void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
109 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx);
110 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx);
111 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
112 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
113 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
114 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
115 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
116 void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
117 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
118 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
119
120 std::shared_ptr<IAppletResource> applet_resource;
121};
122
13/// Reload input devices. Used when input configuration changed 123/// Reload input devices. Used when input configuration changed
14void ReloadInputDevices(); 124void ReloadInputDevices();
15 125
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:
259 return ResultStatus::ErrorNotImplemented; 259 return ResultStatus::ErrorNotImplemented;
260 } 260 }
261 261
262 /**
263 * Get the RomFS of the manual of the application
264 * @param file The raw manual RomFS of the game
265 * @return ResultStatus result of function
266 */
267 virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) {
268 return ResultStatus::ErrorNotImplemented;
269 }
270
262protected: 271protected:
263 FileSys::VirtualFile file; 272 FileSys::VirtualFile file;
264 bool is_loaded = false; 273 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) {
158 nacp = *nacp_file; 158 nacp = *nacp_file;
159 return ResultStatus::Success; 159 return ResultStatus::Success;
160} 160}
161
162ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
163 const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual);
164 if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
165 return ResultStatus::ErrorNoRomFS;
166 file = nca->GetRomFS();
167 return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
168}
161} // namespace Loader 169} // 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:
44 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 44 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
45 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
46 ResultStatus ReadControlData(FileSys::NACP& nacp) override; 46 ResultStatus ReadControlData(FileSys::NACP& nacp) override;
47 ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
47 48
48private: 49private:
49 std::unique_ptr<FileSys::NSP> nsp; 50 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) {
128 return ResultStatus::Success; 128 return ResultStatus::Success;
129} 129}
130 130
131ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
132 const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
133 FileSys::ContentRecordType::Manual);
134 if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
135 return ResultStatus::ErrorXCIMissingPartition;
136 file = nca->GetRomFS();
137 return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
138}
139
131} // namespace Loader 140} // 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:
44 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 44 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
45 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
46 ResultStatus ReadControlData(FileSys::NACP& control) override; 46 ResultStatus ReadControlData(FileSys::NACP& control) override;
47 ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
47 48
48private: 49private:
49 std::unique_ptr<FileSys::XCI> xci; 50 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
11 applets/profile_select.h 11 applets/profile_select.h
12 applets/software_keyboard.cpp 12 applets/software_keyboard.cpp
13 applets/software_keyboard.h 13 applets/software_keyboard.h
14 applets/web_browser.cpp
15 applets/web_browser.h
14 bootmanager.cpp 16 bootmanager.cpp
15 bootmanager.h 17 bootmanager.h
16 compatibility_list.cpp 18 compatibility_list.cpp
@@ -157,6 +159,11 @@ if (USE_DISCORD_PRESENCE)
157 target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) 159 target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
158endif() 160endif()
159 161
162if (YUZU_USE_QT_WEB_ENGINE)
163 target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets)
164 target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
165endif ()
166
160if(UNIX AND NOT APPLE) 167if(UNIX AND NOT APPLE)
161 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 168 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
162endif() 169endif()
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 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mutex>
6
7#include <QKeyEvent>
8
9#include "core/hle/lock.h"
10#include "yuzu/applets/web_browser.h"
11#include "yuzu/main.h"
12
13#ifdef YUZU_USE_QT_WEB_ENGINE
14
15constexpr char NX_SHIM_INJECT_SCRIPT[] = R"(
16 window.nx = {};
17 window.nx.playReport = {};
18 window.nx.playReport.setCounterSetIdentifier = function () {
19 console.log("nx.playReport.setCounterSetIdentifier called - unimplemented");
20 };
21
22 window.nx.playReport.incrementCounter = function () {
23 console.log("nx.playReport.incrementCounter called - unimplemented");
24 };
25
26 window.nx.footer = {};
27 window.nx.footer.unsetAssign = function () {
28 console.log("nx.footer.unsetAssign called - unimplemented");
29 };
30
31 var yuzu_key_callbacks = [];
32 window.nx.footer.setAssign = function(key, discard1, func, discard2) {
33 switch (key) {
34 case 'A':
35 yuzu_key_callbacks[0] = func;
36 break;
37 case 'B':
38 yuzu_key_callbacks[1] = func;
39 break;
40 case 'X':
41 yuzu_key_callbacks[2] = func;
42 break;
43 case 'Y':
44 yuzu_key_callbacks[3] = func;
45 break;
46 case 'L':
47 yuzu_key_callbacks[6] = func;
48 break;
49 case 'R':
50 yuzu_key_callbacks[7] = func;
51 break;
52 }
53 };
54
55 var applet_done = false;
56 window.nx.endApplet = function() {
57 applet_done = true;
58 };
59)";
60
61QString GetNXShimInjectionScript() {
62 return QString::fromStdString(NX_SHIM_INJECT_SCRIPT);
63}
64
65NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {}
66
67void NXInputWebEngineView::keyPressEvent(QKeyEvent* event) {
68 parent()->event(event);
69}
70
71void NXInputWebEngineView::keyReleaseEvent(QKeyEvent* event) {
72 parent()->event(event);
73}
74
75#endif
76
77QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
78 connect(this, &QtWebBrowser::MainWindowOpenPage, &main_window, &GMainWindow::WebBrowserOpenPage,
79 Qt::QueuedConnection);
80 connect(&main_window, &GMainWindow::WebBrowserUnpackRomFS, this,
81 &QtWebBrowser::MainWindowUnpackRomFS, Qt::QueuedConnection);
82 connect(&main_window, &GMainWindow::WebBrowserFinishedBrowsing, this,
83 &QtWebBrowser::MainWindowFinishedBrowsing, Qt::QueuedConnection);
84}
85
86QtWebBrowser::~QtWebBrowser() = default;
87
88void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
89 std::function<void()> finished_callback) const {
90 this->unpack_romfs_callback = unpack_romfs_callback;
91 this->finished_callback = finished_callback;
92
93 const auto index = url.find('?');
94 if (index == std::string::npos) {
95 emit MainWindowOpenPage(url, "");
96 } else {
97 const auto front = url.substr(0, index);
98 const auto back = url.substr(index);
99 emit MainWindowOpenPage(front, back);
100 }
101}
102
103void QtWebBrowser::MainWindowUnpackRomFS() {
104 // Acquire the HLE mutex
105 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
106 unpack_romfs_callback();
107}
108
109void QtWebBrowser::MainWindowFinishedBrowsing() {
110 // Acquire the HLE mutex
111 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
112 finished_callback();
113}
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 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <QObject>
9
10#ifdef YUZU_USE_QT_WEB_ENGINE
11#include <QWebEngineView>
12#endif
13
14#include "core/frontend/applets/web_browser.h"
15
16class GMainWindow;
17
18#ifdef YUZU_USE_QT_WEB_ENGINE
19
20QString GetNXShimInjectionScript();
21
22class NXInputWebEngineView : public QWebEngineView {
23public:
24 explicit NXInputWebEngineView(QWidget* parent = nullptr);
25
26protected:
27 void keyPressEvent(QKeyEvent* event) override;
28 void keyReleaseEvent(QKeyEvent* event) override;
29};
30
31#endif
32
33class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet {
34 Q_OBJECT
35
36public:
37 explicit QtWebBrowser(GMainWindow& main_window);
38 ~QtWebBrowser() override;
39
40 void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
41 std::function<void()> finished_callback) const override;
42
43signals:
44 void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;
45
46public slots:
47 void MainWindowUnpackRomFS();
48 void MainWindowFinishedBrowsing();
49
50private:
51 mutable std::function<void()> unpack_romfs_callback;
52 mutable std::function<void()> finished_callback;
53};
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 @@
10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. 10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
11#include "applets/profile_select.h" 11#include "applets/profile_select.h"
12#include "applets/software_keyboard.h" 12#include "applets/software_keyboard.h"
13#include "applets/web_browser.h"
13#include "configuration/configure_per_general.h" 14#include "configuration/configure_per_general.h"
14#include "core/file_sys/vfs.h" 15#include "core/file_sys/vfs.h"
15#include "core/file_sys/vfs_real.h" 16#include "core/file_sys/vfs_real.h"
16#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
17#include "core/hle/service/am/applets/applets.h" 18#include "core/hle/service/am/applets/applets.h"
19#include "core/hle/service/hid/controllers/npad.h"
20#include "core/hle/service/hid/hid.h"
18 21
19// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows 22// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
20// defines. 23// defines.
@@ -96,6 +99,14 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
96#include "yuzu/discord_impl.h" 99#include "yuzu/discord_impl.h"
97#endif 100#endif
98 101
102#ifdef YUZU_USE_QT_WEB_ENGINE
103#include <QWebEngineProfile>
104#include <QWebEngineScript>
105#include <QWebEngineScriptCollection>
106#include <QWebEngineSettings>
107#include <QWebEngineView>
108#endif
109
99#ifdef QT_STATICPLUGIN 110#ifdef QT_STATICPLUGIN
100Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); 111Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
101#endif 112#endif
@@ -252,6 +263,144 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message
252 emit SoftwareKeyboardFinishedCheckDialog(); 263 emit SoftwareKeyboardFinishedCheckDialog();
253} 264}
254 265
266#ifdef YUZU_USE_QT_WEB_ENGINE
267
268void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
269 NXInputWebEngineView web_browser_view(this);
270
271 // Scope to contain the QProgressDialog for initalization
272 {
273 QProgressDialog progress(this);
274 progress.setMinimumDuration(200);
275 progress.setLabelText(tr("Loading Web Applet..."));
276 progress.setRange(0, 4);
277 progress.setValue(0);
278 progress.show();
279
280 auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); });
281
282 while (!future.isFinished())
283 QApplication::processEvents();
284
285 progress.setValue(1);
286
287 // Load the special shim script to handle input and exit.
288 QWebEngineScript nx_shim;
289 nx_shim.setSourceCode(GetNXShimInjectionScript());
290 nx_shim.setWorldId(QWebEngineScript::MainWorld);
291 nx_shim.setName("nx_inject.js");
292 nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation);
293 nx_shim.setRunsOnSubFrames(true);
294 web_browser_view.page()->profile()->scripts()->insert(nx_shim);
295
296 web_browser_view.load(
297 QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() +
298 QString::fromStdString(std::string(additional_args))));
299
300 progress.setValue(2);
301
302 render_window->hide();
303 web_browser_view.setFocus();
304
305 const auto& layout = render_window->GetFramebufferLayout();
306 web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight());
307 web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height());
308 web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) /
309 Layout::ScreenUndocked::Width);
310 web_browser_view.settings()->setAttribute(
311 QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
312
313 web_browser_view.show();
314
315 progress.setValue(3);
316
317 QApplication::processEvents();
318
319 progress.setValue(4);
320 }
321
322 bool finished = false;
323 QAction* exit_action = new QAction(tr("Exit Web Applet"), this);
324 connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; });
325 ui.menubar->addAction(exit_action);
326
327 auto& npad =
328 Core::System::GetInstance()
329 .ServiceManager()
330 .GetService<Service::HID::Hid>("hid")
331 ->GetAppletResource()
332 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
333
334 const auto fire_js_keypress = [&web_browser_view](u32 key_code) {
335 web_browser_view.page()->runJavaScript(
336 QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));")
337 .arg(QString::fromStdString(std::to_string(key_code))));
338 };
339
340 bool running_exit_check = false;
341 while (!finished) {
342 QApplication::processEvents();
343
344 if (!running_exit_check) {
345 web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"),
346 [&](const QVariant& res) {
347 running_exit_check = false;
348 if (res.toBool())
349 finished = true;
350 });
351 running_exit_check = true;
352 }
353
354 const auto input = npad.GetAndResetPressState();
355 for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
356 if ((input & (1 << i)) != 0) {
357 LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);
358 web_browser_view.page()->runJavaScript(
359 QStringLiteral("yuzu_key_callbacks[%1]();").arg(i));
360 }
361 }
362
363 if (input & 0x00888000) // RStick Down | LStick Down | DPad Down
364 fire_js_keypress(40); // Down Arrow Key
365 else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
366 fire_js_keypress(39); // Right Arrow Key
367 else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
368 fire_js_keypress(38); // Up Arrow Key
369 else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
370 fire_js_keypress(37); // Left Arrow Key
371 else if (input & 0x00000001) // A Button
372 fire_js_keypress(13); // Enter Key
373 }
374
375 web_browser_view.hide();
376 render_window->show();
377 render_window->setFocus();
378 ui.menubar->removeAction(exit_action);
379
380 // Needed to update render window focus/show and remove menubar action
381 QApplication::processEvents();
382 emit WebBrowserFinishedBrowsing();
383}
384
385#else
386
387void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
388 QMessageBox::warning(
389 this, tr("Web Applet"),
390 tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
391 "properly display the game manual or web page requested."),
392 QMessageBox::Ok, QMessageBox::Ok);
393
394 LOG_INFO(Frontend,
395 "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
396 "'{}' with arguments '{}'!",
397 filename, additional_args);
398
399 emit WebBrowserFinishedBrowsing();
400}
401
402#endif
403
255void GMainWindow::InitializeWidgets() { 404void GMainWindow::InitializeWidgets() {
256#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING 405#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
257 ui.action_Report_Compatibility->setVisible(true); 406 ui.action_Report_Compatibility->setVisible(true);
@@ -612,6 +761,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
612 761
613 system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this)); 762 system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this));
614 system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); 763 system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
764 system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this));
615 765
616 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; 766 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
617 767
@@ -1325,6 +1475,7 @@ void GMainWindow::OnStartGame() {
1325 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); 1475 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
1326 qRegisterMetaType<std::string>("std::string"); 1476 qRegisterMetaType<std::string>("std::string");
1327 qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); 1477 qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
1478 qRegisterMetaType<std::string_view>("std::string_view");
1328 1479
1329 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); 1480 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
1330 1481
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 @@
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "core/core.h" 15#include "core/core.h"
16#include "core/hle/service/acc/profile_manager.h"
16#include "ui_main.h" 17#include "ui_main.h"
17#include "yuzu/compatibility_list.h" 18#include "yuzu/compatibility_list.h"
18#include "yuzu/hotkeys.h" 19#include "yuzu/hotkeys.h"
@@ -26,6 +27,7 @@ class GraphicsSurfaceWidget;
26class GRenderWindow; 27class GRenderWindow;
27class MicroProfileDialog; 28class MicroProfileDialog;
28class ProfilerWidget; 29class ProfilerWidget;
30class QLabel;
29class WaitTreeWidget; 31class WaitTreeWidget;
30enum class GameListOpenTarget; 32enum class GameListOpenTarget;
31 33
@@ -103,11 +105,16 @@ signals:
103 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); 105 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
104 void SoftwareKeyboardFinishedCheckDialog(); 106 void SoftwareKeyboardFinishedCheckDialog();
105 107
108 void WebBrowserUnpackRomFS();
109 void WebBrowserFinishedBrowsing();
110
106public slots: 111public slots:
107 void ProfileSelectorSelectProfile(); 112 void ProfileSelectorSelectProfile();
108 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); 113 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
109 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); 114 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
110 115
116 void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
117
111private: 118private:
112 void InitializeWidgets(); 119 void InitializeWidgets();
113 void InitializeDebugWidgets(); 120 void InitializeDebugWidgets();