summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Hilman <zachhilman@gmail.com>2018-12-24 22:23:31 +0100
committerZach Hilman <zachhilman@gmail.com>2018-12-28 21:32:39 +0100
commit45da3be40edd71195b7aac633187fc81956e3150 (patch)
tree52e297ec9e0d34e99300f3eb944534c4f9f187e3
parentqt: Implement Qt frontend to web browser (diff)
downloadyuzu-45da3be40edd71195b7aac633187fc81956e3150.tar
yuzu-45da3be40edd71195b7aac633187fc81956e3150.tar.gz
yuzu-45da3be40edd71195b7aac633187fc81956e3150.tar.bz2
yuzu-45da3be40edd71195b7aac633187fc81956e3150.tar.lz
yuzu-45da3be40edd71195b7aac633187fc81956e3150.tar.xz
yuzu-45da3be40edd71195b7aac633187fc81956e3150.tar.zst
yuzu-45da3be40edd71195b7aac633187fc81956e3150.zip
-rw-r--r--src/yuzu/CMakeLists.txt7
-rw-r--r--src/yuzu/main.cpp151
-rw-r--r--src/yuzu/main.h10
3 files changed, 168 insertions, 0 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 17ecaafde..c6378bce9 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -11,6 +11,8 @@ add_executable(yuzu
applets/profile_select.h
applets/software_keyboard.cpp
applets/software_keyboard.h
+ applets/web_browser.cpp
+ applets/web_browser.h
bootmanager.cpp
bootmanager.h
compatibility_list.cpp
@@ -154,6 +156,11 @@ if (USE_DISCORD_PRESENCE)
target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
endif()
+if (YUZU_USE_QT_WEB_ENGINE)
+ target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets)
+ target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
+endif ()
+
if(UNIX AND NOT APPLE)
install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 01a0f94ab..18dc93c95 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -10,11 +10,14 @@
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
#include "applets/profile_select.h"
#include "applets/software_keyboard.h"
+#include "applets/web_browser.h"
#include "configuration/configure_per_general.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
// defines.
@@ -96,6 +99,14 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/discord_impl.h"
#endif
+#ifdef YUZU_USE_QT_WEB_ENGINE
+#include <QWebEngineProfile>
+#include <QWebEngineScript>
+#include <QWebEngineScriptCollection>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+#endif
+
#ifdef QT_STATICPLUGIN
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#endif
@@ -252,6 +263,144 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message
emit SoftwareKeyboardFinishedCheckDialog();
}
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+ NXInputWebEngineView web_browser_view(this);
+
+ // Scope to contain the QProgressDialog for initalization
+ {
+ QProgressDialog progress(this);
+ progress.setMinimumDuration(200);
+ progress.setLabelText(tr("Loading Web Applet..."));
+ progress.setRange(0, 4);
+ progress.setValue(0);
+ progress.show();
+
+ auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); });
+
+ while (!future.isFinished())
+ QApplication::processEvents();
+
+ progress.setValue(1);
+
+ // Load the special shim script to handle input and exit.
+ QWebEngineScript nx_shim;
+ nx_shim.setSourceCode(GetNXShimInjectionScript());
+ nx_shim.setWorldId(QWebEngineScript::MainWorld);
+ nx_shim.setName("nx_inject.js");
+ nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation);
+ nx_shim.setRunsOnSubFrames(true);
+ web_browser_view.page()->profile()->scripts()->insert(nx_shim);
+
+ web_browser_view.load(
+ QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() +
+ QString::fromStdString(std::string(additional_args))));
+
+ progress.setValue(2);
+
+ render_window->hide();
+ web_browser_view.setFocus();
+
+ const auto& layout = render_window->GetFramebufferLayout();
+ web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight());
+ web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height());
+ web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) /
+ Layout::ScreenUndocked::Width);
+ web_browser_view.settings()->setAttribute(
+ QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
+
+ web_browser_view.show();
+
+ progress.setValue(3);
+
+ QApplication::processEvents();
+
+ progress.setValue(4);
+ }
+
+ bool finished = false;
+ QAction* exit_action = new QAction(tr("Exit Web Applet"), this);
+ connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; });
+ ui.menubar->addAction(exit_action);
+
+ auto& npad =
+ Core::System::GetInstance()
+ .ServiceManager()
+ .GetService<Service::HID::Hid>("hid")
+ ->GetAppletResource()
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+ const auto fire_js_keypress = [&web_browser_view](u32 key_code) {
+ web_browser_view.page()->runJavaScript(
+ QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));")
+ .arg(QString::fromStdString(std::to_string(key_code))));
+ };
+
+ bool running_exit_check = false;
+ while (!finished) {
+ QApplication::processEvents();
+
+ if (!running_exit_check) {
+ web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"),
+ [&](const QVariant& res) {
+ running_exit_check = false;
+ if (res.toBool())
+ finished = true;
+ });
+ running_exit_check = true;
+ }
+
+ const auto input = npad.GetPressState();
+ for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+ if ((input & (1 << i)) != 0) {
+ LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);
+ web_browser_view.page()->runJavaScript(
+ QStringLiteral("yuzu_key_callbacks[%1]();").arg(i));
+ }
+ }
+
+ if (input & 0x00888000) // RStick Down | LStick Down | DPad Down
+ fire_js_keypress(40); // Down Arrow Key
+ else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
+ fire_js_keypress(39); // Right Arrow Key
+ else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
+ fire_js_keypress(38); // Up Arrow Key
+ else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
+ fire_js_keypress(37); // Left Arrow Key
+ else if (input & 0x00000001) // A Button
+ fire_js_keypress(13); // Enter Key
+ }
+
+ web_browser_view.hide();
+ render_window->show();
+ render_window->setFocus();
+ ui.menubar->removeAction(exit_action);
+
+ // Needed to update render window focus/show and remove menubar action
+ QApplication::processEvents();
+ emit WebBrowserFinishedBrowsing();
+}
+
+#else
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+ QMessageBox::warning(
+ this, tr("Web Applet"),
+ tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
+ "properly display the game manual or web page requested."),
+ QMessageBox::Ok, QMessageBox::Ok);
+
+ LOG_INFO(Frontend,
+ "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
+ "'{}' with arguments '{}'!",
+ filename, additional_args);
+
+ emit WebBrowserFinishedBrowsing();
+}
+
+#endif
+
void GMainWindow::InitializeWidgets() {
#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
ui.action_Report_Compatibility->setVisible(true);
@@ -612,6 +761,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this));
system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
+ system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this));
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
@@ -1315,6 +1465,7 @@ void GMainWindow::OnStartGame() {
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
+ qRegisterMetaType<std::string_view>("std::string_view");
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 4e37f6a2d..3af5fa1f3 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -26,6 +26,7 @@ class GraphicsSurfaceWidget;
class GRenderWindow;
class MicroProfileDialog;
class ProfilerWidget;
+class QLabel;
class WaitTreeWidget;
enum class GameListOpenTarget;
@@ -38,6 +39,10 @@ class RegisteredCacheUnion;
class VfsFilesystem;
} // namespace FileSys
+namespace Service::Account {
+struct UUID;
+} // namespace Service::Account
+
namespace Tegra {
class DebugContext;
}
@@ -103,11 +108,16 @@ signals:
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
void SoftwareKeyboardFinishedCheckDialog();
+ void WebBrowserUnpackRomFS();
+ void WebBrowserFinishedBrowsing();
+
public slots:
void ProfileSelectorSelectProfile();
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
+ void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
+
private:
void InitializeWidgets();
void InitializeDebugWidgets();