mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #1939 from DarkLordZach/web-applet
applets: Implement HLE web browser applet (LibAppletOff)
This commit is contained in:
		
						commit
						83e8ad2331
					
				| @ -1,12 +1,12 @@ | |||||||
| #!/bin/bash -ex | #!/bin/bash -ex | ||||||
| 
 | 
 | ||||||
| apt-get update | apt-get update | ||||||
| apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget cmake ninja-build ccache | apt-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 | ||||||
| 
 | 
 | ||||||
| cd /yuzu | cd /yuzu | ||||||
| 
 | 
 | ||||||
| mkdir build && cd build | mkdir build && cd build | ||||||
| cmake .. -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 | cmake .. -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 | ||||||
| ninja | ninja | ||||||
| 
 | 
 | ||||||
| ccache -s | ccache -s | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH" | |||||||
| 
 | 
 | ||||||
| mkdir build && cd build | mkdir build && cd build | ||||||
| cmake --version | cmake --version | ||||||
| cmake .. -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 | cmake .. -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 | ||||||
| make -j4 | make -j4 | ||||||
| 
 | 
 | ||||||
| ccache -s | ccache -s | ||||||
|  | |||||||
| @ -19,6 +19,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) | |||||||
| 
 | 
 | ||||||
| option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON) | option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON) | ||||||
| 
 | 
 | ||||||
|  | option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) | ||||||
|  | 
 | ||||||
| option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) | option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) | ||||||
| 
 | 
 | ||||||
| option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) | option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) | ||||||
| @ -302,7 +304,7 @@ endif() | |||||||
| if (ENABLE_QT) | if (ENABLE_QT) | ||||||
|     if (YUZU_USE_BUNDLED_QT) |     if (YUZU_USE_BUNDLED_QT) | ||||||
|         if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) |         if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) | ||||||
|             set(QT_VER qt-5.10.0-msvc2015_64) |             set(QT_VER qt-5.12.0-msvc2017_64) | ||||||
|         else() |         else() | ||||||
|             message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.") |             message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.") | ||||||
|         endif() |         endif() | ||||||
| @ -319,6 +321,10 @@ if (ENABLE_QT) | |||||||
|     endif() |     endif() | ||||||
| 
 | 
 | ||||||
|     find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) |     find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) | ||||||
|  | 
 | ||||||
|  |     if (YUZU_USE_QT_WEB_ENGINE) | ||||||
|  |         find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets ${QT_PREFIX_HINT}) | ||||||
|  |     endif () | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| # Platform-specific library requirements | # Platform-specific library requirements | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ function(copy_yuzu_Qt5_deps target_dir) | |||||||
|     set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") |     set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") | ||||||
|     set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") |     set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") | ||||||
|     set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") |     set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") | ||||||
|  |     set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") | ||||||
|     set(PLATFORMS ${DLL_DEST}platforms/) |     set(PLATFORMS ${DLL_DEST}platforms/) | ||||||
|     set(STYLES ${DLL_DEST}styles/) |     set(STYLES ${DLL_DEST}styles/) | ||||||
|     set(IMAGEFORMATS ${DLL_DEST}imageformats/) |     set(IMAGEFORMATS ${DLL_DEST}imageformats/) | ||||||
| @ -17,6 +18,31 @@ function(copy_yuzu_Qt5_deps target_dir) | |||||||
|         Qt5OpenGL$<$<CONFIG:Debug>:d>.* |         Qt5OpenGL$<$<CONFIG:Debug>:d>.* | ||||||
|         Qt5Widgets$<$<CONFIG:Debug>:d>.* |         Qt5Widgets$<$<CONFIG:Debug>:d>.* | ||||||
|     ) |     ) | ||||||
|  | 
 | ||||||
|  |     if (YUZU_USE_QT_WEB_ENGINE) | ||||||
|  |         windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}  | ||||||
|  |             Qt5Network$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5Positioning$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5PrintSupport$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5Qml$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5Quick$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5QuickWidgets$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5WebChannel$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5WebEngine$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5WebEngineCore$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.* | ||||||
|  |             QtWebEngineProcess$<$<CONFIG:Debug>:d>.* | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST} | ||||||
|  |             qtwebengine_resources.pak | ||||||
|  |             qtwebengine_devtools_resources.pak | ||||||
|  |             qtwebengine_resources_100p.pak | ||||||
|  |             qtwebengine_resources_200p.pak | ||||||
|  |             icudtl.dat | ||||||
|  |         ) | ||||||
|  |     endif () | ||||||
|  | 
 | ||||||
|     windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) |     windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) | ||||||
|     windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) |     windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) | ||||||
|     windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) |     windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ before_build: | |||||||
|         $COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING} |         $COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING} | ||||||
|         if ($env:BUILD_TYPE -eq 'msvc') { |         if ($env:BUILD_TYPE -eq 'msvc') { | ||||||
|           # redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning |           # redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning | ||||||
|           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' |           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' | ||||||
|         } else { |         } else { | ||||||
|           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" |           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" | ||||||
|         } |         } | ||||||
| @ -94,6 +94,7 @@ after_build: | |||||||
|           Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse |           Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse | ||||||
|           rm "$RELEASE_DIST\*.exe" |           rm "$RELEASE_DIST\*.exe" | ||||||
|           Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST |           Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST | ||||||
|  |           Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST | ||||||
|           Copy-Item .\license.txt -Destination $RELEASE_DIST |           Copy-Item .\license.txt -Destination $RELEASE_DIST | ||||||
|           Copy-Item .\README.md -Destination $RELEASE_DIST |           Copy-Item .\README.md -Destination $RELEASE_DIST | ||||||
|           7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\* |           7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\* | ||||||
|  | |||||||
| @ -88,6 +88,8 @@ add_library(core STATIC | |||||||
|     frontend/applets/profile_select.h |     frontend/applets/profile_select.h | ||||||
|     frontend/applets/software_keyboard.cpp |     frontend/applets/software_keyboard.cpp | ||||||
|     frontend/applets/software_keyboard.h |     frontend/applets/software_keyboard.h | ||||||
|  |     frontend/applets/web_browser.cpp | ||||||
|  |     frontend/applets/web_browser.h | ||||||
|     frontend/emu_window.cpp |     frontend/emu_window.cpp | ||||||
|     frontend/emu_window.h |     frontend/emu_window.h | ||||||
|     frontend/framebuffer_layout.cpp |     frontend/framebuffer_layout.cpp | ||||||
| @ -173,6 +175,8 @@ add_library(core STATIC | |||||||
|     hle/service/am/applets/software_keyboard.h |     hle/service/am/applets/software_keyboard.h | ||||||
|     hle/service/am/applets/stub_applet.cpp |     hle/service/am/applets/stub_applet.cpp | ||||||
|     hle/service/am/applets/stub_applet.h |     hle/service/am/applets/stub_applet.h | ||||||
|  |     hle/service/am/applets/web_browser.cpp | ||||||
|  |     hle/service/am/applets/web_browser.h | ||||||
|     hle/service/am/idle.cpp |     hle/service/am/idle.cpp | ||||||
|     hle/service/am/idle.h |     hle/service/am/idle.h | ||||||
|     hle/service/am/omm.cpp |     hle/service/am/omm.cpp | ||||||
|  | |||||||
| @ -31,7 +31,9 @@ | |||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
| #include "core/perf_stats.h" | #include "core/perf_stats.h" | ||||||
| #include "core/telemetry_session.h" | #include "core/telemetry_session.h" | ||||||
|  | #include "frontend/applets/profile_select.h" | ||||||
| #include "frontend/applets/software_keyboard.h" | #include "frontend/applets/software_keyboard.h" | ||||||
|  | #include "frontend/applets/web_browser.h" | ||||||
| #include "video_core/debug_utils/debug_utils.h" | #include "video_core/debug_utils/debug_utils.h" | ||||||
| #include "video_core/gpu.h" | #include "video_core/gpu.h" | ||||||
| #include "video_core/renderer_base.h" | #include "video_core/renderer_base.h" | ||||||
| @ -103,6 +105,8 @@ struct System::Impl { | |||||||
|             profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); |             profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); | ||||||
|         if (software_keyboard == nullptr) |         if (software_keyboard == nullptr) | ||||||
|             software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); |             software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); | ||||||
|  |         if (web_browser == nullptr) | ||||||
|  |             web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); | ||||||
| 
 | 
 | ||||||
