Merge pull request #1939 from DarkLordZach/web-applet
applets: Implement HLE web browser applet (LibAppletOff)
This commit is contained in:
commit
83e8ad2331
30 changed files with 1413 additions and 623 deletions
|
@ -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)
|
||||||
|
|
|
@ -35,6 +35,7 @@ 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<
|
||||||
|
|
|
@ -40,25 +40,8 @@ constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66;
|
||||||
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
|
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
|
||||||
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
|
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
|
||||||
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
||||||
enum class HidController : std::size_t {
|
|
||||||
DebugPad,
|
|
||||||
Touchscreen,
|
|
||||||
Mouse,
|
|
||||||
Keyboard,
|
|
||||||
XPad,
|
|
||||||
Unknown1,
|
|
||||||
Unknown2,
|
|
||||||
Unknown3,
|
|
||||||
SixAxisSensor,
|
|
||||||
NPad,
|
|
||||||
Gesture,
|
|
||||||
|
|
||||||
MaxControllers,
|
IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
|
||||||
};
|
|
||||||
|
|
||||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
|
||||||
public:
|
|
||||||
IAppletResource() : ServiceFramework("IAppletResource") {
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||||
};
|
};
|
||||||
|
@ -90,9 +73,10 @@ public:
|
||||||
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
|
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
|
||||||
|
|
||||||
// Register update callbacks
|
// Register update callbacks
|
||||||
pad_update_event = CoreTiming::RegisterEvent(
|
pad_update_event =
|
||||||
"HID::UpdatePadCallback",
|
CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
|
||||||
[this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); });
|
UpdateControllers(userdata, cycles_late);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
|
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
|
||||||
|
|
||||||
|
@ -101,30 +85,19 @@ public:
|
||||||
ReloadInputDevices();
|
ReloadInputDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateController(HidController controller) {
|
void IAppletResource::ActivateController(HidController controller) {
|
||||||
controllers[static_cast<size_t>(controller)]->ActivateController();
|
controllers[static_cast<size_t>(controller)]->ActivateController();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeactivateController(HidController controller) {
|
void IAppletResource::DeactivateController(HidController controller) {
|
||||||
controllers[static_cast<size_t>(controller)]->DeactivateController();
|
controllers[static_cast<size_t>(controller)]->DeactivateController();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
IAppletResource ::~IAppletResource() {
|
||||||
void MakeController(HidController controller) {
|
|
||||||
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T& GetController(HidController controller) {
|
|
||||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
~IAppletResource() {
|
|
||||||
CoreTiming::UnscheduleEvent(pad_update_event, 0);
|
CoreTiming::UnscheduleEvent(pad_update_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_HID, "called");
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
@ -132,7 +105,7 @@ private:
|
||||||
rb.PushCopyObjects(shared_mem);
|
rb.PushCopyObjects(shared_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateControllers(u64 userdata, int cycles_late) {
|
void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
|
||||||
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
|
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
|
||||||
for (const auto& controller : controllers) {
|
for (const auto& controller : controllers) {
|
||||||
if (should_reload) {
|
if (should_reload) {
|
||||||
|
@ -144,16 +117,6 @@ private:
|
||||||
CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
|
CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle to shared memory region designated to HID service
|
|
||||||
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
|
|
||||||
|
|
||||||
// CoreTiming update events
|
|
||||||
CoreTiming::EventType* pad_update_event;
|
|
||||||
|
|
||||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
|
||||||
controllers{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
|
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
|
||||||
public:
|
public:
|
||||||
IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
|
IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
|
||||||
|
@ -172,9 +135,15 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Hid final : public ServiceFramework<Hid> {
|
std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
|
||||||
public:
|
if (applet_resource == nullptr) {
|
||||||
Hid() : ServiceFramework("hid") {
|
applet_resource = std::make_shared<IAppletResource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return applet_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hid::Hid() : ServiceFramework("hid") {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
|
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
|
||||||
|
@ -300,12 +269,10 @@ public:
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
~Hid() = default;
|
|
||||||
|
|
||||||
private:
|
Hid::~Hid() = default;
|
||||||
std::shared_ptr<IAppletResource> applet_resource;
|
|
||||||
|
|
||||||
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -320,20 +287,20 @@ private:
|
||||||
rb.PushIpcInterface<IAppletResource>(applet_resource);
|
rb.PushIpcInterface<IAppletResource>(applet_resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateXpad(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto basic_xpad_id{rp.Pop<u32>()};
|
const auto basic_xpad_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
|
LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id,
|
||||||
basic_xpad_id, applet_resource_user_id);
|
applet_resource_user_id);
|
||||||
|
|
||||||
applet_resource->ActivateController(HidController::XPad);
|
applet_resource->ActivateController(HidController::XPad);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -344,7 +311,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -355,7 +322,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateMouse(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -366,7 +333,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -377,7 +344,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateGesture(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto unknown{rp.Pop<u32>()};
|
const auto unknown{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -390,7 +357,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
|
||||||
// Should have no effect with how our npad sets up the data
|
// Should have no effect with how our npad sets up the data
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto unknown{rp.Pop<u32>()};
|
const auto unknown{rp.Pop<u32>()};
|
||||||
|
@ -404,7 +371,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto handle{rp.Pop<u32>()};
|
const auto handle{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -416,21 +383,21 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto handle{rp.Pop<u32>()};
|
const auto handle{rp.Pop<u32>()};
|
||||||
const auto drift_mode{rp.Pop<u32>()};
|
const auto drift_mode{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_WARNING(Service_HID,
|
LOG_WARNING(Service_HID,
|
||||||
"(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}",
|
"(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
|
||||||
handle, drift_mode, applet_resource_user_id);
|
drift_mode, applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
|
void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto handle{rp.Pop<u32>()};
|
const auto handle{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -444,7 +411,7 @@ private:
|
||||||
rb.Push(true);
|
rb.Push(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto supported_styleset{rp.Pop<u32>()};
|
const auto supported_styleset{rp.Pop<u32>()};
|
||||||
|
|
||||||
|
@ -457,7 +424,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -470,7 +437,7 @@ private:
|
||||||
rb.Push<u32>(controller.GetSupportedStyleSet().raw);
|
rb.Push<u32>(controller.GetSupportedStyleSet().raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
|
void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -482,7 +449,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateNpad(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -493,14 +460,14 @@ private:
|
||||||
applet_resource->ActivateController(HidController::NPad);
|
applet_resource->ActivateController(HidController::NPad);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
|
void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto npad_id{rp.Pop<u32>()};
|
const auto npad_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
const auto unknown{rp.Pop<u64>()};
|
const auto unknown{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
|
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id,
|
||||||
npad_id, applet_resource_user_id, unknown);
|
applet_resource_user_id, unknown);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -508,7 +475,7 @@ private:
|
||||||
.GetStyleSetChangedEvent());
|
.GetStyleSetChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisconnectNpad(Kernel::HLERequestContext& ctx) {
|
void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto npad_id{rp.Pop<u32>()};
|
const auto npad_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -516,13 +483,12 @@ private:
|
||||||
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
|
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
|
||||||
applet_resource_user_id);
|
applet_resource_user_id);
|
||||||
|
|
||||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
|
||||||
.DisconnectNPad(npad_id);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
|
void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto npad_id{rp.Pop<u32>()};
|
const auto npad_id{rp.Pop<u32>()};
|
||||||
|
|
||||||
|
@ -535,7 +501,7 @@ private:
|
||||||
.raw);
|
.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
const auto hold_type{rp.Pop<u64>()};
|
const auto hold_type{rp.Pop<u64>()};
|
||||||
|
@ -550,60 +516,57 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
const auto& controller =
|
const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||||
applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
|
rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
|
void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto npad_id{rp.Pop<u32>()};
|
const auto npad_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
|
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
|
||||||
npad_id, applet_resource_user_id);
|
applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
|
||||||
.SetVibrationEnabled(true);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_HID, "called");
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
|
||||||
.SetVibrationEnabled(false);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendVibrationValue(Kernel::HLERequestContext& ctx) {
|
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto controller_id{rp.Pop<u32>()};
|
const auto controller_id{rp.Pop<u32>()};
|
||||||
const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
|
const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}",
|
LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
|
||||||
controller_id, applet_resource_user_id);
|
applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -612,7 +575,7 @@ private:
|
||||||
.VibrateController({controller_id}, {vibration_values});
|
.VibrateController({controller_id}, {vibration_values});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -637,22 +600,21 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
|
void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto controller_id{rp.Pop<u32>()};
|
const auto controller_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}",
|
LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
|
||||||
controller_id, applet_resource_user_id);
|
applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw<Controller_NPad::Vibration>(
|
rb.PushRaw<Controller_NPad::Vibration>(
|
||||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
|
||||||
.GetLastVibration());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
|
void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto npad_id{rp.Pop<u32>()};
|
const auto npad_id{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -667,7 +629,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
|
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto unknown_1{rp.Pop<u32>()};
|
const auto unknown_1{rp.Pop<u32>()};
|
||||||
const auto unknown_2{rp.Pop<u32>()};
|
const auto unknown_2{rp.Pop<u32>()};
|
||||||
|
@ -681,7 +643,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
const auto mode{rp.Pop<u64>()};
|
const auto mode{rp.Pop<u64>()};
|
||||||
|
@ -693,7 +655,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_HID, "called");
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
@ -702,7 +664,7 @@ private:
|
||||||
rb.Push<u32>(0);
|
rb.Push<u32>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
|
void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_HID, "called");
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
@ -710,7 +672,7 @@ private:
|
||||||
rb.PushIpcInterface<IActiveVibrationDeviceList>();
|
rb.PushIpcInterface<IActiveVibrationDeviceList>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
@ -721,7 +683,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto handle{rp.Pop<u32>()};
|
const auto handle{rp.Pop<u32>()};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
@ -733,7 +695,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto handle{rp.Pop<u32>()};
|
const auto handle{rp.Pop<u32>()};
|
||||||
|
|
||||||
|
@ -743,7 +705,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
const auto unknown{rp.Pop<u32>()};
|
const auto unknown{rp.Pop<u32>()};
|
||||||
|
@ -755,7 +717,7 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto unknown{rp.Pop<u32>()};
|
const auto unknown{rp.Pop<u32>()};
|
||||||
|
|
||||||
|
@ -764,7 +726,6 @@ private:
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
class HidDbg final : public ServiceFramework<HidDbg> {
|
class HidDbg final : public ServiceFramework<HidDbg> {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -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 a new issue