|
|
@ -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.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() { |
|
|
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())}; |
|
|
|
|
|
|
|
|
@ -1315,6 +1465,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); |
|
|
|
|
|
|
|
|
|