|         auto main_process = Kernel::Process::Create(kernel, "main"); |         auto main_process = Kernel::Process::Create(kernel, "main"); | ||||||
|         kernel.MakeCurrentProcess(main_process.get()); |         kernel.MakeCurrentProcess(main_process.get()); | ||||||
| @ -199,6 +203,11 @@ struct System::Impl { | |||||||
|         // Close app loader
 |         // Close app loader
 | ||||||
|         app_loader.reset(); |         app_loader.reset(); | ||||||
| 
 | 
 | ||||||
|  |         // Clear all applets
 | ||||||
|  |         profile_selector.reset(); | ||||||
|  |         software_keyboard.reset(); | ||||||
|  |         web_browser.reset(); | ||||||
|  | 
 | ||||||
|         LOG_DEBUG(Core, "Shutdown OK"); |         LOG_DEBUG(Core, "Shutdown OK"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -233,6 +242,7 @@ struct System::Impl { | |||||||
|     /// Frontend applets
 |     /// Frontend applets
 | ||||||
|     std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; |     std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; | ||||||
|     std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; |     std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; | ||||||
|  |     std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; | ||||||
| 
 | 
 | ||||||
|     /// Service manager
 |     /// Service manager
 | ||||||
|     std::shared_ptr<Service::SM::ServiceManager> service_manager; |     std::shared_ptr<Service::SM::ServiceManager> service_manager; | ||||||
| @ -443,6 +453,14 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons | |||||||
|     return *impl->software_keyboard; |     return *impl->software_keyboard; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void System::SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet) { | ||||||
|  |     impl->web_browser = std::move(applet); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const Core::Frontend::WebBrowserApplet& System::GetWebBrowser() const { | ||||||
|  |     return *impl->web_browser; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||||||
|     return impl->Init(*this, emu_window); |     return impl->Init(*this, emu_window); | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,11 +11,12 @@ | |||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/file_sys/vfs_types.h" | #include "core/file_sys/vfs_types.h" | ||||||
| #include "core/hle/kernel/object.h" | #include "core/hle/kernel/object.h" | ||||||
| #include "frontend/applets/profile_select.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Core::Frontend { | namespace Core::Frontend { | ||||||
| class EmuWindow; | class EmuWindow; | ||||||
|  | class ProfileSelectApplet; | ||||||
| class SoftwareKeyboardApplet; | class SoftwareKeyboardApplet; | ||||||
|  | class WebBrowserApplet; | ||||||
| } // namespace Core::Frontend
 | } // namespace Core::Frontend
 | ||||||
| 
 | 
 | ||||||
| namespace FileSys { | namespace FileSys { | ||||||
| @ -250,6 +251,10 @@ public: | |||||||
| 
 | 
 | ||||||
|     const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; |     const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; | ||||||
| 
 | 
 | ||||||
|  |     void SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet); | ||||||
|  | 
 | ||||||
|  |     const Core::Frontend::WebBrowserApplet& GetWebBrowser() const; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     System(); |     System(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -119,6 +119,9 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { | |||||||
| 
 | 
 | ||||||
|     VirtualDir out = std::move(root); |     VirtualDir out = std::move(root); | ||||||
| 
 | 
 | ||||||
|  |     if (type == RomFSExtractionType::SingleDiscard) | ||||||
|  |         return out->GetSubdirectories().front(); | ||||||
|  | 
 | ||||||
|     while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { |     while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { | ||||||
|         if (out->GetSubdirectories().front()->GetName() == "data" && |         if (out->GetSubdirectories().front()->GetName() == "data" && | ||||||
|             type == RomFSExtractionType::Truncated) |             type == RomFSExtractionType::Truncated) | ||||||
|  | |||||||
| @ -33,8 +33,9 @@ struct IVFCHeader { | |||||||
| static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); | static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); | ||||||
| 
 | 
 | ||||||
| enum class RomFSExtractionType { | enum class RomFSExtractionType { | ||||||
|     Full,      // Includes data directory
 |     Full,          // Includes data directory
 | ||||||
|     Truncated, // Traverses into data directory
 |     Truncated,     // Traverses into data directory
 | ||||||
|  |     SingleDiscard, // Traverses into the first subdirectory of root
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Converts a RomFS binary blob to VFS Filesystem
 | // Converts a RomFS binary blob to VFS Filesystem
 | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								src/core/frontend/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/core/frontend/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "core/frontend/applets/web_browser.h" | ||||||
|  | 
 | ||||||
|  | namespace Core::Frontend { | ||||||
|  | 
 | ||||||
|  | WebBrowserApplet::~WebBrowserApplet() = default; | ||||||
|  | 
 | ||||||
|  | DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; | ||||||
|  | 
 | ||||||
|  | void DefaultWebBrowserApplet::OpenPage(std::string_view filename, | ||||||
|  |                                        std::function<void()> unpack_romfs_callback, | ||||||
|  |                                        std::function<void()> finished_callback) const { | ||||||
|  |     LOG_INFO(Service_AM, | ||||||
|  |              "(STUBBED) called - No suitable web browser implementation found to open website page " | ||||||
|  |              "at '{}'!", | ||||||
|  |              filename); | ||||||
|  |     finished_callback(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Core::Frontend
 | ||||||
							
								
								
									
										28
									
								
								src/core/frontend/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/core/frontend/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <functional> | ||||||
|  | #include <string_view> | ||||||
|  | 
 | ||||||
|  | namespace Core::Frontend { | ||||||
|  | 
 | ||||||
|  | class WebBrowserApplet { | ||||||
|  | public: | ||||||
|  |     virtual ~WebBrowserApplet(); | ||||||
|  | 
 | ||||||
|  |     virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, | ||||||
|  |                           std::function<void()> finished_callback) const = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class DefaultWebBrowserApplet final : public WebBrowserApplet { | ||||||
|  | public: | ||||||
|  |     ~DefaultWebBrowserApplet() override; | ||||||
|  | 
 | ||||||
|  |     void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, | ||||||
|  |                   std::function<void()> finished_callback) const override; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Core::Frontend
 | ||||||
| @ -23,6 +23,7 @@ | |||||||
| #include "core/hle/service/am/applets/profile_select.h" | #include "core/hle/service/am/applets/profile_select.h" | ||||||
| #include "core/hle/service/am/applets/software_keyboard.h" | #include "core/hle/service/am/applets/software_keyboard.h" | ||||||
| #include "core/hle/service/am/applets/stub_applet.h" | #include "core/hle/service/am/applets/stub_applet.h" | ||||||
|  | #include "core/hle/service/am/applets/web_browser.h" | ||||||
| #include "core/hle/service/am/idle.h" | #include "core/hle/service/am/idle.h" | ||||||
| #include "core/hle/service/am/omm.h" | #include "core/hle/service/am/omm.h" | ||||||
| #include "core/hle/service/am/spsm.h" | #include "core/hle/service/am/spsm.h" | ||||||
| @ -44,6 +45,7 @@ constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | |||||||
| enum class AppletId : u32 { | enum class AppletId : u32 { | ||||||
|     ProfileSelect = 0x10, |     ProfileSelect = 0x10, | ||||||
|     SoftwareKeyboard = 0x11, |     SoftwareKeyboard = 0x11, | ||||||
|  |     LibAppletOff = 0x17, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | ||||||
| @ -730,10 +732,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | |||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     const u64 offset{rp.Pop<u64>()}; |     const u64 offset{rp.Pop<u64>()}; | ||||||
|     LOG_DEBUG(Service_AM, "called, offset={}", offset); |  | ||||||
| 
 |  | ||||||
|     const std::vector<u8> data{ctx.ReadBuffer()}; |     const std::vector<u8> data{ctx.ReadBuffer()}; | ||||||
| 
 | 
 | ||||||
|  |     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); | ||||||
|  | 
 | ||||||
|     if (data.size() > backing.buffer.size() - offset) { |     if (data.size() > backing.buffer.size() - offset) { | ||||||
|         LOG_ERROR(Service_AM, |         LOG_ERROR(Service_AM, | ||||||
|                   "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", |                   "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", | ||||||
| @ -753,10 +755,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | |||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     const u64 offset{rp.Pop<u64>()}; |     const u64 offset{rp.Pop<u64>()}; | ||||||
|     LOG_DEBUG(Service_AM, "called, offset={}", offset); |  | ||||||
| 
 |  | ||||||
|     const std::size_t size{ctx.GetWriteBufferSize()}; |     const std::size_t size{ctx.GetWriteBufferSize()}; | ||||||
| 
 | 
 | ||||||
|  |     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); | ||||||
|  | 
 | ||||||
|     if (size > backing.buffer.size() - offset) { |     if (size > backing.buffer.size() - offset) { | ||||||
|         LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", |         LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", | ||||||
|                   backing.buffer.size(), size, offset); |                   backing.buffer.size(), size, offset); | ||||||
| @ -791,6 +793,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { | |||||||
|         return std::make_shared<Applets::ProfileSelect>(); |         return std::make_shared<Applets::ProfileSelect>(); | ||||||
|     case AppletId::SoftwareKeyboard: |     case AppletId::SoftwareKeyboard: | ||||||
|         return std::make_shared<Applets::SoftwareKeyboard>(); |         return std::make_shared<Applets::SoftwareKeyboard>(); | ||||||
|  |     case AppletId::LibAppletOff: | ||||||
|  |         return std::make_shared<Applets::WebBrowser>(); | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", |         LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", | ||||||
|                   static_cast<u32>(id)); |                   static_cast<u32>(id)); | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/frontend/applets/software_keyboard.h" | #include "core/frontend/applets/profile_select.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/applets/profile_select.h" | #include "core/hle/service/am/applets/profile_select.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										184
									
								
								src/core/hle/service/am/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/core/hle/service/am/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,184 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/common_paths.h" | ||||||
|  | #include "common/hex_util.h" | ||||||
|  | #include "common/logging/backend.h" | ||||||
|  | #include "common/string_util.h" | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/file_sys/content_archive.h" | ||||||
|  | #include "core/file_sys/mode.h" | ||||||
|  | #include "core/file_sys/nca_metadata.h" | ||||||
|  | #include "core/file_sys/registered_cache.h" | ||||||
|  | #include "core/file_sys/romfs.h" | ||||||
|  | #include "core/file_sys/romfs_factory.h" | ||||||
|  | #include "core/file_sys/vfs_types.h" | ||||||
|  | #include "core/frontend/applets/web_browser.h" | ||||||
|  | #include "core/hle/kernel/process.h" | ||||||
|  | #include "core/hle/service/am/applets/web_browser.h" | ||||||
|  | #include "core/hle/service/filesystem/filesystem.h" | ||||||
|  | #include "core/loader/loader.h" | ||||||
|  | 
 | ||||||
|  | namespace Service::AM::Applets { | ||||||
|  | 
 | ||||||
|  | // TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
 | ||||||
|  | // parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
 | ||||||
|  | // but some may be worth an implementation.
 | ||||||
|  | constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; | ||||||
|  | 
 | ||||||
|  | struct WebBufferHeader { | ||||||
|  |     u16 count; | ||||||
|  |     INSERT_PADDING_BYTES(6); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); | ||||||
|  | 
 | ||||||
|  | struct WebArgumentHeader { | ||||||
|  |     u16 type; | ||||||
|  |     u16 size; | ||||||
|  |     u32 offset; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); | ||||||
|  | 
 | ||||||
|  | struct WebArgumentResult { | ||||||
|  |     u32 result_code; | ||||||
|  |     std::array<char, 0x1000> last_url; | ||||||
|  |     u64 last_url_size; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); | ||||||
|  | 
 | ||||||
|  | static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { | ||||||
|  |     WebBufferHeader header; | ||||||
|  |     ASSERT(sizeof(WebBufferHeader) <= data.size()); | ||||||
|  |     std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); | ||||||
|  | 
 | ||||||
|  |     u64 offset = sizeof(WebBufferHeader); | ||||||
|  |     for (u16 i = 0; i < header.count; ++i) { | ||||||
|  |         WebArgumentHeader arg; | ||||||
|  |         ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); | ||||||
|  |         std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); | ||||||
|  |         offset += sizeof(WebArgumentHeader); | ||||||
|  | 
 | ||||||
|  |         if (arg.type == type) { | ||||||
|  |             std::vector<u8> out(arg.size); | ||||||
|  |             offset += arg.offset; | ||||||
|  |             ASSERT(offset + arg.size <= data.size()); | ||||||
|  |             std::memcpy(out.data(), data.data() + offset, out.size()); | ||||||
|  |             return out; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         offset += arg.offset + arg.size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static FileSys::VirtualFile GetManualRomFS() { | ||||||
|  |     auto& loader{Core::System::GetInstance().GetAppLoader()}; | ||||||
|  | 
 | ||||||
|  |     FileSys::VirtualFile out; | ||||||
|  |     if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) | ||||||
|  |         return out; | ||||||
|  | 
 | ||||||
|  |     const auto& installed{FileSystem::GetUnionContents()}; | ||||||
|  |     const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), | ||||||
|  |                                         FileSys::ContentRecordType::Manual); | ||||||
|  | 
 | ||||||
|  |     if (res != nullptr) | ||||||
|  |         return res->GetRomFS(); | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WebBrowser::WebBrowser() = default; | ||||||
|  | 
 | ||||||
|  | WebBrowser::~WebBrowser() = default; | ||||||
|  | 
 | ||||||
|  | void WebBrowser::Initialize() { | ||||||
|  |     Applet::Initialize(); | ||||||
|  | 
 | ||||||
|  |     complete = false; | ||||||
|  |     temporary_dir.clear(); | ||||||
|  |     filename.clear(); | ||||||
|  |     status = RESULT_SUCCESS; | ||||||
|  | 
 | ||||||
|  |     const auto web_arg_storage = broker.PopNormalDataToApplet(); | ||||||
|  |     ASSERT(web_arg_storage != nullptr); | ||||||
|  |     const auto& web_arg = web_arg_storage->GetData(); | ||||||
|  | 
 | ||||||
|  |     const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); | ||||||
|  |     filename = Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |         reinterpret_cast<const char*>(url_data.data()), url_data.size()); | ||||||
|  | 
 | ||||||
|  |     temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + | ||||||
|  |                                                "web_applet_manual", | ||||||
|  |                                            FileUtil::DirectorySeparator::PlatformDefault); | ||||||
|  |     FileUtil::DeleteDirRecursively(temporary_dir); | ||||||
|  | 
 | ||||||
|  |     manual_romfs = GetManualRomFS(); | ||||||
|  |     if (manual_romfs == nullptr) { | ||||||
|  |         status = ResultCode(-1); | ||||||
|  |         LOG_ERROR(Service_AM, "Failed to find manual for current process!"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     filename = | ||||||
|  |         FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, | ||||||
|  |                                FileUtil::DirectorySeparator::PlatformDefault); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool WebBrowser::TransactionComplete() const { | ||||||
|  |     return complete; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode WebBrowser::GetStatus() const { | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WebBrowser::ExecuteInteractive() { | ||||||
|  |     UNIMPLEMENTED_MSG("Unexpected interactive data recieved!"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WebBrowser::Execute() { | ||||||
|  |     if (complete) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     if (status != RESULT_SUCCESS) { | ||||||
|  |         complete = true; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto& frontend{Core::System::GetInstance().GetWebBrowser()}; | ||||||
|  | 
 | ||||||
|  |     frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WebBrowser::UnpackRomFS() { | ||||||
|  |     if (unpacked) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     ASSERT(manual_romfs != nullptr); | ||||||
|  |     const auto dir = | ||||||
|  |         FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); | ||||||
|  |     const auto& vfs{Core::System::GetInstance().GetFilesystem()}; | ||||||
|  |     const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); | ||||||
|  |     FileSys::VfsRawCopyD(dir, temp_dir); | ||||||
|  | 
 | ||||||
|  |     unpacked = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WebBrowser::Finalize() { | ||||||
|  |     complete = true; | ||||||
|  | 
 | ||||||
|  |     WebArgumentResult out{}; | ||||||
|  |     out.result_code = 0; | ||||||
|  |     out.last_url_size = 0; | ||||||
|  | 
 | ||||||
|  |     std::vector<u8> data(sizeof(WebArgumentResult)); | ||||||
|  |     std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); | ||||||
|  | 
 | ||||||
|  |     broker.PushNormalDataFromApplet(IStorage{data}); | ||||||
|  |     broker.SignalStateChanged(); | ||||||
|  | 
 | ||||||
|  |     FileUtil::DeleteDirRecursively(temporary_dir); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Service::AM::Applets
 | ||||||
							
								
								
									
										44
									
								
								src/core/hle/service/am/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/hle/service/am/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "core/file_sys/vfs_types.h" | ||||||
|  | #include "core/hle/service/am/am.h" | ||||||
|  | #include "core/hle/service/am/applets/applets.h" | ||||||
|  | 
 | ||||||
|  | namespace Service::AM::Applets { | ||||||
|  | 
 | ||||||
|  | class WebBrowser final : public Applet { | ||||||
|  | public: | ||||||
|  |     WebBrowser(); | ||||||
|  |     ~WebBrowser() override; | ||||||
|  | 
 | ||||||
|  |     void Initialize() override; | ||||||
|  | 
 | ||||||
|  |     bool TransactionComplete() const override; | ||||||
|  |     ResultCode GetStatus() const override; | ||||||
|  |     void ExecuteInteractive() override; | ||||||
|  |     void Execute() override; | ||||||
|  | 
 | ||||||
|  |     // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary
 | ||||||
|  |     // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in
 | ||||||
|  |     // size. Attempting to access files at filename before invocation is likely to not work.
 | ||||||
|  |     void UnpackRomFS(); | ||||||
|  | 
 | ||||||
|  |     // Callback to be fired when the frontend is finished browsing. This will delete the temporary
 | ||||||
|  |     // manual RomFS extracted files, so ensure this is only called at actual finalization.
 | ||||||
|  |     void Finalize(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     bool complete = false; | ||||||
|  |     bool unpacked = false; | ||||||
|  |     ResultCode status = RESULT_SUCCESS; | ||||||
|  | 
 | ||||||
|  |     FileSys::VirtualFile manual_romfs; | ||||||
|  |     std::string temporary_dir; | ||||||
|  |     std::string filename; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Service::AM::Applets
 | ||||||
| @ -410,6 +410,8 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||||||
|         libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; |         libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||||||
|         libnx_entry.pad.l_stick = pad_state.l_stick; |         libnx_entry.pad.l_stick = pad_state.l_stick; | ||||||
|         libnx_entry.pad.r_stick = pad_state.r_stick; |         libnx_entry.pad.r_stick = pad_state.r_stick; | ||||||
|  | 
 | ||||||
|  |         press_state |= static_cast<u32>(pad_state.pad_states.raw); | ||||||
|     } |     } | ||||||
|     std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), |     std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | ||||||
|                 shared_memory_entries.size() * sizeof(NPadEntry)); |                 shared_memory_entries.size() * sizeof(NPadEntry)); | ||||||
| @ -636,6 +638,10 @@ void Controller_NPad::ClearAllControllers() { | |||||||
|                   }); |                   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u32 Controller_NPad::GetAndResetPressState() { | ||||||
|  |     return std::exchange(press_state, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { | ||||||
|     const bool support_handheld = |     const bool support_handheld = | ||||||
|         std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != |         std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != | ||||||
|  | |||||||
| @ -124,6 +124,10 @@ public: | |||||||
|     void ConnectAllDisconnectedControllers(); |     void ConnectAllDisconnectedControllers(); | ||||||
|     void ClearAllControllers(); |     void ClearAllControllers(); | ||||||
| 
 | 
 | ||||||
|  |     // Logical OR for all buttons presses on all controllers
 | ||||||
|  |     // Specifically for cheat engine and other features.
 | ||||||
|  |     u32 GetAndResetPressState(); | ||||||
|  | 
 | ||||||
|     static std::size_t NPadIdToIndex(u32 npad_id); |     static std::size_t NPadIdToIndex(u32 npad_id); | ||||||
|     static u32 IndexToNPad(std::size_t index); |     static u32 IndexToNPad(std::size_t index); | ||||||
| 
 | 
 | ||||||
| @ -292,6 +296,8 @@ private: | |||||||
|         bool is_connected; |         bool is_connected; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     u32 press_state{}; | ||||||
|  | 
 | ||||||
|     NPadType style{}; |     NPadType style{}; | ||||||
|     std::array<NPadEntry, 10> shared_memory_entries{}; |     std::array<NPadEntry, 10> shared_memory_entries{}; | ||||||
|     std::array< |     std::array< | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -4,12 +4,122 @@ | |||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "controllers/controller_base.h" | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  | 
 | ||||||
|  | namespace CoreTiming { | ||||||
|  | struct EventType; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | class SharedMemory; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace SM { | namespace SM { | ||||||
| class ServiceManager; | class ServiceManager; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace Service::HID { | namespace Service::HID { | ||||||
| 
 | 
 | ||||||
|  | enum class HidController : std::size_t { | ||||||
|  |     DebugPad, | ||||||
|  |     Touchscreen, | ||||||
|  |     Mouse, | ||||||
|  |     Keyboard, | ||||||
|  |     XPad, | ||||||
|  |     Unknown1, | ||||||
|  |     Unknown2, | ||||||
|  |     Unknown3, | ||||||
|  |     SixAxisSensor, | ||||||
|  |     NPad, | ||||||
|  |     Gesture, | ||||||
|  | 
 | ||||||
|  |     MaxControllers, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class IAppletResource final : public ServiceFramework<IAppletResource> { | ||||||
|  | public: | ||||||
|  |     IAppletResource(); | ||||||
|  |     ~IAppletResource() override; | ||||||
|  | 
 | ||||||
|  |     void ActivateController(HidController controller); | ||||||
|  |     void DeactivateController(HidController controller); | ||||||
|  | 
 | ||||||
|  |     template <typename T> | ||||||
|  |     T& GetController(HidController controller) { | ||||||
|  |         return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template <typename T> | ||||||
|  |     const T& GetController(HidController controller) const { | ||||||
|  |         return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     template <typename T> | ||||||
|  |     void MakeController(HidController controller) { | ||||||
|  |         controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | ||||||
|  |     void UpdateControllers(u64 userdata, int cycles_late); | ||||||
|  | 
 | ||||||
|  |     Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; | ||||||
|  | 
 | ||||||
|  |     CoreTiming::EventType* pad_update_event; | ||||||
|  | 
 | ||||||
|  |     std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | ||||||
|  |         controllers{}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class Hid final : public ServiceFramework<Hid> { | ||||||
|  | public: | ||||||
|  |     Hid(); | ||||||
|  |     ~Hid() override; | ||||||
|  | 
 | ||||||
|  |     std::shared_ptr<IAppletResource> GetAppletResource(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void CreateAppletResource(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateXpad(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateDebugPad(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateTouchScreen(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateMouse(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateKeyboard(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateGesture(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); | ||||||
|  |     void StartSixAxisSensor(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | ||||||
|  |     void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateNpad(Kernel::HLERequestContext& ctx); | ||||||
|  |     void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); | ||||||
|  |     void DisconnectNpad(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); | ||||||
|  |     void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); | ||||||
|  |     void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SendVibrationValue(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SendVibrationValues(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetActualVibrationValue(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); | ||||||
|  |     void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); | ||||||
|  |     void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); | ||||||
|  |     void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); | ||||||
|  |     void StopSixAxisSensor(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); | ||||||
|  |     void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     std::shared_ptr<IAppletResource> applet_resource; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /// Reload input devices. Used when input configuration changed
 | /// Reload input devices. Used when input configuration changed
 | ||||||
| void ReloadInputDevices(); | void ReloadInputDevices(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -259,6 +259,15 @@ public: | |||||||
|         return ResultStatus::ErrorNotImplemented; |         return ResultStatus::ErrorNotImplemented; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Get the RomFS of the manual of the application | ||||||
|  |      * @param file The raw manual RomFS of the game | ||||||
|  |      * @return ResultStatus result of function | ||||||
|  |      */ | ||||||
|  |     virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) { | ||||||
|  |         return ResultStatus::ErrorNotImplemented; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     FileSys::VirtualFile file; |     FileSys::VirtualFile file; | ||||||
|     bool is_loaded = false; |     bool is_loaded = false; | ||||||
|  | |||||||
| @ -158,4 +158,12 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) { | |||||||
|     nacp = *nacp_file; |     nacp = *nacp_file; | ||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) { | ||||||
|  |     const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual); | ||||||
|  |     if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr) | ||||||
|  |         return ResultStatus::ErrorNoRomFS; | ||||||
|  |     file = nca->GetRomFS(); | ||||||
|  |     return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; | ||||||
|  | } | ||||||
| } // namespace Loader
 | } // namespace Loader
 | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ public: | |||||||
|     ResultStatus ReadIcon(std::vector<u8>& buffer) override; |     ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||||||
|     ResultStatus ReadTitle(std::string& title) override; |     ResultStatus ReadTitle(std::string& title) override; | ||||||
|     ResultStatus ReadControlData(FileSys::NACP& nacp) override; |     ResultStatus ReadControlData(FileSys::NACP& nacp) override; | ||||||
|  |     ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::unique_ptr<FileSys::NSP> nsp; |     std::unique_ptr<FileSys::NSP> nsp; | ||||||
|  | |||||||
| @ -128,4 +128,13 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { | |||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) { | ||||||
|  |     const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), | ||||||
|  |                                                           FileSys::ContentRecordType::Manual); | ||||||
|  |     if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) | ||||||
|  |         return ResultStatus::ErrorXCIMissingPartition; | ||||||
|  |     file = nca->GetRomFS(); | ||||||
|  |     return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace Loader
 | } // namespace Loader
 | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ public: | |||||||
|     ResultStatus ReadIcon(std::vector<u8>& buffer) override; |     ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||||||
|     ResultStatus ReadTitle(std::string& title) override; |     ResultStatus ReadTitle(std::string& title) override; | ||||||
|     ResultStatus ReadControlData(FileSys::NACP& control) override; |     ResultStatus ReadControlData(FileSys::NACP& control) override; | ||||||
|  |     ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::unique_ptr<FileSys::XCI> xci; |     std::unique_ptr<FileSys::XCI> xci; | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ add_executable(yuzu | |||||||
|     applets/profile_select.h |     applets/profile_select.h | ||||||
|     applets/software_keyboard.cpp |     applets/software_keyboard.cpp | ||||||
|     applets/software_keyboard.h |     applets/software_keyboard.h | ||||||
|  |     applets/web_browser.cpp | ||||||
|  |     applets/web_browser.h | ||||||
|     bootmanager.cpp |     bootmanager.cpp | ||||||
|     bootmanager.h |     bootmanager.h | ||||||
|     compatibility_list.cpp |     compatibility_list.cpp | ||||||
| @ -157,6 +159,11 @@ if (USE_DISCORD_PRESENCE) | |||||||
|     target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) |     target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
|  | if (YUZU_USE_QT_WEB_ENGINE) | ||||||
|  |     target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets) | ||||||
|  |     target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) | ||||||
|  | endif () | ||||||
|  | 
 | ||||||
| if(UNIX AND NOT APPLE) | if(UNIX AND NOT APPLE) | ||||||
|     install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") |     install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||||||
| endif() | endif() | ||||||
|  | |||||||
							
								
								
									
										113
									
								
								src/yuzu/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/yuzu/applets/web_browser.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | // Copyright 2018 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <mutex> | ||||||
|  | 
 | ||||||
|  | #include <QKeyEvent> | ||||||
|  | 
 | ||||||
|  | #include "core/hle/lock.h" | ||||||
|  | #include "yuzu/applets/web_browser.h" | ||||||
|  | #include "yuzu/main.h" | ||||||
|  | 
 | ||||||
|  | #ifdef YUZU_USE_QT_WEB_ENGINE | ||||||
|  | 
 | ||||||
|  | constexpr char NX_SHIM_INJECT_SCRIPT[] = R"( | ||||||
|  |     window.nx = {}; | ||||||
|  |     window.nx.playReport = {}; | ||||||
|  |     window.nx.playReport.setCounterSetIdentifier = function () { | ||||||
|  |         console.log("nx.playReport.setCounterSetIdentifier called - unimplemented"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     window.nx.playReport.incrementCounter = function () { | ||||||
|  |         console.log("nx.playReport.incrementCounter called - unimplemented"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     window.nx.footer = {}; | ||||||
|  |     window.nx.footer.unsetAssign = function () { | ||||||
|  |         console.log("nx.footer.unsetAssign called - unimplemented"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var yuzu_key_callbacks = []; | ||||||
|  |     window.nx.footer.setAssign = function(key, discard1, func, discard2) { | ||||||
|  |         switch (key) { | ||||||
|  |         case 'A': | ||||||
|  |             yuzu_key_callbacks[0] = func; | ||||||
|  |             break; | ||||||
|  |         case 'B': | ||||||
|  |             yuzu_key_callbacks[1] = func; | ||||||
|  |             break; | ||||||
|  |         case 'X': | ||||||
|  |             yuzu_key_callbacks[2] = func; | ||||||
|  |             break; | ||||||
|  |         case 'Y': | ||||||
|  |             yuzu_key_callbacks[3] = func; | ||||||
|  |             break; | ||||||
|  |         case 'L': | ||||||
|  |             yuzu_key_callbacks[6] = func; | ||||||
|  |             break; | ||||||
|  |         case 'R': | ||||||
|  |             yuzu_key_callbacks[7] = func; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var applet_done = false; | ||||||
|  |     window.nx.endApplet = function() { | ||||||
|  |         applet_done = true; | ||||||
|  |     }; | ||||||
|  | )"; | ||||||
|  | 
 | ||||||
|  | QString GetNXShimInjectionScript() { | ||||||
|  |     return QString::fromStdString(NX_SHIM_INJECT_SCRIPT); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {} | ||||||
|  | 
 | ||||||
|  | void NXInputWebEngineView::keyPressEvent(QKeyEvent* event) { | ||||||
|  |     parent()->event(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NXInputWebEngineView::keyReleaseEvent(QKeyEvent* event) { | ||||||
|  |     parent()->event(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { | ||||||
|  |     connect(this, &QtWebBrowser::MainWindowOpenPage, &main_window, &GMainWindow::WebBrowserOpenPage, | ||||||
|  |             Qt::QueuedConnection); | ||||||
|  |     connect(&main_window, &GMainWindow::WebBrowserUnpackRomFS, this, | ||||||
|  |             &QtWebBrowser::MainWindowUnpackRomFS, Qt::QueuedConnection); | ||||||
|  |     connect(&main_window, &GMainWindow::WebBrowserFinishedBrowsing, this, | ||||||
|  |             &QtWebBrowser::MainWindowFinishedBrowsing, Qt::QueuedConnection); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QtWebBrowser::~QtWebBrowser() = default; | ||||||
|  | 
 | ||||||
|  | void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, | ||||||
|  |                             std::function<void()> finished_callback) const { | ||||||
|  |     this->unpack_romfs_callback = unpack_romfs_callback; | ||||||
|  |     this->finished_callback = finished_callback; | ||||||
|  | 
 | ||||||
|  |     const auto index = url.find('?'); | ||||||
|  |     if (index == std::string::npos) { | ||||||
|  |         emit MainWindowOpenPage(url, ""); | ||||||
|  |     } else { | ||||||
|  |         const auto front = url.substr(0, index); | ||||||
|  |         const auto back = url.substr(index); | ||||||
|  |         emit MainWindowOpenPage(front, back); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void QtWebBrowser::MainWindowUnpackRomFS() { | ||||||
|  |     // Acquire the HLE mutex
 | ||||||
|  |     std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||||||
|  |     unpack_romfs_callback(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void QtWebBrowser::MainWindowFinishedBrowsing() { | ||||||
|  |     // Acquire the HLE mutex
 | ||||||
|  |     std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||||||
|  |     finished_callback(); | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								src/yuzu/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/yuzu/applets/web_browser.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright 2018 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <functional> | ||||||
|  | #include <QObject> | ||||||
|  | 
 | ||||||
|  | #ifdef YUZU_USE_QT_WEB_ENGINE | ||||||
|  | #include <QWebEngineView> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include "core/frontend/applets/web_browser.h" | ||||||
|  | 
 | ||||||
|  | class GMainWindow; | ||||||
|  | 
 | ||||||
|  | #ifdef YUZU_USE_QT_WEB_ENGINE | ||||||
|  | 
 | ||||||
|  | QString GetNXShimInjectionScript(); | ||||||
|  | 
 | ||||||
|  | class NXInputWebEngineView : public QWebEngineView { | ||||||
|  | public: | ||||||
|  |     explicit NXInputWebEngineView(QWidget* parent = nullptr); | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     void keyPressEvent(QKeyEvent* event) override; | ||||||
|  |     void keyReleaseEvent(QKeyEvent* event) override; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet { | ||||||
|  |     Q_OBJECT | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     explicit QtWebBrowser(GMainWindow& main_window); | ||||||
|  |     ~QtWebBrowser() override; | ||||||
|  | 
 | ||||||
|  |     void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, | ||||||
|  |                   std::function<void()> finished_callback) const override; | ||||||
|  | 
 | ||||||
|  | signals: | ||||||
|  |     void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const; | ||||||
|  | 
 | ||||||
|  | public slots: | ||||||
|  |     void MainWindowUnpackRomFS(); | ||||||
|  |     void MainWindowFinishedBrowsing(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     mutable std::function<void()> unpack_romfs_callback; | ||||||
|  |     mutable std::function<void()> finished_callback; | ||||||
|  | }; | ||||||
| @ -10,11 +10,14 @@ | |||||||
| // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 | ||||||
| #include "applets/profile_select.h" | #include "applets/profile_select.h" | ||||||
| #include "applets/software_keyboard.h" | #include "applets/software_keyboard.h" | ||||||
|  | #include "applets/web_browser.h" | ||||||
| #include "configuration/configure_per_general.h" | #include "configuration/configure_per_general.h" | ||||||
| #include "core/file_sys/vfs.h" | #include "core/file_sys/vfs.h" | ||||||
| #include "core/file_sys/vfs_real.h" | #include "core/file_sys/vfs_real.h" | ||||||
| #include "core/hle/service/acc/profile_manager.h" | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "core/hle/service/am/applets/applets.h" | #include "core/hle/service/am/applets/applets.h" | ||||||
|  | #include "core/hle/service/hid/controllers/npad.h" | ||||||
|  | #include "core/hle/service/hid/hid.h" | ||||||
| 
 | 
 | ||||||
| // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
 | // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
 | ||||||
| // defines.
 | // defines.
 | ||||||
| @ -96,6 +99,14 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||||||
| #include "yuzu/discord_impl.h" | #include "yuzu/discord_impl.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef YUZU_USE_QT_WEB_ENGINE | ||||||
|  | #include <QWebEngineProfile> | ||||||
|  | #include <QWebEngineScript> | ||||||
|  | #include <QWebEngineScriptCollection> | ||||||
|  | #include <QWebEngineSettings> | ||||||
|  | #include <QWebEngineView> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef QT_STATICPLUGIN | #ifdef QT_STATICPLUGIN | ||||||
| Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); | ||||||
| #endif | #endif | ||||||
| @ -252,6 +263,144 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message | |||||||
|     emit SoftwareKeyboardFinishedCheckDialog(); |     emit SoftwareKeyboardFinishedCheckDialog(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef YUZU_USE_QT_WEB_ENGINE | ||||||
|  | 
 | ||||||
|  | void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { | ||||||
|  |     NXInputWebEngineView web_browser_view(this); | ||||||
|  | 
 | ||||||
|  |     // Scope to contain the QProgressDialog for initalization
 | ||||||
|  |     { | ||||||
|  |         QProgressDialog progress(this); | ||||||
|  |         progress.setMinimumDuration(200); | ||||||
|  |         progress.setLabelText(tr("Loading Web Applet...")); | ||||||
|  |         progress.setRange(0, 4); | ||||||
|  |         progress.setValue(0); | ||||||
|  |         progress.show(); | ||||||
|  | 
 | ||||||
|  |         auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); }); | ||||||
|  | 
 | ||||||
|  |         while (!future.isFinished()) | ||||||
|  |             QApplication::processEvents(); | ||||||
|  | 
 | ||||||
|  |         progress.setValue(1); | ||||||
|  | 
 | ||||||
|  |         // Load the special shim script to handle input and exit.
 | ||||||
|  |         QWebEngineScript nx_shim; | ||||||
|  |         nx_shim.setSourceCode(GetNXShimInjectionScript()); | ||||||
|  |         nx_shim.setWorldId(QWebEngineScript::MainWorld); | ||||||
|  |         nx_shim.setName("nx_inject.js"); | ||||||
|  |         nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation); | ||||||
|  |         nx_shim.setRunsOnSubFrames(true); | ||||||
|  |         web_browser_view.page()->profile()->scripts()->insert(nx_shim); | ||||||
|  | 
 | ||||||
|  |         web_browser_view.load( | ||||||
|  |             QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() + | ||||||
|  |                  QString::fromStdString(std::string(additional_args)))); | ||||||
|  | 
 | ||||||
|  |         progress.setValue(2); | ||||||
|  | 
 | ||||||
|  |         render_window->hide(); | ||||||
|  |         web_browser_view.setFocus(); | ||||||
|  | 
 | ||||||
|  |         const auto& layout = render_window->GetFramebufferLayout(); | ||||||
|  |         web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight()); | ||||||
|  |         web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height()); | ||||||
|  |         web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) / | ||||||
|  |                                        Layout::ScreenUndocked::Width); | ||||||
|  |         web_browser_view.settings()->setAttribute( | ||||||
|  |             QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); | ||||||
|  | 
 | ||||||
|  |         web_browser_view.show(); | ||||||
|  | 
 | ||||||
|  |         progress.setValue(3); | ||||||
|  | 
 | ||||||
|  |         QApplication::processEvents(); | ||||||
|  | 
 | ||||||
|  |         progress.setValue(4); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool finished = false; | ||||||
|  |     QAction* exit_action = new QAction(tr("Exit Web Applet"), this); | ||||||
|  |     connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; }); | ||||||
|  |     ui.menubar->addAction(exit_action); | ||||||
|  | 
 | ||||||
|  |     auto& npad = | ||||||
|  |         Core::System::GetInstance() | ||||||
|  |             .ServiceManager() | ||||||
|  |             .GetService<Service::HID::Hid>("hid") | ||||||
|  |             ->GetAppletResource() | ||||||
|  |             ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); | ||||||
|  | 
 | ||||||
|  |     const auto fire_js_keypress = [&web_browser_view](u32 key_code) { | ||||||
|  |         web_browser_view.page()->runJavaScript( | ||||||
|  |             QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));") | ||||||
|  |                 .arg(QString::fromStdString(std::to_string(key_code)))); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     bool running_exit_check = false; | ||||||
|  |     while (!finished) { | ||||||
|  |         QApplication::processEvents(); | ||||||
|  | 
 | ||||||
|  |         if (!running_exit_check) { | ||||||
|  |             web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"), | ||||||
|  |                                                    [&](const QVariant& res) { | ||||||
|  |                                                        running_exit_check = false; | ||||||
|  |                                                        if (res.toBool()) | ||||||
|  |                                                            finished = true; | ||||||
|  |                                                    }); | ||||||
|  |             running_exit_check = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const auto input = npad.GetAndResetPressState(); | ||||||
|  |         for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||||||
|  |             if ((input & (1 << i)) != 0) { | ||||||
|  |                 LOG_DEBUG(Frontend, "firing input for button id={:02X}", i); | ||||||
|  |                 web_browser_view.page()->runJavaScript( | ||||||
|  |                     QStringLiteral("yuzu_key_callbacks[%1]();").arg(i)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (input & 0x00888000)      // RStick Down | LStick Down | DPad Down
 | ||||||
|  |             fire_js_keypress(40);    // Down Arrow Key
 | ||||||
|  |         else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
 | ||||||
|  |             fire_js_keypress(39);    // Right Arrow Key
 | ||||||
|  |         else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
 | ||||||
|  |             fire_js_keypress(38);    // Up Arrow Key
 | ||||||
|  |         else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
 | ||||||
|  |             fire_js_keypress(37);    // Left Arrow Key
 | ||||||
|  |         else if (input & 0x00000001) // A Button
 | ||||||
|  |             fire_js_keypress(13);    // Enter Key
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     web_browser_view.hide(); | ||||||
|  |     render_window->show(); | ||||||
|  |     render_window->setFocus(); | ||||||
|  |     ui.menubar->removeAction(exit_action); | ||||||
|  | 
 | ||||||
|  |     // Needed to update render window focus/show and remove menubar action
 | ||||||
|  |     QApplication::processEvents(); | ||||||
|  |     emit WebBrowserFinishedBrowsing(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { | ||||||
|  |     QMessageBox::warning( | ||||||
|  |         this, tr("Web Applet"), | ||||||
|  |         tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot " | ||||||
|  |            "properly display the game manual or web page requested."), | ||||||
|  |         QMessageBox::Ok, QMessageBox::Ok); | ||||||
|  | 
 | ||||||
|  |     LOG_INFO(Frontend, | ||||||
|  |              "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at " | ||||||
|  |              "'{}' with arguments '{}'!", | ||||||
|  |              filename, additional_args); | ||||||
|  | 
 | ||||||
|  |     emit WebBrowserFinishedBrowsing(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| void GMainWindow::InitializeWidgets() { | void GMainWindow::InitializeWidgets() { | ||||||
| #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING | #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING | ||||||
|     ui.action_Report_Compatibility->setVisible(true); |     ui.action_Report_Compatibility->setVisible(true); | ||||||
| @ -612,6 +761,7 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||||||
| 
 | 
 | ||||||
|     system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this)); |     system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this)); | ||||||
|     system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); |     system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); | ||||||
|  |     system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this)); | ||||||
| 
 | 
 | ||||||
|     const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; |     const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; | ||||||
| 
 | 
 | ||||||
| @ -1325,6 +1475,7 @@ void GMainWindow::OnStartGame() { | |||||||
|     qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); |     qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); | ||||||
|     qRegisterMetaType<std::string>("std::string"); |     qRegisterMetaType<std::string>("std::string"); | ||||||
|     qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); |     qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); | ||||||
|  |     qRegisterMetaType<std::string_view>("std::string_view"); | ||||||
| 
 | 
 | ||||||
|     connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); |     connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "ui_main.h" | #include "ui_main.h" | ||||||
| #include "yuzu/compatibility_list.h" | #include "yuzu/compatibility_list.h" | ||||||
| #include "yuzu/hotkeys.h" | #include "yuzu/hotkeys.h" | ||||||
| @ -26,6 +27,7 @@ class GraphicsSurfaceWidget; | |||||||
| class GRenderWindow; | class GRenderWindow; | ||||||
| class MicroProfileDialog; | class MicroProfileDialog; | ||||||
| class ProfilerWidget; | class ProfilerWidget; | ||||||
|  | class QLabel; | ||||||
| class WaitTreeWidget; | class WaitTreeWidget; | ||||||
| enum class GameListOpenTarget; | enum class GameListOpenTarget; | ||||||
| 
 | 
 | ||||||
| @ -103,11 +105,16 @@ signals: | |||||||
|     void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); |     void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); | ||||||
|     void SoftwareKeyboardFinishedCheckDialog(); |     void SoftwareKeyboardFinishedCheckDialog(); | ||||||
| 
 | 
 | ||||||
|  |     void WebBrowserUnpackRomFS(); | ||||||
|  |     void WebBrowserFinishedBrowsing(); | ||||||
|  | 
 | ||||||
| public slots: | public slots: | ||||||
|     void ProfileSelectorSelectProfile(); |     void ProfileSelectorSelectProfile(); | ||||||
|     void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); |     void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); | ||||||
|     void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); |     void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); | ||||||
| 
 | 
 | ||||||
|  |     void WebBrowserOpenPage(std::string_view filename, std::string_view arguments); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     void InitializeWidgets(); |     void InitializeWidgets(); | ||||||
|     void InitializeDebugWidgets(); |     void InitializeDebugWidgets(); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei