summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_common/main.cpp250
-rw-r--r--src/input_common/main.h130
-rw-r--r--src/yuzu/bootmanager.cpp23
-rw-r--r--src/yuzu/bootmanager.h8
-rw-r--r--src/yuzu/configuration/configure_debug_controller.cpp5
-rw-r--r--src/yuzu/configuration/configure_debug_controller.h7
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp5
-rw-r--r--src/yuzu/configuration/configure_dialog.h7
-rw-r--r--src/yuzu/configuration/configure_input.cpp32
-rw-r--r--src/yuzu/configuration/configure_input.h9
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp34
-rw-r--r--src/yuzu/configuration/configure_input_player.h10
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h10
-rw-r--r--src/yuzu/main.cpp11
-rw-r--r--src/yuzu/main.h17
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp18
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h10
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp5
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h7
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp5
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h7
-rw-r--r--src/yuzu_cmd/yuzu.cpp9
-rw-r--r--src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp5
-rw-r--r--src/yuzu_tester/emu_window/emu_window_sdl2_hide.h6
25 files changed, 396 insertions, 242 deletions
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 8e67a7437..57e7a25fe 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -18,66 +18,166 @@
18 18
19namespace InputCommon { 19namespace InputCommon {
20 20
21static std::shared_ptr<Keyboard> keyboard; 21struct InputSubsystem::Impl {
22static std::shared_ptr<MotionEmu> motion_emu; 22 void Initialize() {
23 auto gcadapter = std::make_shared<GCAdapter::Adapter>();
24 gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
25 Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
26 gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
27 Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
28
29 keyboard = std::make_shared<Keyboard>();
30 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
31 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
32 std::make_shared<AnalogFromButton>());
33 motion_emu = std::make_shared<MotionEmu>();
34 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
35
23#ifdef HAVE_SDL2 36#ifdef HAVE_SDL2
24static std::unique_ptr<SDL::State> sdl; 37 sdl = SDL::Init();
25#endif 38#endif
26static std::unique_ptr<CemuhookUDP::State> udp;
27static std::shared_ptr<GCButtonFactory> gcbuttons;
28static std::shared_ptr<GCAnalogFactory> gcanalog;
29
30void Init() {
31 auto gcadapter = std::make_shared<GCAdapter::Adapter>();
32 gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
33 Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
34 gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
35 Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
36
37 keyboard = std::make_shared<Keyboard>();
38 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
39 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
40 std::make_shared<AnalogFromButton>());
41 motion_emu = std::make_shared<MotionEmu>();
42 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
43 39
40 udp = CemuhookUDP::Init();
41 }
42
43 void Shutdown() {
44 Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
45 keyboard.reset();
46 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
47 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
48 motion_emu.reset();
44#ifdef HAVE_SDL2 49#ifdef HAVE_SDL2
45 sdl = SDL::Init(); 50 sdl.reset();
46#endif 51#endif
47 udp = CemuhookUDP::Init(); 52 udp.reset();
48} 53 Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
54 Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
55
56 gcbuttons.reset();
57 gcanalog.reset();
58 }
59
60 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
61 std::vector<Common::ParamPackage> devices = {
62 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
63 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
64 };
65#ifdef HAVE_SDL2
66 auto sdl_devices = sdl->GetInputDevices();
67 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
68#endif
69 auto udp_devices = udp->GetInputDevices();
70 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
71 return devices;
72 }
73
74 [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
75 const Common::ParamPackage& params) const {
76 if (!params.Has("class") || params.Get("class", "") == "any") {
77 return {};
78 }
79 if (params.Get("class", "") == "key") {
80 // TODO consider returning the SDL key codes for the default keybindings
81 return {};
82 }
83#ifdef HAVE_SDL2
84 if (params.Get("class", "") == "sdl") {
85 return sdl->GetAnalogMappingForDevice(params);
86 }
87#endif
88 return {};
89 }
90
91 [[nodiscard]] ButtonMapping GetButtonMappingForDevice(
92 const Common::ParamPackage& params) const {
93 if (!params.Has("class") || params.Get("class", "") == "any") {
94 return {};
95 }
96 if (params.Get("class", "") == "key") {
97 // TODO consider returning the SDL key codes for the default keybindings
98 return {};
99 }
100#ifdef HAVE_SDL2
101 if (params.Get("class", "") == "sdl") {
102 return sdl->GetButtonMappingForDevice(params);
103 }
104#endif
105 return {};
106 }
49 107
50void Shutdown() { 108 std::shared_ptr<Keyboard> keyboard;
51 Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); 109 std::shared_ptr<MotionEmu> motion_emu;
52 keyboard.reset();
53 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
54 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
55 motion_emu.reset();
56#ifdef HAVE_SDL2 110#ifdef HAVE_SDL2
57 sdl.reset(); 111 std::unique_ptr<SDL::State> sdl;
58#endif 112#endif
59 udp.reset(); 113 std::unique_ptr<CemuhookUDP::State> udp;
60 Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); 114 std::shared_ptr<GCButtonFactory> gcbuttons;
61 Input::UnregisterFactory<Input::AnalogDevice>("gcpad"); 115 std::shared_ptr<GCAnalogFactory> gcanalog;
116};
117
118InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
119
120InputSubsystem::~InputSubsystem() = default;
121
122void InputSubsystem::Initialize() {
123 impl->Initialize();
124}
125
126void InputSubsystem::Shutdown() {
127 impl->Shutdown();
128}
129
130Keyboard* InputSubsystem::GetKeyboard() {
131 return impl->keyboard.get();
132}
133
134const Keyboard* InputSubsystem::GetKeyboard() const {
135 return impl->keyboard.get();
136}
137
138MotionEmu* InputSubsystem::GetMotionEmu() {
139 return impl->motion_emu.get();
140}
141
142const MotionEmu* InputSubsystem::GetMotionEmu() const {
143 return impl->motion_emu.get();
144}
145
146std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
147 return impl->GetInputDevices();
148}
149
150AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const {
151 return impl->GetAnalogMappingForDevice(device);
152}
62 153
63 gcbuttons.reset(); 154ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const {
64 gcanalog.reset(); 155 return impl->GetButtonMappingForDevice(device);
65} 156}
66 157
67Keyboard* GetKeyboard() { 158GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
68 return keyboard.get(); 159 return impl->gcanalog.get();
69} 160}
70 161
71MotionEmu* GetMotionEmu() { 162const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const {
72 return motion_emu.get(); 163 return impl->gcanalog.get();
73} 164}
74 165
75GCButtonFactory* GetGCButtons() { 166GCButtonFactory* InputSubsystem::GetGCButtons() {
76 return gcbuttons.get(); 167 return impl->gcbuttons.get();
77} 168}
78 169
79GCAnalogFactory* GetGCAnalogs() { 170const GCButtonFactory* InputSubsystem::GetGCButtons() const {
80 return gcanalog.get(); 171 return impl->gcbuttons.get();
172}
173
174std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
175 Polling::DeviceType type) const {
176#ifdef HAVE_SDL2
177 return impl->sdl->GetPollers(type);
178#else
179 return {};
180#endif
81} 181}
82 182
83std::string GenerateKeyboardParam(int key_code) { 183std::string GenerateKeyboardParam(int key_code) {
@@ -101,68 +201,4 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
101 }; 201 };
102 return circle_pad_param.Serialize(); 202 return circle_pad_param.Serialize();
103} 203}
104
105std::vector<Common::ParamPackage> GetInputDevices() {
106 std::vector<Common::ParamPackage> devices = {
107 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
108 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
109 };
110#ifdef HAVE_SDL2
111 auto sdl_devices = sdl->GetInputDevices();
112 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
113#endif
114 auto udp_devices = udp->GetInputDevices();
115 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
116 return devices;
117}
118
119std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
120 const Common::ParamPackage& params) {
121 std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings;
122 if (!params.Has("class") || params.Get("class", "") == "any") {
123 return {};
124 }
125 if (params.Get("class", "") == "key") {
126 // TODO consider returning the SDL key codes for the default keybindings
127 return {};
128 }
129#ifdef HAVE_SDL2
130 if (params.Get("class", "") == "sdl") {
131 return sdl->GetButtonMappingForDevice(params);
132 }
133#endif
134 return {};
135}
136
137std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
138 const Common::ParamPackage& params) {
139 std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings;
140 if (!params.Has("class") || params.Get("class", "") == "any") {
141 return {};
142 }
143 if (params.Get("class", "") == "key") {
144 // TODO consider returning the SDL key codes for the default keybindings
145 return {};
146 }
147#ifdef HAVE_SDL2
148 if (params.Get("class", "") == "sdl") {
149 return sdl->GetAnalogMappingForDevice(params);
150 }
151#endif
152 return {};
153}
154
155namespace Polling {
156
157std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
158 std::vector<std::unique_ptr<DevicePoller>> pollers;
159
160#ifdef HAVE_SDL2
161 pollers = sdl->GetPollers(type);
162#endif
163
164 return pollers;
165}
166
167} // namespace Polling
168} // namespace InputCommon 204} // namespace InputCommon
diff --git a/src/input_common/main.h b/src/input_common/main.h
index e706c3750..f66308163 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -16,52 +16,6 @@ class ParamPackage;
16} 16}
17 17
18namespace InputCommon { 18namespace InputCommon {
19
20/// Initializes and registers all built-in input device factories.
21void Init();
22
23/// Deregisters all built-in input device factories and shuts them down.
24void Shutdown();
25
26class Keyboard;
27
28/// Gets the keyboard button device factory.
29Keyboard* GetKeyboard();
30
31class MotionEmu;
32
33/// Gets the motion emulation factory.
34MotionEmu* GetMotionEmu();
35
36GCButtonFactory* GetGCButtons();
37
38GCAnalogFactory* GetGCAnalogs();
39
40/// Generates a serialized param package for creating a keyboard button device
41std::string GenerateKeyboardParam(int key_code);
42
43/// Generates a serialized param package for creating an analog device taking input from keyboard
44std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
45 int key_modifier, float modifier_scale);
46
47/**
48 * Return a list of available input devices that this Factory can create a new device with.
49 * Each returned Parampackage should have a `display` field used for display, a class field for
50 * backends to determine if this backend is meant to service the request and any other information
51 * needed to identify this in the backend later.
52 */
53std::vector<Common::ParamPackage> GetInputDevices();
54
55/**
56 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
57 * mapping for the device. This is currently only implemented for the sdl backend devices.
58 */
59using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
60using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
61
62ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
63AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
64
65namespace Polling { 19namespace Polling {
66 20
67enum class DeviceType { Button, AnalogPreferred }; 21enum class DeviceType { Button, AnalogPreferred };
@@ -90,4 +44,88 @@ public:
90// Get all DevicePoller from all backends for a specific device type 44// Get all DevicePoller from all backends for a specific device type
91std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type); 45std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
92} // namespace Polling 46} // namespace Polling
47
48class GCAnalogFactory;
49class GCButtonFactory;
50class Keyboard;
51class MotionEmu;
52
53/**
54 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
55 * mapping for the device. This is currently only implemented for the SDL backend devices.
56 */
57using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
58using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
59
60class InputSubsystem {
61public:
62 explicit InputSubsystem();
63 ~InputSubsystem();
64
65 InputSubsystem(const InputSubsystem&) = delete;
66 InputSubsystem& operator=(const InputSubsystem&) = delete;
67
68 InputSubsystem(InputSubsystem&&) = delete;
69 InputSubsystem& operator=(InputSubsystem&&) = delete;
70
71 /// Initializes and registers all built-in input device factories.
72 void Initialize();
73
74 /// Unregisters all built-in input device factories and shuts them down.
75 void Shutdown();
76
77 /// Retrieves the underlying keyboard device.
78 [[nodiscard]] Keyboard* GetKeyboard();
79
80 /// Retrieves the underlying keyboard device.
81 [[nodiscard]] const Keyboard* GetKeyboard() const;
82
83 /// Retrieves the underlying motion emulation factory.
84 [[nodiscard]] MotionEmu* GetMotionEmu();
85
86 /// Retrieves the underlying motion emulation factory.
87 [[nodiscard]] const MotionEmu* GetMotionEmu() const;
88
89 /**
90 * Returns all available input devices that this Factory can create a new device with.
91 * Each returned ParamPackage should have a `display` field used for display, a class field for
92 * backends to determine if this backend is meant to service the request and any other
93 * information needed to identify this in the backend later.
94 */
95 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
96
97 /// Retrieves the analog mappings for the given device.
98 [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& device) const;
99
100 /// Retrieves the button mappings for the given device.
101 [[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
102
103 /// Retrieves the underlying GameCube analog handler.
104 [[nodiscard]] GCAnalogFactory* GetGCAnalogs();
105
106 /// Retrieves the underlying GameCube analog handler.
107 [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const;
108
109 /// Retrieves the underlying GameCube button handler.
110 [[nodiscard]] GCButtonFactory* GetGCButtons();
111
112 /// Retrieves the underlying GameCube button handler.
113 [[nodiscard]] const GCButtonFactory* GetGCButtons() const;
114
115 /// Get all DevicePoller from all backends for a specific device type
116 [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
117 Polling::DeviceType type) const;
118
119private:
120 struct Impl;
121 std::unique_ptr<Impl> impl;
122};
123
124/// Generates a serialized param package for creating a keyboard button device
125std::string GenerateKeyboardParam(int key_code);
126
127/// Generates a serialized param package for creating an analog device taking input from keyboard
128std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
129 int key_modifier, float modifier_scale);
130
93} // namespace InputCommon 131} // namespace InputCommon
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 8fc322b30..f1b428bde 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -304,8 +304,9 @@ static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow*
304 return wsi; 304 return wsi;
305} 305}
306 306
307GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_) 307GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
308 : QWidget(parent_), emu_thread(emu_thread_) { 308 InputCommon::InputSubsystem* input_subsystem_)
309 : QWidget(parent), emu_thread(emu_thread_), input_subsystem{input_subsystem_} {
309 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") 310 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
310 .arg(QString::fromUtf8(Common::g_build_name), 311 .arg(QString::fromUtf8(Common::g_build_name),
311 QString::fromUtf8(Common::g_scm_branch), 312 QString::fromUtf8(Common::g_scm_branch),
@@ -314,15 +315,15 @@ GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_)
314 auto layout = new QHBoxLayout(this); 315 auto layout = new QHBoxLayout(this);
315 layout->setMargin(0); 316 layout->setMargin(0);
316 setLayout(layout); 317 setLayout(layout);
317 InputCommon::Init(); 318 input_subsystem->Initialize();
318 319
319 this->setMouseTracking(true); 320 this->setMouseTracking(true);
320 321
321 connect(this, &GRenderWindow::FirstFrameDisplayed, parent_, &GMainWindow::OnLoadComplete); 322 connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
322} 323}
323 324
324GRenderWindow::~GRenderWindow() { 325GRenderWindow::~GRenderWindow() {
325 InputCommon::Shutdown(); 326 input_subsystem->Shutdown();
326} 327}
327 328
328void GRenderWindow::PollEvents() { 329void GRenderWindow::PollEvents() {
@@ -391,11 +392,11 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
391} 392}
392 393
393void GRenderWindow::keyPressEvent(QKeyEvent* event) { 394void GRenderWindow::keyPressEvent(QKeyEvent* event) {
394 InputCommon::GetKeyboard()->PressKey(event->key()); 395 input_subsystem->GetKeyboard()->PressKey(event->key());
395} 396}
396 397
397void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { 398void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
398 InputCommon::GetKeyboard()->ReleaseKey(event->key()); 399 input_subsystem->GetKeyboard()->ReleaseKey(event->key());
399} 400}
400 401
401void GRenderWindow::mousePressEvent(QMouseEvent* event) { 402void GRenderWindow::mousePressEvent(QMouseEvent* event) {
@@ -409,7 +410,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
409 const auto [x, y] = ScaleTouch(pos); 410 const auto [x, y] = ScaleTouch(pos);
410 this->TouchPressed(x, y); 411 this->TouchPressed(x, y);
411 } else if (event->button() == Qt::RightButton) { 412 } else if (event->button() == Qt::RightButton) {
412 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); 413 input_subsystem->GetMotionEmu()->BeginTilt(pos.x(), pos.y());
413 } 414 }
414 QWidget::mousePressEvent(event); 415 QWidget::mousePressEvent(event);
415} 416}
@@ -423,7 +424,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
423 auto pos = event->pos(); 424 auto pos = event->pos();
424 const auto [x, y] = ScaleTouch(pos); 425 const auto [x, y] = ScaleTouch(pos);
425 this->TouchMoved(x, y); 426 this->TouchMoved(x, y);
426 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); 427 input_subsystem->GetMotionEmu()->Tilt(pos.x(), pos.y());
427 QWidget::mouseMoveEvent(event); 428 QWidget::mouseMoveEvent(event);
428} 429}
429 430
@@ -436,7 +437,7 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
436 if (event->button() == Qt::LeftButton) { 437 if (event->button() == Qt::LeftButton) {
437 this->TouchReleased(); 438 this->TouchReleased();
438 } else if (event->button() == Qt::RightButton) { 439 } else if (event->button() == Qt::RightButton) {
439 InputCommon::GetMotionEmu()->EndTilt(); 440 input_subsystem->GetMotionEmu()->EndTilt();
440 } 441 }
441} 442}
442 443
@@ -485,7 +486,7 @@ bool GRenderWindow::event(QEvent* event) {
485 486
486void GRenderWindow::focusOutEvent(QFocusEvent* event) { 487void GRenderWindow::focusOutEvent(QFocusEvent* event) {
487 QWidget::focusOutEvent(event); 488 QWidget::focusOutEvent(event);
488 InputCommon::GetKeyboard()->ReleaseAllKeys(); 489 input_subsystem->GetKeyboard()->ReleaseAllKeys();
489} 490}
490 491
491void GRenderWindow::resizeEvent(QResizeEvent* event) { 492void GRenderWindow::resizeEvent(QResizeEvent* event) {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 6c59b4d5c..ecb3b8135 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -23,6 +23,10 @@ class QKeyEvent;
23class QTouchEvent; 23class QTouchEvent;
24class QStringList; 24class QStringList;
25 25
26namespace InputCommon {
27class InputSubsystem;
28}
29
26namespace VideoCore { 30namespace VideoCore {
27enum class LoadCallbackStage; 31enum class LoadCallbackStage;
28} 32}
@@ -121,7 +125,8 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
121 Q_OBJECT 125 Q_OBJECT
122 126
123public: 127public:
124 GRenderWindow(GMainWindow* parent, EmuThread* emu_thread); 128 explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
129 InputCommon::InputSubsystem* input_subsystem_);
125 ~GRenderWindow() override; 130 ~GRenderWindow() override;
126 131
127 // EmuWindow implementation. 132 // EmuWindow implementation.
@@ -183,6 +188,7 @@ private:
183 QStringList GetUnsupportedGLExtensions() const; 188 QStringList GetUnsupportedGLExtensions() const;
184 189
185 EmuThread* emu_thread; 190 EmuThread* emu_thread;
191 InputCommon::InputSubsystem* input_subsystem;
186 192
187 // Main context that will be shared with all other contexts that are requested. 193 // Main context that will be shared with all other contexts that are requested.
188 // If this is used in a shared context setting, then this should not be used directly, but 194 // If this is used in a shared context setting, then this should not be used directly, but
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
index 72885b4b8..0097c9a29 100644
--- a/src/yuzu/configuration/configure_debug_controller.cpp
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -5,9 +5,10 @@
5#include "ui_configure_debug_controller.h" 5#include "ui_configure_debug_controller.h"
6#include "yuzu/configuration/configure_debug_controller.h" 6#include "yuzu/configuration/configure_debug_controller.h"
7 7
8ConfigureDebugController::ConfigureDebugController(QWidget* parent) 8ConfigureDebugController::ConfigureDebugController(QWidget* parent,
9 InputCommon::InputSubsystem* input_subsystem)
9 : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()), 10 : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
10 debug_controller(new ConfigureInputPlayer(this, 9, nullptr, true)) { 11 debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, true)) {
11 ui->setupUi(this); 12 ui->setupUi(this);
12 13
13 ui->controllerLayout->addWidget(debug_controller); 14 ui->controllerLayout->addWidget(debug_controller);
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
index 36475bbea..34dcf705f 100644
--- a/src/yuzu/configuration/configure_debug_controller.h
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -10,6 +10,10 @@
10 10
11class QPushButton; 11class QPushButton;
12 12
13namespace InputCommon {
14class InputSubsystem;
15}
16
13namespace Ui { 17namespace Ui {
14class ConfigureDebugController; 18class ConfigureDebugController;
15} 19}
@@ -18,7 +22,8 @@ class ConfigureDebugController : public QDialog {
18 Q_OBJECT 22 Q_OBJECT
19 23
20public: 24public:
21 explicit ConfigureDebugController(QWidget* parent); 25 explicit ConfigureDebugController(QWidget* parent,
26 InputCommon::InputSubsystem* input_subsystem);
22 ~ConfigureDebugController() override; 27 ~ConfigureDebugController() override;
23 28
24 void ApplyConfiguration(); 29 void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 857577591..8186929a6 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -12,7 +12,8 @@
12#include "yuzu/configuration/configure_input_player.h" 12#include "yuzu/configuration/configure_input_player.h"
13#include "yuzu/hotkeys.h" 13#include "yuzu/hotkeys.h"
14 14
15ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) 15ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
16 InputCommon::InputSubsystem* input_subsystem)
16 : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { 17 : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
17 Settings::configuring_global = true; 18 Settings::configuring_global = true;
18 19
@@ -20,6 +21,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
20 ui->hotkeysTab->Populate(registry); 21 ui->hotkeysTab->Populate(registry);
21 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 22 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
22 23
24 ui->inputTab->Initialize(input_subsystem);
25
23 SetConfiguration(); 26 SetConfiguration();
24 PopulateSelectionList(); 27 PopulateSelectionList();
25 28
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 4289bc225..570c3b941 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -9,6 +9,10 @@
9 9
10class HotkeyRegistry; 10class HotkeyRegistry;
11 11
12namespace InputCommon {
13class InputSubsystem;
14}
15
12namespace Ui { 16namespace Ui {
13class ConfigureDialog; 17class ConfigureDialog;
14} 18}
@@ -17,7 +21,8 @@ class ConfigureDialog : public QDialog {
17 Q_OBJECT 21 Q_OBJECT
18 22
19public: 23public:
20 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry); 24 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
25 InputCommon::InputSubsystem* input_subsystem);
21 ~ConfigureDialog() override; 26 ~ConfigureDialog() override;
22 27
23 void ApplyConfiguration(); 28 void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 0d004c2f7..5223eed1d 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -65,16 +65,20 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
65ConfigureInput::ConfigureInput(QWidget* parent) 65ConfigureInput::ConfigureInput(QWidget* parent)
66 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { 66 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
67 ui->setupUi(this); 67 ui->setupUi(this);
68}
69
70ConfigureInput::~ConfigureInput() = default;
68 71
72void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
69 player_controllers = { 73 player_controllers = {
70 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings), 74 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
71 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings), 75 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
72 new ConfigureInputPlayer(this, 2, ui->consoleInputSettings), 76 new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem),
73 new ConfigureInputPlayer(this, 3, ui->consoleInputSettings), 77 new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem),
74 new ConfigureInputPlayer(this, 4, ui->consoleInputSettings), 78 new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem),
75 new ConfigureInputPlayer(this, 5, ui->consoleInputSettings), 79 new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem),
76 new ConfigureInputPlayer(this, 6, ui->consoleInputSettings), 80 new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem),
77 new ConfigureInputPlayer(this, 7, ui->consoleInputSettings), 81 new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem),
78 }; 82 };
79 83
80 player_tabs = { 84 player_tabs = {
@@ -115,10 +119,12 @@ ConfigureInput::ConfigureInput(QWidget* parent)
115 advanced = new ConfigureInputAdvanced(this); 119 advanced = new ConfigureInputAdvanced(this);
116 ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); 120 ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
117 ui->tabAdvanced->layout()->addWidget(advanced); 121 ui->tabAdvanced->layout()->addWidget(advanced);
118 connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, 122 connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
119 [this] { CallConfigureDialog<ConfigureDebugController>(*this); }); 123 CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem);
120 connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, 124 });
121 [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); }); 125 connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
126 CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
127 });
122 connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, 128 connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
123 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); 129 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
124 130
@@ -129,8 +135,6 @@ ConfigureInput::ConfigureInput(QWidget* parent)
129 LoadConfiguration(); 135 LoadConfiguration();
130} 136}
131 137
132ConfigureInput::~ConfigureInput() = default;
133
134QList<QWidget*> ConfigureInput::GetSubTabs() const { 138QList<QWidget*> ConfigureInput::GetSubTabs() const {
135 return { 139 return {
136 ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5, 140 ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5,
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 78ca659da..d08a24f96 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -7,8 +7,8 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9 9
10#include <QDialog>
11#include <QKeyEvent> 10#include <QKeyEvent>
11#include <QWidget>
12 12
13#include "yuzu/configuration/configure_input_advanced.h" 13#include "yuzu/configuration/configure_input_advanced.h"
14#include "yuzu/configuration/configure_input_player.h" 14#include "yuzu/configuration/configure_input_player.h"
@@ -19,6 +19,10 @@ class QCheckBox;
19class QString; 19class QString;
20class QTimer; 20class QTimer;
21 21
22namespace InputCommon {
23class InputSubsystem;
24}
25
22namespace Ui { 26namespace Ui {
23class ConfigureInput; 27class ConfigureInput;
24} 28}
@@ -32,6 +36,9 @@ public:
32 explicit ConfigureInput(QWidget* parent = nullptr); 36 explicit ConfigureInput(QWidget* parent = nullptr);
33 ~ConfigureInput() override; 37 ~ConfigureInput() override;
34 38
39 /// Initializes the input dialog with the given input subsystem.
40 void Initialize(InputCommon::InputSubsystem* input_subsystem_);
41
35 /// Save all button configurations to settings file. 42 /// Save all button configurations to settings file.
36 void ApplyConfiguration(); 43 void ApplyConfiguration();
37 44
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index d3980eb49..80bf40acb 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -11,12 +11,12 @@
11#include <QMenu> 11#include <QMenu>
12#include <QMessageBox> 12#include <QMessageBox>
13#include <QTimer> 13#include <QTimer>
14#include "common/assert.h"
15#include "common/param_package.h" 14#include "common/param_package.h"
16#include "core/core.h" 15#include "core/core.h"
17#include "core/hle/service/hid/controllers/npad.h" 16#include "core/hle/service/hid/controllers/npad.h"
18#include "core/hle/service/hid/hid.h" 17#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/sm/sm.h" 18#include "core/hle/service/sm/sm.h"
19#include "input_common/gcadapter/gc_poller.h"
20#include "input_common/main.h" 20#include "input_common/main.h"
21#include "ui_configure_input_player.h" 21#include "ui_configure_input_player.h"
22#include "yuzu/configuration/config.h" 22#include "yuzu/configuration/config.h"
@@ -229,9 +229,11 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir)
229} // namespace 229} // namespace
230 230
231ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, 231ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
232 QWidget* bottom_row, bool debug) 232 QWidget* bottom_row,
233 InputCommon::InputSubsystem* input_subsystem_,
234 bool debug)
233 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), 235 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
234 debug(debug), timeout_timer(std::make_unique<QTimer>()), 236 debug(debug), input_subsystem{input_subsystem_}, timeout_timer(std::make_unique<QTimer>()),
235 poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) { 237 poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) {
236 ui->setupUi(this); 238 ui->setupUi(this);
237 239
@@ -287,7 +289,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
287 params.Set("direction", "+"); 289 params.Set("direction", "+");
288 params.Set("threshold", "0.5"); 290 params.Set("threshold", "0.5");
289 } 291 }
290 (*param) = std::move(params); 292 *param = std::move(params);
291 }, 293 },
292 InputCommon::Polling::DeviceType::Button); 294 InputCommon::Polling::DeviceType::Button);
293 }); 295 });
@@ -401,15 +403,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
401 403
402 connect(poll_timer.get(), &QTimer::timeout, [this] { 404 connect(poll_timer.get(), &QTimer::timeout, [this] {
403 Common::ParamPackage params; 405 Common::ParamPackage params;
404 if (InputCommon::GetGCButtons()->IsPolling()) { 406 if (input_subsystem->GetGCButtons()->IsPolling()) {
405 params = InputCommon::GetGCButtons()->GetNextInput(); 407 params = input_subsystem->GetGCButtons()->GetNextInput();
406 if (params.Has("engine")) { 408 if (params.Has("engine")) {
407 SetPollingResult(params, false); 409 SetPollingResult(params, false);
408 return; 410 return;
409 } 411 }
410 } 412 }
411 if (InputCommon::GetGCAnalogs()->IsPolling()) { 413 if (input_subsystem->GetGCAnalogs()->IsPolling()) {
412 params = InputCommon::GetGCAnalogs()->GetNextInput(); 414 params = input_subsystem->GetGCAnalogs()->GetNextInput();
413 if (params.Has("engine")) { 415 if (params.Has("engine")) {
414 SetPollingResult(params, false); 416 SetPollingResult(params, false);
415 return; 417 return;
@@ -514,7 +516,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
514} 516}
515 517
516void ConfigureInputPlayer::UpdateInputDevices() { 518void ConfigureInputPlayer::UpdateInputDevices() {
517 input_devices = InputCommon::GetInputDevices(); 519 input_devices = input_subsystem->GetInputDevices();
518 ui->comboDevices->clear(); 520 ui->comboDevices->clear();
519 for (auto device : input_devices) { 521 for (auto device : input_devices) {
520 ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); 522 ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
@@ -642,8 +644,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
642 return; 644 return;
643 } 645 }
644 const auto& device = input_devices[ui->comboDevices->currentIndex()]; 646 const auto& device = input_devices[ui->comboDevices->currentIndex()];
645 auto button_mapping = InputCommon::GetButtonMappingForDevice(device); 647 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
646 auto analog_mapping = InputCommon::GetAnalogMappingForDevice(device); 648 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
647 for (int i = 0; i < buttons_param.size(); ++i) { 649 for (int i = 0; i < buttons_param.size(); ++i) {
648 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; 650 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
649 } 651 }
@@ -666,7 +668,7 @@ void ConfigureInputPlayer::HandleClick(
666 668
667 input_setter = new_input_setter; 669 input_setter = new_input_setter;
668 670
669 device_pollers = InputCommon::Polling::GetPollers(type); 671 device_pollers = input_subsystem->GetPollers(type);
670 672
671 for (auto& poller : device_pollers) { 673 for (auto& poller : device_pollers) {
672 poller->Start(); 674 poller->Start();
@@ -676,9 +678,9 @@ void ConfigureInputPlayer::HandleClick(
676 QWidget::grabKeyboard(); 678 QWidget::grabKeyboard();
677 679
678 if (type == InputCommon::Polling::DeviceType::Button) { 680 if (type == InputCommon::Polling::DeviceType::Button) {
679 InputCommon::GetGCButtons()->BeginConfiguration(); 681 input_subsystem->GetGCButtons()->BeginConfiguration();
680 } else { 682 } else {
681 InputCommon::GetGCAnalogs()->BeginConfiguration(); 683 input_subsystem->GetGCAnalogs()->BeginConfiguration();
682 } 684 }
683 685
684 timeout_timer->start(2500); // Cancel after 2.5 seconds 686 timeout_timer->start(2500); // Cancel after 2.5 seconds
@@ -695,8 +697,8 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
695 QWidget::releaseMouse(); 697 QWidget::releaseMouse();
696 QWidget::releaseKeyboard(); 698 QWidget::releaseKeyboard();
697 699
698 InputCommon::GetGCButtons()->EndConfiguration(); 700 input_subsystem->GetGCButtons()->EndConfiguration();
699 InputCommon::GetGCAnalogs()->EndConfiguration(); 701 input_subsystem->GetGCAnalogs()->EndConfiguration();
700 702
701 if (!abort) { 703 if (!abort) {
702 (*input_setter)(params); 704 (*input_setter)(params);
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 25d4cde5e..a25bc3bd9 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -10,12 +10,11 @@
10#include <optional> 10#include <optional>
11#include <string> 11#include <string>
12 12
13#include <QDialog> 13#include <QWidget>
14 14
15#include "common/param_package.h" 15#include "common/param_package.h"
16#include "core/settings.h" 16#include "core/settings.h"
17#include "ui_configure_input.h" 17#include "ui_configure_input.h"
18#include "yuzu/uisettings.h"
19 18
20class QCheckBox; 19class QCheckBox;
21class QKeyEvent; 20class QKeyEvent;
@@ -27,6 +26,10 @@ class QString;
27class QTimer; 26class QTimer;
28class QWidget; 27class QWidget;
29 28
29namespace InputCommon {
30class InputSubsystem;
31}
32
30namespace InputCommon::Polling { 33namespace InputCommon::Polling {
31class DevicePoller; 34class DevicePoller;
32enum class DeviceType; 35enum class DeviceType;
@@ -41,6 +44,7 @@ class ConfigureInputPlayer : public QWidget {
41 44
42public: 45public:
43 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, 46 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
47 InputCommon::InputSubsystem* input_subsystem_,
44 bool debug = false); 48 bool debug = false);
45 ~ConfigureInputPlayer() override; 49 ~ConfigureInputPlayer() override;
46 50
@@ -111,6 +115,8 @@ private:
111 std::size_t player_index; 115 std::size_t player_index;
112 bool debug; 116 bool debug;
113 117
118 InputCommon::InputSubsystem* input_subsystem;
119
114 std::unique_ptr<QTimer> timeout_timer; 120 std::unique_ptr<QTimer> timeout_timer;
115 std::unique_ptr<QTimer> poll_timer; 121 std::unique_ptr<QTimer> poll_timer;
116 122
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index dcda8ab14..2af3afda8 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -76,8 +76,10 @@ static QString ButtonToText(const Common::ParamPackage& param) {
76 return QObject::tr("[unknown]"); 76 return QObject::tr("[unknown]");
77} 77}
78 78
79ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent) 79ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent,
80 : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), 80 InputCommon::InputSubsystem* input_subsystem_)
81 : QDialog(parent),
82 ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), input_subsystem{input_subsystem_},
81 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { 83 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
82 ui->setupUi(this); 84 ui->setupUi(this);
83 setFocusPolicy(Qt::ClickFocus); 85 setFocusPolicy(Qt::ClickFocus);
@@ -209,7 +211,7 @@ void ConfigureMouseAdvanced::HandleClick(
209 211
210 input_setter = new_input_setter; 212 input_setter = new_input_setter;
211 213
212 device_pollers = InputCommon::Polling::GetPollers(type); 214 device_pollers = input_subsystem->GetPollers(type);
213 215
214 for (auto& poller : device_pollers) { 216 for (auto& poller : device_pollers) {
215 poller->Start(); 217 poller->Start();
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
index e7d27dab7..65b6fca9a 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.h
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -8,12 +8,14 @@
8#include <optional> 8#include <optional>
9#include <QDialog> 9#include <QDialog>
10 10
11#include "core/settings.h"
12
13class QCheckBox; 11class QCheckBox;
14class QPushButton; 12class QPushButton;
15class QTimer; 13class QTimer;
16 14
15namespace InputCommon {
16class InputSubsystem;
17}
18
17namespace Ui { 19namespace Ui {
18class ConfigureMouseAdvanced; 20class ConfigureMouseAdvanced;
19} 21}
@@ -22,7 +24,7 @@ class ConfigureMouseAdvanced : public QDialog {
22 Q_OBJECT 24 Q_OBJECT
23 25
24public: 26public:
25 explicit ConfigureMouseAdvanced(QWidget* parent); 27 explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
26 ~ConfigureMouseAdvanced() override; 28 ~ConfigureMouseAdvanced() override;
27 29
28 void ApplyConfiguration(); 30 void ApplyConfiguration();
@@ -57,6 +59,8 @@ private:
57 59
58 std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; 60 std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
59 61
62 InputCommon::InputSubsystem* input_subsystem;
63
60 /// This will be the the setting function when an input is awaiting configuration. 64 /// This will be the the setting function when an input is awaiting configuration.
61 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; 65 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
62 66
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cd7e78eb4..cab9d680a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -94,6 +94,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
94#include "core/perf_stats.h" 94#include "core/perf_stats.h"
95#include "core/settings.h" 95#include "core/settings.h"
96#include "core/telemetry_session.h" 96#include "core/telemetry_session.h"
97#include "input_common/main.h"
97#include "video_core/gpu.h" 98#include "video_core/gpu.h"
98#include "video_core/shader_notify.h" 99#include "video_core/shader_notify.h"
99#include "yuzu/about_dialog.h" 100#include "yuzu/about_dialog.h"
@@ -186,9 +187,9 @@ static void InitializeLogging() {
186} 187}
187 188
188GMainWindow::GMainWindow() 189GMainWindow::GMainWindow()
189 : config(new Config()), emu_thread(nullptr), 190 : input_subsystem{std::make_unique<InputCommon::InputSubsystem>()},
190 vfs(std::make_shared<FileSys::RealVfsFilesystem>()), 191 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
191 provider(std::make_unique<FileSys::ManualContentProvider>()) { 192 provider{std::make_unique<FileSys::ManualContentProvider>()} {
192 InitializeLogging(); 193 InitializeLogging();
193 194
194 LoadTranslation(); 195 LoadTranslation();
@@ -473,7 +474,7 @@ void GMainWindow::InitializeWidgets() {
473#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING 474#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
474 ui.action_Report_Compatibility->setVisible(true); 475 ui.action_Report_Compatibility->setVisible(true);
475#endif 476#endif
476 render_window = new GRenderWindow(this, emu_thread.get()); 477 render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem.get());
477 render_window->hide(); 478 render_window->hide();
478 479
479 game_list = new GameList(vfs, provider.get(), this); 480 game_list = new GameList(vfs, provider.get(), this);
@@ -2213,7 +2214,7 @@ void GMainWindow::OnConfigure() {
2213 const auto old_theme = UISettings::values.theme; 2214 const auto old_theme = UISettings::values.theme;
2214 const bool old_discord_presence = UISettings::values.enable_discord_presence; 2215 const bool old_discord_presence = UISettings::values.enable_discord_presence;
2215 2216
2216 ConfigureDialog configure_dialog(this, hotkey_registry); 2217 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
2217 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, 2218 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
2218 &GMainWindow::OnLanguageChanged); 2219 &GMainWindow::OnLanguageChanged);
2219 2220
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 01f9131e5..957f20fa8 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -40,12 +40,20 @@ namespace Core::Frontend {
40struct SoftwareKeyboardParameters; 40struct SoftwareKeyboardParameters;
41} // namespace Core::Frontend 41} // namespace Core::Frontend
42 42
43namespace DiscordRPC {
44class DiscordInterface;
45}
46
43namespace FileSys { 47namespace FileSys {
44class ContentProvider; 48class ContentProvider;
45class ManualContentProvider; 49class ManualContentProvider;
46class VfsFilesystem; 50class VfsFilesystem;
47} // namespace FileSys 51} // namespace FileSys
48 52
53namespace InputCommon {
54class InputSubsystem;
55}
56
49enum class EmulatedDirectoryTarget { 57enum class EmulatedDirectoryTarget {
50 NAND, 58 NAND,
51 SDMC, 59 SDMC,
@@ -62,10 +70,6 @@ enum class ReinitializeKeyBehavior {
62 Warning, 70 Warning,
63}; 71};
64 72
65namespace DiscordRPC {
66class DiscordInterface;
67}
68
69class GMainWindow : public QMainWindow { 73class GMainWindow : public QMainWindow {
70 Q_OBJECT 74 Q_OBJECT
71 75
@@ -86,8 +90,6 @@ public:
86 GMainWindow(); 90 GMainWindow();
87 ~GMainWindow() override; 91 ~GMainWindow() override;
88 92
89 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
90
91 bool DropAction(QDropEvent* event); 93 bool DropAction(QDropEvent* event);
92 void AcceptDropEvent(QDropEvent* event); 94 void AcceptDropEvent(QDropEvent* event);
93 95
@@ -255,6 +257,9 @@ private:
255 257
256 Ui::MainWindow ui; 258 Ui::MainWindow ui;
257 259
260 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
261 std::unique_ptr<InputCommon::InputSubsystem> input_subsystem;
262
258 GRenderWindow* render_window; 263 GRenderWindow* render_window;
259 GameList* game_list; 264 GameList* game_list;
260 LoadingScreen* loading_screen; 265 LoadingScreen* loading_screen;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index e5e684206..a804d5185 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -13,23 +13,25 @@
13#include "input_common/sdl/sdl.h" 13#include "input_common/sdl/sdl.h"
14#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 14#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
15 15
16EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen) : system{system} { 16EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen,
17 InputCommon::InputSubsystem* input_subsystem_)
18 : system{system}, input_subsystem{input_subsystem_} {
17 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { 19 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
18 LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); 20 LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
19 exit(1); 21 exit(1);
20 } 22 }
21 InputCommon::Init(); 23 input_subsystem->Initialize();
22 SDL_SetMainReady(); 24 SDL_SetMainReady();
23} 25}
24 26
25EmuWindow_SDL2::~EmuWindow_SDL2() { 27EmuWindow_SDL2::~EmuWindow_SDL2() {
26 InputCommon::Shutdown(); 28 input_subsystem->Shutdown();
27 SDL_Quit(); 29 SDL_Quit();
28} 30}
29 31
30void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { 32void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
31 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); 33 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
32 InputCommon::GetMotionEmu()->Tilt(x, y); 34 input_subsystem->GetMotionEmu()->Tilt(x, y);
33} 35}
34 36
35void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 37void 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) {
41 } 43 }
42 } else if (button == SDL_BUTTON_RIGHT) { 44 } else if (button == SDL_BUTTON_RIGHT) {
43 if (state == SDL_PRESSED) { 45 if (state == SDL_PRESSED) {
44 InputCommon::GetMotionEmu()->BeginTilt(x, y); 46 input_subsystem->GetMotionEmu()->BeginTilt(x, y);
45 } else { 47 } else {
46 InputCommon::GetMotionEmu()->EndTilt(); 48 input_subsystem->GetMotionEmu()->EndTilt();
47 } 49 }
48 } 50 }
49} 51}
@@ -79,9 +81,9 @@ void EmuWindow_SDL2::OnFingerUp() {
79 81
80void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 82void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
81 if (state == SDL_PRESSED) { 83 if (state == SDL_PRESSED) {
82 InputCommon::GetKeyboard()->PressKey(key); 84 input_subsystem->GetKeyboard()->PressKey(key);
83 } else if (state == SDL_RELEASED) { 85 } else if (state == SDL_RELEASED) {
84 InputCommon::GetKeyboard()->ReleaseKey(key); 86 input_subsystem->GetKeyboard()->ReleaseKey(key);
85 } 87 }
86} 88}
87 89
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index fffac4252..82750ffec 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -14,9 +14,14 @@ namespace Core {
14class System; 14class System;
15} 15}
16 16
17namespace InputCommon {
18class InputSubsystem;
19}
20
17class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { 21class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
18public: 22public:
19 explicit EmuWindow_SDL2(Core::System& system, bool fullscreen); 23 explicit EmuWindow_SDL2(Core::System& system, bool fullscreen,
24 InputCommon::InputSubsystem* input_subsystem);
20 ~EmuWindow_SDL2(); 25 ~EmuWindow_SDL2();
21 26
22 /// Polls window events 27 /// Polls window events
@@ -76,4 +81,7 @@ protected:
76 81
77 /// Keeps track of how often to update the title bar during gameplay 82 /// Keeps track of how often to update the title bar during gameplay
78 u32 last_time = 0; 83 u32 last_time = 0;
84
85 /// Input subsystem to use with this window.
86 InputCommon::InputSubsystem* input_subsystem;
79}; 87};
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index e78025737..881b67a76 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -87,8 +87,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
87 return unsupported_ext.empty(); 87 return unsupported_ext.empty();
88} 88}
89 89
90EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen) 90EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen,
91 : EmuWindow_SDL2{system, fullscreen} { 91 InputCommon::InputSubsystem* input_subsystem)
92 : EmuWindow_SDL2{system, fullscreen, input_subsystem} {
92 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 93 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
93 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 94 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
94 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); 95 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
index 48bb41683..732a64edd 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
@@ -8,9 +8,14 @@
8#include "core/frontend/emu_window.h" 8#include "core/frontend/emu_window.h"
9#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 9#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
10 10
11namespace InputCommon {
12class InputSubsystem;
13}
14
11class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { 15class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
12public: 16public:
13 explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen); 17 explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen,
18 InputCommon::InputSubsystem* input_subsystem);
14 ~EmuWindow_SDL2_GL(); 19 ~EmuWindow_SDL2_GL();
15 20
16 void Present() override; 21 void Present() override;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index cb8e68a39..53491f86e 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -19,8 +19,9 @@
19#include <SDL.h> 19#include <SDL.h>
20#include <SDL_syswm.h> 20#include <SDL_syswm.h>
21 21
22EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen) 22EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen,
23 : EmuWindow_SDL2{system, fullscreen} { 23 InputCommon::InputSubsystem* input_subsystem)
24 : EmuWindow_SDL2{system, fullscreen, input_subsystem} {
24 const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, 25 const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
25 Common::g_scm_branch, Common::g_scm_desc); 26 Common::g_scm_branch, Common::g_scm_desc);
26 render_window = 27 render_window =
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
index 77a6ca72b..f99704d4c 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
@@ -13,9 +13,14 @@ namespace Core {
13class System; 13class System;
14} 14}
15 15
16namespace InputCommon {
17class InputSubsystem;
18}
19
16class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { 20class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
17public: 21public:
18 explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen); 22 explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen,
23 InputCommon::InputSubsystem* input_subsystem);
19 ~EmuWindow_SDL2_VK(); 24 ~EmuWindow_SDL2_VK();
20 25
21 void Present() override; 26 void Present() override;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 8efe49390..4f00c804d 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -23,12 +23,14 @@
23#include "common/telemetry.h" 23#include "common/telemetry.h"
24#include "core/core.h" 24#include "core/core.h"
25#include "core/crypto/key_manager.h" 25#include "core/crypto/key_manager.h"
26#include "core/file_sys/registered_cache.h"
26#include "core/file_sys/vfs_real.h" 27#include "core/file_sys/vfs_real.h"
27#include "core/gdbstub/gdbstub.h" 28#include "core/gdbstub/gdbstub.h"
28#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
29#include "core/loader/loader.h" 30#include "core/loader/loader.h"
30#include "core/settings.h" 31#include "core/settings.h"
31#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
33#include "input_common/main.h"
32#include "video_core/renderer_base.h" 34#include "video_core/renderer_base.h"
33#include "yuzu_cmd/config.h" 35#include "yuzu_cmd/config.h"
34#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 36#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
@@ -37,8 +39,6 @@
37#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" 39#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
38#endif 40#endif
39 41
40#include "core/file_sys/registered_cache.h"
41
42#ifdef _WIN32 42#ifdef _WIN32
43// windows.h needs to be included before shellapi.h 43// windows.h needs to be included before shellapi.h
44#include <windows.h> 44#include <windows.h>
@@ -179,15 +179,16 @@ int main(int argc, char** argv) {
179 Settings::Apply(); 179 Settings::Apply();
180 180
181 Core::System& system{Core::System::GetInstance()}; 181 Core::System& system{Core::System::GetInstance()};
182 InputCommon::InputSubsystem input_subsystem;
182 183
183 std::unique_ptr<EmuWindow_SDL2> emu_window; 184 std::unique_ptr<EmuWindow_SDL2> emu_window;
184 switch (Settings::values.renderer_backend.GetValue()) { 185 switch (Settings::values.renderer_backend.GetValue()) {
185 case Settings::RendererBackend::OpenGL: 186 case Settings::RendererBackend::OpenGL:
186 emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen); 187 emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, &input_subsystem);
187 break; 188 break;
188 case Settings::RendererBackend::Vulkan: 189 case Settings::RendererBackend::Vulkan:
189#ifdef HAS_VULKAN 190#ifdef HAS_VULKAN
190 emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen); 191 emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, &input_subsystem);
191 break; 192 break;
192#else 193#else
193 LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!"); 194 LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!");
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
index 8584f6671..78f75fb38 100644
--- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
+++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
@@ -13,7 +13,6 @@
13 13
14#include <glad/glad.h> 14#include <glad/glad.h>
15 15
16#include "common/assert.h"
17#include "common/logging/log.h" 16#include "common/logging/log.h"
18#include "common/scm_rev.h" 17#include "common/scm_rev.h"
19#include "core/settings.h" 18#include "core/settings.h"
@@ -53,7 +52,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
53 exit(1); 52 exit(1);
54 } 53 }
55 54
56 InputCommon::Init(); 55 input_subsystem->Initialize();
57 56
58 SDL_SetMainReady(); 57 SDL_SetMainReady();
59 58
@@ -105,7 +104,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
105} 104}
106 105
107EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { 106EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() {
108 InputCommon::Shutdown(); 107 input_subsystem->Shutdown();
109 SDL_GL_DeleteContext(gl_context); 108 SDL_GL_DeleteContext(gl_context);
110 SDL_Quit(); 109 SDL_Quit();
111} 110}
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
index c13a82df2..a553b4b95 100644
--- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
+++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
@@ -8,6 +8,10 @@
8 8
9struct SDL_Window; 9struct SDL_Window;
10 10
11namespace InputCommon {
12class InputSubsystem;
13}
14
11class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow { 15class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow {
12public: 16public:
13 explicit EmuWindow_SDL2_Hide(); 17 explicit EmuWindow_SDL2_Hide();
@@ -25,6 +29,8 @@ private:
25 /// Whether the GPU and driver supports the OpenGL extension required 29 /// Whether the GPU and driver supports the OpenGL extension required
26 bool SupportsRequiredGLExtensions(); 30 bool SupportsRequiredGLExtensions();
27 31
32 std::unique_ptr<InputCommon::InputSubsystem> input_subsystem;
33
28 /// Internal SDL2 render window 34 /// Internal SDL2 render window
29 SDL_Window* render_window; 35 SDL_Window* render_window;
30 36