input_common: Eliminate most global state

Abstracts most of the input mechanisms under an InputSubsystem class
that is managed by the frontends, eliminating any static constructors
and destructors. This gets rid of global accessor functions and also
allows the frontends to have a more fine-grained control over the
lifecycle of the input subsystem.

This also makes it explicit which interfaces rely on the input subsystem
instead of making it opaque in the interface functions. All that remains
to migrate over is the factories, which can be done in a separate
change.
This commit is contained in:
Lioncash 2020-08-27 15:16:47 -04:00
parent 3db9a25977
commit 9e1b0af259
25 changed files with 397 additions and 243 deletions

View File

@ -18,16 +18,8 @@
namespace InputCommon { namespace InputCommon {
static std::shared_ptr<Keyboard> keyboard; struct InputSubsystem::Impl {
static std::shared_ptr<MotionEmu> motion_emu; void Initialize() {
#ifdef HAVE_SDL2
static std::unique_ptr<SDL::State> sdl;
#endif
static std::unique_ptr<CemuhookUDP::State> udp;
static std::shared_ptr<GCButtonFactory> gcbuttons;
static std::shared_ptr<GCAnalogFactory> gcanalog;
void Init() {
auto gcadapter = std::make_shared<GCAdapter::Adapter>(); auto gcadapter = std::make_shared<GCAdapter::Adapter>();
gcbuttons = std::make_shared<GCButtonFactory>(gcadapter); gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
@ -44,10 +36,11 @@ void Init() {
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
sdl = SDL::Init(); sdl = SDL::Init();
#endif #endif
udp = CemuhookUDP::Init();
}
void Shutdown() { udp = CemuhookUDP::Init();
}
void Shutdown() {
Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
keyboard.reset(); keyboard.reset();
Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
@ -62,22 +55,129 @@ void Shutdown() {
gcbuttons.reset(); gcbuttons.reset();
gcanalog.reset(); gcanalog.reset();
}
[[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
std::vector<Common::ParamPackage> devices = {
Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
};
#ifdef HAVE_SDL2
auto sdl_devices = sdl->GetInputDevices();
devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
#endif
auto udp_devices = udp->GetInputDevices();
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
return devices;
}
[[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") {
return {};
}
if (params.Get("class", "") == "key") {
// TODO consider returning the SDL key codes for the default keybindings
return {};
}
#ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") {
return sdl->GetAnalogMappingForDevice(params);
}
#endif
return {};
}
[[nodiscard]] ButtonMapping GetButtonMappingForDevice(
const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") {
return {};
}
if (params.Get("class", "") == "key") {
// TODO consider returning the SDL key codes for the default keybindings
return {};
}
#ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") {
return sdl->GetButtonMappingForDevice(params);
}
#endif
return {};
}
std::shared_ptr<Keyboard> keyboard;
std::shared_ptr<MotionEmu> motion_emu;
#ifdef HAVE_SDL2
std::unique_ptr<SDL::State> sdl;
#endif
std::unique_ptr<CemuhookUDP::State> udp;
std::shared_ptr<GCButtonFactory> gcbuttons;
std::shared_ptr<GCAnalogFactory> gcanalog;
};
InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
InputSubsystem::~InputSubsystem() = default;
void InputSubsystem::Initialize() {
impl->Initialize();
} }
Keyboard* GetKeyboard() { void InputSubsystem::Shutdown() {
return keyboard.get(); impl->Shutdown();
} }
MotionEmu* GetMotionEmu() { Keyboard* InputSubsystem::GetKeyboard() {
return motion_emu.get(); return impl->keyboard.get();
} }
GCButtonFactory* GetGCButtons() { const Keyboard* InputSubsystem::GetKeyboard() const {
return gcbuttons.get(); return impl->keyboard.get();
} }
GCAnalogFactory* GetGCAnalogs() { MotionEmu* InputSubsystem::GetMotionEmu() {
return gcanalog.get(); return impl->motion_emu.get();
}
const MotionEmu* InputSubsystem::GetMotionEmu() const {
return impl->motion_emu.get();
}
std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
return impl->GetInputDevices();
}
AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const {
return impl->GetAnalogMappingForDevice(device);
}
ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const {
return impl->GetButtonMappingForDevice(device);
}
GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
return impl->gcanalog.get();
}
const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const {
return impl->gcanalog.get();
}
GCButtonFactory* InputSubsystem::GetGCButtons() {
return impl->gcbuttons.get();
}
const GCButtonFactory* InputSubsystem::GetGCButtons() const {
return impl->gcbuttons.get();
}
std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
Polling::DeviceType type) const {
#ifdef HAVE_SDL2
return impl->sdl->GetPollers(type);
#else
return {};
#endif
} }
std::string GenerateKeyboardParam(int key_code) { std::string GenerateKeyboardParam(int key_code) {
@ -101,68 +201,4 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
}; };
return circle_pad_param.Serialize(); return circle_pad_param.Serialize();
} }
std::vector<Common::ParamPackage> GetInputDevices() {
std::vector<Common::ParamPackage> devices = {
Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
};
#ifdef HAVE_SDL2
auto sdl_devices = sdl->GetInputDevices();
devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
#endif
auto udp_devices = udp->GetInputDevices();
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
return devices;
}
std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
const Common::ParamPackage& params) {
std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings;
if (!params.Has("class") || params.Get("class", "") == "any") {
return {};
}
if (params.Get("class", "") == "key") {
// TODO consider returning the SDL key codes for the default keybindings
return {};
}
#ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") {
return sdl->GetButtonMappingForDevice(params);
}
#endif
return {};
}
std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
const Common::ParamPackage& params) {
std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings;
if (!params.Has("class") || params.Get("class", "") == "any") {
return {};
}
if (params.Get("class", "") == "key") {
// TODO consider returning the SDL key codes for the default keybindings
return {};
}
#ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") {
return sdl->GetAnalogMappingForDevice(params);
}
#endif
return {};
}
namespace Polling {
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
std::vector<std::unique_ptr<DevicePoller>> pollers;
#ifdef HAVE_SDL2
pollers = sdl->GetPollers(type);
#endif
return pollers;
}
} // namespace Polling
} // namespace InputCommon } // namespace InputCommon

View File

@ -16,52 +16,6 @@ class ParamPackage;
} }
namespace InputCommon { namespace InputCommon {
/// Initializes and registers all built-in input device factories.
void Init();
/// Deregisters all built-in input device factories and shuts them down.
void Shutdown();
class Keyboard;
/// Gets the keyboard button device factory.
Keyboard* GetKeyboard();
class MotionEmu;
/// Gets the motion emulation factory.
MotionEmu* GetMotionEmu();
GCButtonFactory* GetGCButtons();
GCAnalogFactory* GetGCAnalogs();
/// Generates a serialized param package for creating a keyboard button device
std::string GenerateKeyboardParam(int key_code);
/// Generates a serialized param package for creating an analog device taking input from keyboard
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale);
/**
* Return a list of available input devices that this Factory can create a new device with.
* Each returned Parampackage should have a `display` field used for display, a class field for
* backends to determine if this backend is meant to service the request and any other information
* needed to identify this in the backend later.
*/
std::vector<Common::ParamPackage> GetInputDevices();
/**
* Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
* mapping for the device. This is currently only implemented for the sdl backend devices.
*/
using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
namespace Polling { namespace Polling {
enum class DeviceType { Button, AnalogPreferred }; enum class DeviceType { Button, AnalogPreferred };
@ -90,4 +44,88 @@ public:
// Get all DevicePoller from all backends for a specific device type // Get all DevicePoller from all backends for a specific device type
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type); std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
} // namespace Polling } // namespace Polling
class GCAnalogFactory;
class GCButtonFactory;
class Keyboard;
class MotionEmu;
/**
* Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
* mapping for the device. This is currently only implemented for the SDL backend devices.
*/
using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
class InputSubsystem {
public:
explicit InputSubsystem();
~InputSubsystem();
InputSubsystem(const InputSubsystem&) = delete;
InputSubsystem& operator=(const InputSubsystem&) = delete;
InputSubsystem(InputSubsystem&&) = delete;
InputSubsystem& operator=(InputSubsystem&&) = delete;
/// Initializes and registers all built-in input device factories.
void Initialize();
/// Unregisters all built-in input device factories and shuts them down.
void Shutdown();
/// Retrieves the underlying keyboard device.
[[nodiscard]] Keyboard* GetKeyboard();
/// Retrieves the underlying keyboard device.
[[nodiscard]] const Keyboard* GetKeyboard() const;
/// Retrieves the underlying motion emulation factory.
[[nodiscard]] MotionEmu* GetMotionEmu();
/// Retrieves the underlying motion emulation factory.
[[nodiscard]] const MotionEmu* GetMotionEmu() const;
/**
* Returns all available input devices that this Factory can create a new device with.
* Each returned ParamPackage should have a `display` field used for display, a class field for
* backends to determine if this backend is meant to service the request and any other
* information needed to identify this in the backend later.
*/
[[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
/// Retrieves the analog mappings for the given device.
[[nodiscard]] AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& device) const;
/// Retrieves the button mappings for the given device.
[[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
/// Retrieves the underlying GameCube analog handler.
[[nodiscard]] GCAnalogFactory* GetGCAnalogs();
/// Retrieves the underlying GameCube analog handler.
[[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const;
/// Retrieves the underlying GameCube button handler.
[[nodiscard]] GCButtonFactory* GetGCButtons();
/// Retrieves the underlying GameCube button handler.
[[nodiscard]] const GCButtonFactory* GetGCButtons() const;
/// Get all DevicePoller from all backends for a specific device type
[[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
Polling::DeviceType type) const;
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
/// Generates a serialized param package for creating a keyboard button device
std::string GenerateKeyboardParam(int key_code);
/// Generates a serialized param package for creating an analog device taking input from keyboard
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale);
} // namespace InputCommon } // namespace InputCommon

View File

@ -304,8 +304,9 @@ static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow*
return wsi; return wsi;
} }
GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_) GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
: QWidget(parent_), emu_thread(emu_thread_) { InputCommon::InputSubsystem* input_subsystem_)
: QWidget(parent), emu_thread(emu_thread_), input_subsystem{input_subsystem_} {
setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
.arg(QString::fromUtf8(Common::g_build_name), .arg(QString::fromUtf8(Common::g_build_name),
QString::fromUtf8(Common::g_scm_branch), QString::fromUtf8(Common::g_scm_branch),
@ -314,15 +315,15 @@ GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_)
auto layout = new QHBoxLayout(this); auto layout = new QHBoxLayout(this);
layout->setMargin(0); layout->setMargin(0);
setLayout(layout); setLayout(layout);
InputCommon::Init(); input_subsystem->Initialize();
this->setMouseTracking(true); this->setMouseTracking(true);
connect(this, &GRenderWindow::FirstFrameDisplayed, parent_, &GMainWindow::OnLoadComplete); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
} }
GRenderWindow::~GRenderWindow() { GRenderWindow::~GRenderWindow() {
InputCommon::Shutdown(); input_subsystem->Shutdown();
} }
void GRenderWindow::PollEvents() { void GRenderWindow::PollEvents() {
@ -391,11 +392,11 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
} }
void GRenderWindow::keyPressEvent(QKeyEvent* event) { void GRenderWindow::keyPressEvent(QKeyEvent* event) {
InputCommon::GetKeyboard()->PressKey(event->key()); input_subsystem->GetKeyboard()->PressKey(event->key());
} }
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
InputCommon::GetKeyboard()->ReleaseKey(event->key()); input_subsystem->GetKeyboard()->ReleaseKey(event->key());
} }
void GRenderWindow::mousePressEvent(QMouseEvent* event) { void GRenderWindow::mousePressEvent(QMouseEvent* event) {
@ -409,7 +410,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
const auto [x, y] = ScaleTouch(pos); const auto [x, y] = ScaleTouch(pos);
this->TouchPressed(x, y); this->TouchPressed(x, y);
} else if (event->button() == Qt::RightButton) { } else if (event->button() == Qt::RightButton) {
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); input_subsystem->GetMotionEmu()->BeginTilt(pos.x(), pos.y());
} }
QWidget::mousePressEvent(event); QWidget::mousePressEvent(event);
} }
@ -423,7 +424,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
auto pos = event->pos(); auto pos = event->pos();
const auto [x, y] = ScaleTouch(pos); const auto [x, y] = ScaleTouch(pos);
this->TouchMoved(x, y); this->TouchMoved(x, y);
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); input_subsystem->GetMotionEmu()->Tilt(pos.x(), pos.y());
QWidget::mouseMoveEvent(event); QWidget::mouseMoveEvent(event);
} }
@ -436,7 +437,7 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
this->TouchReleased(); this->TouchReleased();
} else if (event->button() == Qt::RightButton) { } else if (event->button() == Qt::RightButton) {
InputCommon::GetMotionEmu()->EndTilt(); input_subsystem->GetMotionEmu()->EndTilt();
} }
} }
@ -485,7 +486,7 @@ bool GRenderWindow::event(QEvent* event) {
void GRenderWindow::focusOutEvent(QFocusEvent* event) { void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event); QWidget::focusOutEvent(event);
InputCommon::GetKeyboard()->ReleaseAllKeys(); input_subsystem->GetKeyboard()->ReleaseAllKeys();
} }
void GRenderWindow::resizeEvent(QResizeEvent* event) { void GRenderWindow::resizeEvent(QResizeEvent* event) {

View File

@ -23,6 +23,10 @@ class QKeyEvent;
class QTouchEvent; class QTouchEvent;
class QStringList; class QStringList;
namespace InputCommon {
class InputSubsystem;
}
namespace VideoCore { namespace VideoCore {
enum class LoadCallbackStage; enum class LoadCallbackStage;
} }
@ -121,7 +125,8 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT Q_OBJECT
public: public:
GRenderWindow(GMainWindow* parent, EmuThread* emu_thread); explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
InputCommon::InputSubsystem* input_subsystem_);
~GRenderWindow() override; ~GRenderWindow() override;
// EmuWindow implementation. // EmuWindow implementation.
@ -183,6 +188,7 @@ private:
QStringList GetUnsupportedGLExtensions() const; QStringList GetUnsupportedGLExtensions() const;
EmuThread* emu_thread; EmuThread* emu_thread;
InputCommon::InputSubsystem* input_subsystem;
// Main context that will be shared with all other contexts that are requested. // Main context that will be shared with all other contexts that are requested.
// If this is used in a shared context setting, then this should not be used directly, but // If this is used in a shared context setting, then this should not be used directly, but

View File

@ -5,9 +5,10 @@
#include "ui_configure_debug_controller.h" #include "ui_configure_debug_controller.h"
#include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_debug_controller.h"
ConfigureDebugController::ConfigureDebugController(QWidget* parent) ConfigureDebugController::ConfigureDebugController(QWidget* parent,
InputCommon::InputSubsystem* input_subsystem)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()), : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
debug_controller(new ConfigureInputPlayer(this, 9, nullptr, true)) { debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, true)) {
ui->setupUi(this); ui->setupUi(this);
ui->controllerLayout->addWidget(debug_controller); ui->controllerLayout->addWidget(debug_controller);

View File

@ -10,6 +10,10 @@
class QPushButton; class QPushButton;
namespace InputCommon {
class InputSubsystem;
}
namespace Ui { namespace Ui {
class ConfigureDebugController; class ConfigureDebugController;
} }
@ -18,7 +22,8 @@ class ConfigureDebugController : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit ConfigureDebugController(QWidget* parent); explicit ConfigureDebugController(QWidget* parent,
InputCommon::InputSubsystem* input_subsystem);
~ConfigureDebugController() override; ~ConfigureDebugController() override;
void ApplyConfiguration(); void ApplyConfiguration();

View File

@ -12,7 +12,8 @@
#include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player.h"
#include "yuzu/hotkeys.h" #include "yuzu/hotkeys.h"
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
InputCommon::InputSubsystem* input_subsystem)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
Settings::configuring_global = true; Settings::configuring_global = true;
@ -20,6 +21,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ui->hotkeysTab->Populate(registry); ui->hotkeysTab->Populate(registry);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->inputTab->Initialize(input_subsystem);
SetConfiguration(); SetConfiguration();
PopulateSelectionList(); PopulateSelectionList();

View File

@ -9,6 +9,10 @@
class HotkeyRegistry; class HotkeyRegistry;
namespace InputCommon {
class InputSubsystem;
}
namespace Ui { namespace Ui {
class ConfigureDialog; class ConfigureDialog;
} }
@ -17,7 +21,8 @@ class ConfigureDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry); explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
InputCommon::InputSubsystem* input_subsystem);
~ConfigureDialog() override; ~ConfigureDialog() override;
void ApplyConfiguration(); void ApplyConfiguration();

View File

@ -65,16 +65,20 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
ConfigureInput::ConfigureInput(QWidget* parent) ConfigureInput::ConfigureInput(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
ui->setupUi(this); ui->setupUi(this);
}
ConfigureInput::~ConfigureInput() = default;
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
player_controllers = { player_controllers = {
new ConfigureInputPlayer(this, 0, ui->consoleInputSettings), new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 1, ui->consoleInputSettings), new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 2, ui->consoleInputSettings), new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 3, ui->consoleInputSettings), new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 4, ui->consoleInputSettings), new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 5, ui->consoleInputSettings), new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 6, ui->consoleInputSettings), new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem),
new ConfigureInputPlayer(this, 7, ui->consoleInputSettings), new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem),
}; };
player_tabs = { player_tabs = {
@ -115,10 +119,12 @@ ConfigureInput::ConfigureInput(QWidget* parent)
advanced = new ConfigureInputAdvanced(this); advanced = new ConfigureInputAdvanced(this);
ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
ui->tabAdvanced->layout()->addWidget(advanced); ui->tabAdvanced->layout()->addWidget(advanced);
connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
[this] { CallConfigureDialog<ConfigureDebugController>(*this); }); CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem);
connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, });
[this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); }); connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
});
connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
[this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
@ -129,8 +135,6 @@ ConfigureInput::ConfigureInput(QWidget* parent)
LoadConfiguration(); LoadConfiguration();
} }
ConfigureInput::~ConfigureInput() = default;
QList<QWidget*> ConfigureInput::GetSubTabs() const { QList<QWidget*> ConfigureInput::GetSubTabs() const {
return { return {
ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5, ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5,

View File

@ -7,8 +7,8 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include <QDialog>
#include <QKeyEvent> #include <QKeyEvent>
#include <QWidget>
#include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_advanced.h"
#include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player.h"
@ -19,6 +19,10 @@ class QCheckBox;
class QString; class QString;
class QTimer; class QTimer;
namespace InputCommon {
class InputSubsystem;
}
namespace Ui { namespace Ui {
class ConfigureInput; class ConfigureInput;
} }
@ -32,6 +36,9 @@ public:
explicit ConfigureInput(QWidget* parent = nullptr); explicit ConfigureInput(QWidget* parent = nullptr);
~ConfigureInput() override; ~ConfigureInput() override;
/// Initializes the input dialog with the given input subsystem.
void Initialize(InputCommon::InputSubsystem* input_subsystem_);
/// Save all button configurations to settings file. /// Save all button configurations to settings file.
void ApplyConfiguration(); void ApplyConfiguration();

View File

@ -11,12 +11,12 @@
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
#include <QTimer> #include <QTimer>
#include "common/assert.h"
#include "common/param_package.h" #include "common/param_package.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#include "input_common/gcadapter/gc_poller.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "ui_configure_input_player.h" #include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h" #include "yuzu/configuration/config.h"
@ -229,9 +229,11 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir)
} // namespace } // namespace
ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
QWidget* bottom_row, bool debug) QWidget* bottom_row,
InputCommon::InputSubsystem* input_subsystem_,
bool debug)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
debug(debug), timeout_timer(std::make_unique<QTimer>()), debug(debug), input_subsystem{input_subsystem_}, timeout_timer(std::make_unique<QTimer>()),
poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) { poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) {
ui->setupUi(this); ui->setupUi(this);
@ -287,7 +289,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
params.Set("direction", "+"); params.Set("direction", "+");
params.Set("threshold", "0.5"); params.Set("threshold", "0.5");
} }
(*param) = std::move(params); *param = std::move(params);
}, },
InputCommon::Polling::DeviceType::Button); InputCommon::Polling::DeviceType::Button);
}); });
@ -401,15 +403,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
connect(poll_timer.get(), &QTimer::timeout, [this] { connect(poll_timer.get(), &QTimer::timeout, [this] {
Common::ParamPackage params; Common::ParamPackage params;
if (InputCommon::GetGCButtons()->IsPolling()) { if (input_subsystem->GetGCButtons()->IsPolling()) {
params = InputCommon::GetGCButtons()->GetNextInput(); params = input_subsystem->GetGCButtons()->GetNextInput();
if (params.Has("engine")) { if (params.Has("engine")) {
SetPollingResult(params, false); SetPollingResult(params, false);
return; return;
} }
} }
if (InputCommon::GetGCAnalogs()->IsPolling()) { if (input_subsystem->GetGCAnalogs()->IsPolling()) {
params = InputCommon::GetGCAnalogs()->GetNextInput(); params = input_subsystem->GetGCAnalogs()->GetNextInput();
if (params.Has("engine")) { if (params.Has("engine")) {
SetPollingResult(params, false); SetPollingResult(params, false);
return; return;
@ -514,7 +516,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
} }
void ConfigureInputPlayer::UpdateInputDevices() { void ConfigureInputPlayer::UpdateInputDevices() {
input_devices = InputCommon::GetInputDevices(); input_devices = input_subsystem->GetInputDevices();
ui->comboDevices->clear(); ui->comboDevices->clear();
for (auto device : input_devices) { for (auto device : input_devices) {
ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
@ -642,8 +644,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
return; return;
} }
const auto& device = input_devices[ui->comboDevices->currentIndex()]; const auto& device = input_devices[ui->comboDevices->currentIndex()];
auto button_mapping = InputCommon::GetButtonMappingForDevice(device); auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
auto analog_mapping = InputCommon::GetAnalogMappingForDevice(device); auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
for (int i = 0; i < buttons_param.size(); ++i) { for (int i = 0; i < buttons_param.size(); ++i) {
buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
} }
@ -666,7 +668,7 @@ void ConfigureInputPlayer::HandleClick(
input_setter = new_input_setter; input_setter = new_input_setter;
device_pollers = InputCommon::Polling::GetPollers(type); device_pollers = input_subsystem->GetPollers(type);
for (auto& poller : device_pollers) { for (auto& poller : device_pollers) {
poller->Start(); poller->Start();
@ -676,9 +678,9 @@ void ConfigureInputPlayer::HandleClick(
QWidget::grabKeyboard(); QWidget::grabKeyboard();
if (type == InputCommon::Polling::DeviceType::Button) { if (type == InputCommon::Polling::DeviceType::Button) {
InputCommon::GetGCButtons()->BeginConfiguration(); input_subsystem->GetGCButtons()->BeginConfiguration();
} else { } else {
InputCommon::GetGCAnalogs()->BeginConfiguration(); input_subsystem->GetGCAnalogs()->BeginConfiguration();
} }
timeout_timer->start(2500); // Cancel after 2.5 seconds timeout_timer->start(2500); // Cancel after 2.5 seconds
@ -695,8 +697,8 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
QWidget::releaseMouse(); QWidget::releaseMouse();
QWidget::releaseKeyboard(); QWidget::releaseKeyboard();
InputCommon::GetGCButtons()->EndConfiguration(); input_subsystem->GetGCButtons()->EndConfiguration();
InputCommon::GetGCAnalogs()->EndConfiguration(); input_subsystem->GetGCAnalogs()->EndConfiguration();
if (!abort) { if (!abort) {
(*input_setter)(params); (*input_setter)(params);

View File

@ -10,12 +10,11 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <QDialog> #include <QWidget>
#include "common/param_package.h" #include "common/param_package.h"
#include "core/settings.h" #include "core/settings.h"
#include "ui_configure_input.h" #include "ui_configure_input.h"
#include "yuzu/uisettings.h"
class QCheckBox; class QCheckBox;
class QKeyEvent; class QKeyEvent;
@ -27,6 +26,10 @@ class QString;
class QTimer; class QTimer;
class QWidget; class QWidget;
namespace InputCommon {
class InputSubsystem;
}
namespace InputCommon::Polling { namespace InputCommon::Polling {
class DevicePoller; class DevicePoller;
enum class DeviceType; enum class DeviceType;
@ -41,6 +44,7 @@ class ConfigureInputPlayer : public QWidget {
public: public:
explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
InputCommon::InputSubsystem* input_subsystem_,
bool debug = false); bool debug = false);
~ConfigureInputPlayer() override; ~ConfigureInputPlayer() override;
@ -111,6 +115,8 @@ private:
std::size_t player_index; std::size_t player_index;
bool debug; bool debug;
InputCommon::InputSubsystem* input_subsystem;
std::unique_ptr<QTimer> timeout_timer; std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer; std::unique_ptr<QTimer> poll_timer;

View File

@ -76,8 +76,10 @@ static QString ButtonToText(const Common::ParamPackage& param) {
return QObject::tr("[unknown]"); return QObject::tr("[unknown]");
} }
ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent) ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent,
: QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), InputCommon::InputSubsystem* input_subsystem_)
: QDialog(parent),
ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), input_subsystem{input_subsystem_},
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this); ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
@ -209,7 +211,7 @@ void ConfigureMouseAdvanced::HandleClick(
input_setter = new_input_setter; input_setter = new_input_setter;
device_pollers = InputCommon::Polling::GetPollers(type); device_pollers = input_subsystem->GetPollers(type);
for (auto& poller : device_pollers) { for (auto& poller : device_pollers) {
poller->Start(); poller->Start();

View File

@ -8,12 +8,14 @@
#include <optional> #include <optional>
#include <QDialog> #include <QDialog>
#include "core/settings.h"
class QCheckBox; class QCheckBox;
class QPushButton; class QPushButton;
class QTimer; class QTimer;
namespace InputCommon {
class InputSubsystem;
}
namespace Ui { namespace Ui {
class ConfigureMouseAdvanced; class ConfigureMouseAdvanced;
} }
@ -22,7 +24,7 @@ class ConfigureMouseAdvanced : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit ConfigureMouseAdvanced(QWidget* parent); explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
~ConfigureMouseAdvanced() override; ~ConfigureMouseAdvanced() override;
void ApplyConfiguration(); void ApplyConfiguration();
@ -57,6 +59,8 @@ private:
std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
InputCommon::InputSubsystem* input_subsystem;
/// This will be the the setting function when an input is awaiting configuration. /// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;

View File

@ -94,6 +94,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "core/settings.h" #include "core/settings.h"
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
#include "input_common/main.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/shader_notify.h" #include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h" #include "yuzu/about_dialog.h"
@ -186,9 +187,9 @@ static void InitializeLogging() {
} }
GMainWindow::GMainWindow() GMainWindow::GMainWindow()
: config(new Config()), emu_thread(nullptr), : input_subsystem{std::make_unique<InputCommon::InputSubsystem>()},
vfs(std::make_shared<FileSys::RealVfsFilesystem>()), config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
provider(std::make_unique<FileSys::ManualContentProvider>()) { provider{std::make_unique<FileSys::ManualContentProvider>()} {
InitializeLogging(); InitializeLogging();
LoadTranslation(); LoadTranslation();
@ -473,7 +474,7 @@ 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);
#endif #endif
render_window = new GRenderWindow(this, emu_thread.get()); render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem.get());
render_window->hide(); render_window->hide();
game_list = new GameList(vfs, provider.get(), this); game_list = new GameList(vfs, provider.get(), this);
@ -2213,7 +2214,7 @@ void GMainWindow::OnConfigure() {
const auto old_theme = UISettings::values.theme; const auto old_theme = UISettings::values.theme;
const bool old_discord_presence = UISettings::values.enable_discord_presence; const bool old_discord_presence = UISettings::values.enable_discord_presence;
ConfigureDialog configure_dialog(this, hotkey_registry); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
&GMainWindow::OnLanguageChanged); &GMainWindow::OnLanguageChanged);

View File

@ -40,12 +40,20 @@ namespace Core::Frontend {
struct SoftwareKeyboardParameters; struct SoftwareKeyboardParameters;
} // namespace Core::Frontend } // namespace Core::Frontend
namespace DiscordRPC {
class DiscordInterface;
}
namespace FileSys { namespace FileSys {
class ContentProvider; class ContentProvider;
class ManualContentProvider; class ManualContentProvider;
class VfsFilesystem; class VfsFilesystem;
} // namespace FileSys } // namespace FileSys
namespace InputCommon {
class InputSubsystem;
}
enum class EmulatedDirectoryTarget { enum class EmulatedDirectoryTarget {
NAND, NAND,
SDMC, SDMC,
@ -62,10 +70,6 @@ enum class ReinitializeKeyBehavior {
Warning, Warning,
}; };
namespace DiscordRPC {
class DiscordInterface;
}
class GMainWindow : public QMainWindow { class GMainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
@ -86,8 +90,6 @@ public:
GMainWindow(); GMainWindow();
~GMainWindow() override; ~GMainWindow() override;
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
bool DropAction(QDropEvent* event); bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event); void AcceptDropEvent(QDropEvent* event);
@ -255,6 +257,9 @@ private:
Ui::MainWindow ui; Ui::MainWindow ui;
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
std::unique_ptr<InputCommon::InputSubsystem> input_subsystem;
GRenderWindow* render_window; GRenderWindow* render_window;
GameList* game_list; GameList* game_list;
LoadingScreen* loading_screen; LoadingScreen* loading_screen;

View File

@ -13,23 +13,25 @@
#include "input_common/sdl/sdl.h" #include "input_common/sdl/sdl.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h"
EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen) : system{system} { EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen,
InputCommon::InputSubsystem* input_subsystem_)
: system{system}, input_subsystem{input_subsystem_} {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
exit(1); exit(1);
} }
InputCommon::Init(); input_subsystem->Initialize();
SDL_SetMainReady(); SDL_SetMainReady();
} }
EmuWindow_SDL2::~EmuWindow_SDL2() { EmuWindow_SDL2::~EmuWindow_SDL2() {
InputCommon::Shutdown(); input_subsystem->Shutdown();
SDL_Quit(); SDL_Quit();
} }
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
InputCommon::GetMotionEmu()->Tilt(x, y); input_subsystem->GetMotionEmu()->Tilt(x, y);
} }
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
@ -41,9 +43,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
} }
} else if (button == SDL_BUTTON_RIGHT) { } else if (button == SDL_BUTTON_RIGHT) {
if (state == SDL_PRESSED) { if (state == SDL_PRESSED) {
InputCommon::GetMotionEmu()->BeginTilt(x, y); input_subsystem->GetMotionEmu()->BeginTilt(x, y);
} else { } else {
InputCommon::GetMotionEmu()->EndTilt(); input_subsystem->GetMotionEmu()->EndTilt();
} }
} }
} }
@ -79,9 +81,9 @@ void EmuWindow_SDL2::OnFingerUp() {
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) { if (state == SDL_PRESSED) {
InputCommon::GetKeyboard()->PressKey(key); input_subsystem->GetKeyboard()->PressKey(key);
} else if (state == SDL_RELEASED) { } else if (state == SDL_RELEASED) {
InputCommon::GetKeyboard()->ReleaseKey(key); input_subsystem->GetKeyboard()->ReleaseKey(key);
} }
} }

View File

@ -14,9 +14,14 @@ namespace Core {
class System; class System;
} }
namespace InputCommon {
class InputSubsystem;
}
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public: public:
explicit EmuWindow_SDL2(Core::System& system, bool fullscreen); explicit EmuWindow_SDL2(Core::System& system, bool fullscreen,
InputCommon::InputSubsystem* input_subsystem);
~EmuWindow_SDL2(); ~EmuWindow_SDL2();
/// Polls window events /// Polls window events
@ -76,4 +81,7 @@ protected:
/// Keeps track of how often to update the title bar during gameplay /// Keeps track of how often to update the title bar during gameplay
u32 last_time = 0; u32 last_time = 0;
/// Input subsystem to use with this window.
InputCommon::InputSubsystem* input_subsystem;
}; };

View File

@ -87,8 +87,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
return unsupported_ext.empty(); return unsupported_ext.empty();
} }
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen) EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen,
: EmuWindow_SDL2{system, fullscreen} { InputCommon::InputSubsystem* input_subsystem)
: EmuWindow_SDL2{system, fullscreen, input_subsystem} {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);

View File

@ -8,9 +8,14 @@
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h"
namespace InputCommon {
class InputSubsystem;
}
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
public: public:
explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen); explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen,
InputCommon::InputSubsystem* input_subsystem);
~EmuWindow_SDL2_GL(); ~EmuWindow_SDL2_GL();
void Present() override; void Present() override;

View File

@ -19,8 +19,9 @@
#include <SDL.h> #include <SDL.h>
#include <SDL_syswm.h> #include <SDL_syswm.h>
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen) EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen,
: EmuWindow_SDL2{system, fullscreen} { InputCommon::InputSubsystem* input_subsystem)
: EmuWindow_SDL2{system, fullscreen, input_subsystem} {
const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc); Common::g_scm_branch, Common::g_scm_desc);
render_window = render_window =

View File

@ -13,9 +13,14 @@ namespace Core {
class System; class System;
} }
namespace InputCommon {
class InputSubsystem;
}
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
public: public:
explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen); explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen,
InputCommon::InputSubsystem* input_subsystem);
~EmuWindow_SDL2_VK(); ~EmuWindow_SDL2_VK();
void Present() override; void Present() override;

View File

@ -23,12 +23,14 @@
#include "common/telemetry.h" #include "common/telemetry.h"
#include "core/core.h" #include "core/core.h"
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h" #include "core/gdbstub/gdbstub.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/settings.h" #include "core/settings.h"
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
#include "input_common/main.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "yuzu_cmd/config.h" #include "yuzu_cmd/config.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h"
@ -37,8 +39,6 @@
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
#endif #endif
#include "core/file_sys/registered_cache.h"
#ifdef _WIN32 #ifdef _WIN32
// windows.h needs to be included before shellapi.h // windows.h needs to be included before shellapi.h
#include <windows.h> #include <windows.h>
@ -179,15 +179,16 @@ int main(int argc, char** argv) {
Settings::Apply(); Settings::Apply();
Core::System& system{Core::System::GetInstance()}; Core::System& system{Core::System::GetInstance()};
InputCommon::InputSubsystem input_subsystem;
std::unique_ptr<EmuWindow_SDL2> emu_window; std::unique_ptr<EmuWindow_SDL2> emu_window;
switch (Settings::values.renderer_backend.GetValue()) { switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL: case Settings::RendererBackend::OpenGL:
emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen); emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, &input_subsystem);
break; break;
case Settings::RendererBackend::Vulkan: case Settings::RendererBackend::Vulkan:
#ifdef HAS_VULKAN #ifdef HAS_VULKAN
emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen); emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, &input_subsystem);
break; break;
#else #else
LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!"); LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!");

View File

@ -13,7 +13,6 @@
#include <glad/glad.h> #include <glad/glad.h>
#include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "core/settings.h" #include "core/settings.h"
@ -53,7 +52,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
exit(1); exit(1);
} }
InputCommon::Init(); input_subsystem->Initialize();
SDL_SetMainReady(); SDL_SetMainReady();
@ -105,7 +104,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
} }
EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() {
InputCommon::Shutdown(); input_subsystem->Shutdown();
SDL_GL_DeleteContext(gl_context); SDL_GL_DeleteContext(gl_context);
SDL_Quit(); SDL_Quit();
} }

View File

@ -8,6 +8,10 @@
struct SDL_Window; struct SDL_Window;
namespace InputCommon {
class InputSubsystem;
}
class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow { class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow {
public: public:
explicit EmuWindow_SDL2_Hide(); explicit EmuWindow_SDL2_Hide();
@ -25,6 +29,8 @@ private:
/// Whether the GPU and driver supports the OpenGL extension required /// Whether the GPU and driver supports the OpenGL extension required
bool SupportsRequiredGLExtensions(); bool SupportsRequiredGLExtensions();
std::unique_ptr<InputCommon::InputSubsystem> input_subsystem;
/// Internal SDL2 render window /// Internal SDL2 render window
SDL_Window* render_window; SDL_Window* render_window;