Dependency injection for apu/gpu/hid.

This commit is contained in:
Ben Vanik 2015-11-08 15:02:24 -08:00
parent 9a6c5c5c74
commit 5834a42ef3
34 changed files with 217 additions and 158 deletions

View File

@ -17,11 +17,103 @@
#include "xenia/emulator.h"
#include "xenia/ui/file_picker.h"
// Available audio systems:
#include "xenia/apu/nop/nop_audio_system.h"
#if XE_PLATFORM_WIN32
#include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#endif // XE_PLATFORM_WIN32
// Available graphics systems:
#include "xenia/gpu/gl4/gl4_graphics_system.h"
// Available input drivers:
#include "xenia/hid/nop/nop_hid.h"
#if XE_PLATFORM_WIN32
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h"
#endif // XE_PLATFORM_WIN32
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, gl4]");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");
DEFINE_string(target, "", "Specifies the target .xex or .iso to execute.");
namespace xe {
namespace app {
std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
if (FLAGS_apu.compare("nop") == 0) {
return apu::nop::NopAudioSystem::Create(processor);
#if XE_PLATFORM_WIN32
} else if (FLAGS_apu.compare("xaudio2") == 0) {
return apu::xaudio2::XAudio2AudioSystem::Create(processor);
#endif // XE_PLATFORM_WIN32
} else {
// Create best available.
std::unique_ptr<apu::AudioSystem> best;
#if XE_PLATFORM_WIN32
best = apu::xaudio2::XAudio2AudioSystem::Create(processor);
if (best) {
return best;
}
#endif // XE_PLATFORM_WIN32
// Fallback to nop.
return apu::nop::NopAudioSystem::Create(processor);
}
}
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
if (FLAGS_gpu.compare("gl4") == 0) {
return std::unique_ptr<gpu::GraphicsSystem>(
new xe::gpu::gl4::GL4GraphicsSystem());
} else {
// Create best available.
std::unique_ptr<gpu::GraphicsSystem> best;
best = std::unique_ptr<gpu::GraphicsSystem>(
new xe::gpu::gl4::GL4GraphicsSystem());
if (best) {
return best;
}
// Nothing!
return nullptr;
}
}
std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
ui::Window* window) {
std::vector<std::unique_ptr<hid::InputDriver>> drivers;
if (FLAGS_hid.compare("nop") == 0) {
drivers.emplace_back(xe::hid::nop::Create(window));
#if XE_PLATFORM_WIN32
} else if (FLAGS_hid.compare("winkey") == 0) {
drivers.emplace_back(xe::hid::winkey::Create(window));
} else if (FLAGS_hid.compare("xinput") == 0) {
drivers.emplace_back(xe::hid::xinput::Create(window));
#endif // XE_PLATFORM_WIN32
} else {
#if XE_PLATFORM_WIN32
auto xinput_driver = xe::hid::xinput::Create(window);
if (xinput_driver) {
drivers.emplace_back(std::move(xinput_driver));
}
auto winkey_driver = xe::hid::winkey::Create(window);
if (winkey_driver) {
drivers.emplace_back(std::move(winkey_driver));
}
#endif // XE_PLATFORM_WIN32
if (drivers.empty()) {
// Fallback to nop if none created.
drivers.emplace_back(xe::hid::nop::Create(window));
}
}
return drivers;
}
int xenia_main(const std::vector<std::wstring>& args) {
Profiler::Initialize();
Profiler::ThreadEnter("main");
@ -34,7 +126,9 @@ int xenia_main(const std::vector<std::wstring>& args) {
// Setup and initialize all subsystems. If we can't do something
// (unsupported system, memory issues, etc) this will fail early.
X_STATUS result = emulator->Setup(emulator_window->window());
X_STATUS result =
emulator->Setup(emulator_window->window(), CreateAudioSystem,
CreateGraphicsSystem, CreateInputDrivers);
if (XFAILED(result)) {
XELOGE("Failed to setup emulator: %.8X", result);
return 1;

View File

@ -9,6 +9,4 @@
#include "xenia/apu/apu_flags.h"
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]");
DEFINE_bool(mute, false, "Mutes all audio output.");

View File

@ -12,8 +12,6 @@
#include <gflags/gflags.h>
DECLARE_string(apu);
DECLARE_bool(mute);
#endif // XENIA_APU_APU_FLAGS_H_

View File

@ -20,11 +20,6 @@
#include "xenia/base/threading.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/apu/nop/nop_audio_system.h"
#if XE_PLATFORM_WIN32
#include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#endif // XE_PLATFORM_WIN32
// As with normal Microsoft, there are like twelve different ways to access
// the audio APIs. Early games use XMA*() methods almost exclusively to touch
// decoders. Later games use XAudio*() and direct memory writes to the XMA
@ -40,29 +35,6 @@
namespace xe {
namespace apu {
std::unique_ptr<AudioSystem> AudioSystem::Create(cpu::Processor* processor) {
if (FLAGS_apu.compare("nop") == 0) {
return nop::NopAudioSystem::Create(processor);
#if XE_PLATFORM_WIN32
} else if (FLAGS_apu.compare("xaudio2") == 0) {
return xaudio2::XAudio2AudioSystem::Create(processor);
#endif // WIN32
} else {
// Create best available.
std::unique_ptr<AudioSystem> best;
#if XE_PLATFORM_WIN32
best = xaudio2::XAudio2AudioSystem::Create(processor);
if (best) {
return best;
}
#endif // XE_PLATFORM_WIN32
// Fallback to nop.
return nop::NopAudioSystem::Create(processor);
}
}
AudioSystem::AudioSystem(cpu::Processor* processor)
: memory_(processor->memory()),
processor_(processor),

View File

@ -30,8 +30,6 @@ class AudioSystem {
public:
virtual ~AudioSystem();
static std::unique_ptr<AudioSystem> Create(cpu::Processor* processor);
Memory* memory() const { return memory_; }
cpu::Processor* processor() const { return processor_; }
XmaDecoder* xma_decoder() const { return xma_decoder_.get(); }

View File

@ -22,6 +22,7 @@
#include "xenia/base/string.h"
#include "xenia/cpu/backend/code_cache.h"
#include "xenia/gpu/graphics_system.h"
#include "xenia/hid/input_driver.h"
#include "xenia/hid/input_system.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/xam/xam_module.h"
@ -68,7 +69,14 @@ Emulator::~Emulator() {
ExceptionHandler::Uninstall(Emulator::ExceptionCallbackThunk, this);
}
X_STATUS Emulator::Setup(ui::Window* display_window) {
X_STATUS Emulator::Setup(
ui::Window* display_window,
std::function<std::unique_ptr<apu::AudioSystem>(cpu::Processor*)>
audio_system_factory,
std::function<std::unique_ptr<gpu::GraphicsSystem>()>
graphics_system_factory,
std::function<std::vector<std::unique_ptr<hid::InputDriver>>(ui::Window*)>
input_driver_factory) {
X_STATUS result = X_STATUS_UNSUCCESSFUL;
display_window_ = display_window;
@ -111,13 +119,15 @@ X_STATUS Emulator::Setup(ui::Window* display_window) {
}
// Initialize the APU.
audio_system_ = xe::apu::AudioSystem::Create(processor_.get());
if (!audio_system_) {
return X_STATUS_NOT_IMPLEMENTED;
if (audio_system_factory) {
audio_system_ = audio_system_factory(processor_.get());
if (!audio_system_) {
return X_STATUS_NOT_IMPLEMENTED;
}
}
// Initialize the GPU.
graphics_system_ = xe::gpu::GraphicsSystem::Create();
graphics_system_ = graphics_system_factory();
if (!graphics_system_) {
return X_STATUS_NOT_IMPLEMENTED;
}
@ -127,10 +137,16 @@ X_STATUS Emulator::Setup(ui::Window* display_window) {
});
// Initialize the HID.
input_system_ = xe::hid::InputSystem::Create(display_window_);
input_system_ = std::make_unique<xe::hid::InputSystem>(display_window_);
if (!input_system_) {
return X_STATUS_NOT_IMPLEMENTED;
}
if (input_driver_factory) {
auto input_drivers = input_driver_factory(display_window_);
for (size_t i = 0; i < input_drivers.size(); ++i) {
input_system_->AddDriver(std::move(input_drivers[i]));
}
}
result = input_system_->Setup();
if (result) {
@ -150,9 +166,11 @@ X_STATUS Emulator::Setup(ui::Window* display_window) {
return result;
}
result = audio_system_->Setup(kernel_state_.get());
if (result) {
return result;
if (audio_system_) {
result = audio_system_->Setup(kernel_state_.get());
if (result) {
return result;
}
}
// HLE kernel modules.

View File

@ -10,6 +10,7 @@
#ifndef XENIA_EMULATOR_H_
#define XENIA_EMULATOR_H_
#include <functional>
#include <string>
#include "xenia/base/exception_handler.h"
@ -32,6 +33,7 @@ namespace gpu {
class GraphicsSystem;
} // namespace gpu
namespace hid {
class InputDriver;
class InputSystem;
} // namespace hid
namespace ui {
@ -68,7 +70,14 @@ class Emulator {
kernel::KernelState* kernel_state() const { return kernel_state_.get(); }
X_STATUS Setup(ui::Window* display_window);
X_STATUS Setup(
ui::Window* display_window,
std::function<std::unique_ptr<apu::AudioSystem>(cpu::Processor*)>
audio_system_factory,
std::function<std::unique_ptr<gpu::GraphicsSystem>()>
graphics_system_factory,
std::function<std::vector<std::unique_ptr<hid::InputDriver>>(ui::Window*)>
input_driver_factory);
X_STATUS LaunchPath(std::wstring path);
X_STATUS LaunchXexFile(std::wstring path);

View File

@ -24,10 +24,6 @@ namespace xe {
namespace gpu {
namespace gl4 {
std::unique_ptr<GraphicsSystem> Create() {
return std::make_unique<GL4GraphicsSystem>();
}
std::unique_ptr<ui::GraphicsContext> GL4GraphicsSystem::CreateContext(
ui::Window* target_window) {
// Setup the GL control that actually does the drawing.

View File

@ -30,6 +30,10 @@ using namespace xe::gpu::xenos;
class GL4TraceViewer : public TraceViewer {
public:
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
return std::unique_ptr<gpu::GraphicsSystem>(new GL4GraphicsSystem());
}
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
ColorRenderTargetFormat format) override {

View File

@ -9,8 +9,6 @@
#include "xenia/gpu/gpu_flags.h"
DEFINE_string(gpu, "any", "Graphics system. Use: [any, gl4]");
DEFINE_string(trace_gpu_prefix, "scratch/gpu/gpu_trace_",
"Prefix path for GPU trace files.");
DEFINE_bool(trace_gpu_stream, false, "Trace all GPU packets.");

View File

@ -12,8 +12,6 @@
#include <gflags/gflags.h>
DECLARE_string(gpu);
DECLARE_string(trace_gpu_prefix);
DECLARE_bool(trace_gpu_stream);

View File

@ -21,27 +21,6 @@
namespace xe {
namespace gpu {
namespace gl4 {
std::unique_ptr<GraphicsSystem> Create();
} // namespace gl4
std::unique_ptr<GraphicsSystem> GraphicsSystem::Create() {
if (FLAGS_gpu.compare("gl4") == 0) {
return xe::gpu::gl4::Create();
} else {
// Create best available.
std::unique_ptr<GraphicsSystem> best;
best = xe::gpu::gl4::Create();
if (best) {
return best;
}
// Nothing!
return nullptr;
}
}
GraphicsSystem::GraphicsSystem() : vsync_worker_running_(false) {}
GraphicsSystem::~GraphicsSystem() = default;

View File

@ -34,7 +34,6 @@ class GraphicsSystem {
public:
virtual ~GraphicsSystem();
static std::unique_ptr<GraphicsSystem> Create();
virtual std::unique_ptr<ui::GraphicsContext> CreateContext(
ui::Window* target_window) = 0;

View File

@ -66,7 +66,9 @@ bool TraceViewer::Setup() {
// Create the emulator but don't initialize so we can setup the window.
emulator_ = std::make_unique<Emulator>(L"");
X_STATUS result = emulator_->Setup(window_.get());
X_STATUS result =
emulator_->Setup(window_.get(), nullptr,
[this]() { return CreateGraphicsSystem(); }, nullptr);
if (XFAILED(result)) {
XELOGE("Failed to setup emulator: %.8X", result);
return false;

View File

@ -44,6 +44,8 @@ class TraceViewer {
protected:
TraceViewer();
virtual std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() = 0;
void DrawMultilineString(const std::string& str);
virtual uintptr_t GetColorRenderTarget(

View File

@ -22,12 +22,51 @@
#include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/window.h"
// Available input drivers:
#include "xenia/hid/nop/nop_hid.h"
#if XE_PLATFORM_WIN32
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h"
#endif // XE_PLATFORM_WIN32
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");
namespace xe {
namespace hid {
std::unique_ptr<xe::ui::ImGuiDrawer> imgui_drawer_;
std::unique_ptr<xe::hid::InputSystem> input_system_;
std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
ui::Window* window) {
std::vector<std::unique_ptr<hid::InputDriver>> drivers;
if (FLAGS_hid.compare("nop") == 0) {
drivers.emplace_back(xe::hid::nop::Create(window));
#if XE_PLATFORM_WIN32
} else if (FLAGS_hid.compare("winkey") == 0) {
drivers.emplace_back(xe::hid::winkey::Create(window));
} else if (FLAGS_hid.compare("xinput") == 0) {
drivers.emplace_back(xe::hid::xinput::Create(window));
#endif // XE_PLATFORM_WIN32
} else {
#if XE_PLATFORM_WIN32
auto xinput_driver = xe::hid::xinput::Create(window);
if (xinput_driver) {
drivers.emplace_back(std::move(xinput_driver));
}
auto winkey_driver = xe::hid::winkey::Create(window);
if (winkey_driver) {
drivers.emplace_back(std::move(winkey_driver));
}
#endif // XE_PLATFORM_WIN32
if (drivers.empty()) {
// Fallback to nop if none created.
drivers.emplace_back(xe::hid::nop::Create(window));
}
}
return drivers;
}
std::unique_ptr<xe::ui::GraphicsContext> CreateDemoContext(
xe::ui::Window* window) {
return xe::ui::gl::GLContext::Create(window);
@ -70,7 +109,11 @@ int hid_demo_main(const std::vector<std::wstring>& args) {
imgui_drawer_->SetupDefaultInput();
// Initialize input system and all drivers.
input_system_ = xe::hid::InputSystem::Create(window.get());
input_system_ = std::make_unique<xe::hid::InputSystem>(window.get());
auto drivers = CreateInputDrivers(window.get());
for (size_t i = 0; i < drivers.size(); ++i) {
input_system_->AddDriver(std::move(drivers[i]));
}
});
window->on_painting.AddListener([&](xe::ui::UIEvent* e) {

View File

@ -8,5 +8,3 @@
*/
#include "xenia/hid/hid_flags.h"
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");

View File

@ -12,6 +12,4 @@
#include <gflags/gflags.h>
DECLARE_string(hid);
#endif // XENIA_HID_HID_FLAGS_H_

View File

@ -12,8 +12,7 @@
namespace xe {
namespace hid {
InputDriver::InputDriver(InputSystem* input_system)
: input_system_(input_system) {}
InputDriver::InputDriver(xe::ui::Window* window) : window_(window) {}
InputDriver::~InputDriver() = default;

View File

@ -13,6 +13,12 @@
#include "xenia/hid/input.h"
#include "xenia/xbox.h"
namespace xe {
namespace ui {
class Window;
} // namespace ui
} // namespace xe
namespace xe {
namespace hid {
@ -33,9 +39,9 @@ class InputDriver {
X_INPUT_KEYSTROKE* out_keystroke) = 0;
protected:
explicit InputDriver(InputSystem* input_system);
explicit InputDriver(xe::ui::Window* window);
InputSystem* input_system_ = nullptr;
xe::ui::Window* window_ = nullptr;
};
} // namespace hid

View File

@ -13,54 +13,9 @@
#include "xenia/hid/hid_flags.h"
#include "xenia/hid/input_driver.h"
#include "xenia/hid/nop/nop_hid.h"
#if XE_PLATFORM_WIN32
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h"
#endif // XE_PLATFORM_WIN32
namespace xe {
namespace hid {
std::unique_ptr<InputSystem> InputSystem::Create(xe::ui::Window* window) {
std::unique_ptr<InputSystem> input_system(new InputSystem(window));
if (FLAGS_hid.compare("nop") == 0) {
input_system->AddDriver(xe::hid::nop::Create(input_system.get()));
#if XE_PLATFORM_WIN32
} else if (FLAGS_hid.compare("winkey") == 0) {
input_system->AddDriver(xe::hid::winkey::Create(input_system.get()));
} else if (FLAGS_hid.compare("xinput") == 0) {
input_system->AddDriver(xe::hid::xinput::Create(input_system.get()));
#endif // WIN32
} else {
// Create all available.
bool any_created = false;
// NOTE: in any mode we create as many as we can, falling back to nop.
#if XE_PLATFORM_WIN32
auto xinput_driver = xe::hid::xinput::Create(input_system.get());
if (xinput_driver) {
input_system->AddDriver(std::move(xinput_driver));
any_created = true;
}
auto winkey_driver = xe::hid::winkey::Create(input_system.get());
if (winkey_driver) {
input_system->AddDriver(std::move(winkey_driver));
any_created = true;
}
#endif // WIN32
// Fallback to nop if none created.
if (!any_created) {
input_system->AddDriver(xe::hid::nop::Create(input_system.get()));
}
}
return input_system;
}
InputSystem::InputSystem(xe::ui::Window* window) : window_(window) {}
InputSystem::~InputSystem() = default;

View File

@ -14,6 +14,7 @@
#include <vector>
#include "xenia/hid/input.h"
#include "xenia/hid/input_driver.h"
#include "xenia/xbox.h"
namespace xe {
@ -25,14 +26,11 @@ class Window;
namespace xe {
namespace hid {
class InputDriver;
class InputSystem {
public:
explicit InputSystem(xe::ui::Window* window);
~InputSystem();
static std::unique_ptr<InputSystem> Create(xe::ui::Window* window);
xe::ui::Window* window() const { return window_; }
X_STATUS Setup();
@ -47,8 +45,6 @@ class InputSystem {
X_INPUT_KEYSTROKE* out_keystroke);
private:
explicit InputSystem(xe::ui::Window* window);
xe::ui::Window* window_ = nullptr;
std::vector<std::unique_ptr<InputDriver>> drivers_;

View File

@ -15,8 +15,8 @@ namespace xe {
namespace hid {
namespace nop {
std::unique_ptr<InputDriver> Create(InputSystem* input_system) {
return std::make_unique<NopInputDriver>(input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window) {
return std::make_unique<NopInputDriver>(window);
}
} // namespace nop

View File

@ -18,7 +18,7 @@ namespace xe {
namespace hid {
namespace nop {
std::unique_ptr<InputDriver> Create(InputSystem* input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window);
} // namespace nop
} // namespace hid

View File

@ -15,10 +15,9 @@ namespace xe {
namespace hid {
namespace nop {
NopInputDriver::NopInputDriver(InputSystem* input_system)
: InputDriver(input_system) {}
NopInputDriver::NopInputDriver(xe::ui::Window* window) : InputDriver(window) {}
NopInputDriver::~NopInputDriver() {}
NopInputDriver::~NopInputDriver() = default;
X_STATUS NopInputDriver::Setup() { return X_STATUS_SUCCESS; }

View File

@ -18,7 +18,7 @@ namespace nop {
class NopInputDriver : public InputDriver {
public:
explicit NopInputDriver(InputSystem* input_system);
explicit NopInputDriver(xe::ui::Window* window);
~NopInputDriver() override;
X_STATUS Setup() override;

View File

@ -15,8 +15,8 @@ namespace xe {
namespace hid {
namespace winkey {
std::unique_ptr<InputDriver> Create(InputSystem* input_system) {
return std::make_unique<WinKeyInputDriver>(input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window) {
return std::make_unique<WinKeyInputDriver>(window);
}
} // namespace winkey

View File

@ -18,7 +18,7 @@ namespace xe {
namespace hid {
namespace winkey {
std::unique_ptr<InputDriver> Create(InputSystem* input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window);
} // namespace winkey
} // namespace hid

View File

@ -19,10 +19,10 @@ namespace xe {
namespace hid {
namespace winkey {
WinKeyInputDriver::WinKeyInputDriver(InputSystem* input_system)
: InputDriver(input_system), packet_number_(1) {
WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window)
: InputDriver(window), packet_number_(1) {
// Register a key listener.
input_system_->window()->on_key_down.AddListener([this](ui::KeyEvent* evt) {
window_->on_key_down.AddListener([this](ui::KeyEvent* evt) {
auto global_lock = global_critical_region_.Acquire();
KeyEvent key;
@ -32,7 +32,7 @@ WinKeyInputDriver::WinKeyInputDriver(InputSystem* input_system)
key.repeat_count = evt->repeat_count();
key_events_.push(key);
});
input_system_->window()->on_key_up.AddListener([this](ui::KeyEvent* evt) {
window_->on_key_up.AddListener([this](ui::KeyEvent* evt) {
auto global_lock = global_critical_region_.Acquire();
KeyEvent key;
@ -89,7 +89,7 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index,
int16_t thumb_rx = 0;
int16_t thumb_ry = 0;
if (input_system_->window()->has_focus()) {
if (window_->has_focus()) {
if (IS_KEY_TOGGLED(VK_CAPITAL)) {
// dpad toggled
if (IS_KEY_DOWN(0x41)) {

View File

@ -21,7 +21,7 @@ namespace winkey {
class WinKeyInputDriver : public InputDriver {
public:
explicit WinKeyInputDriver(InputSystem* input_system);
explicit WinKeyInputDriver(xe::ui::Window* window);
~WinKeyInputDriver() override;
X_STATUS Setup() override;

View File

@ -15,8 +15,8 @@ namespace xe {
namespace hid {
namespace xinput {
std::unique_ptr<InputDriver> Create(InputSystem* input_system) {
return std::make_unique<XInputInputDriver>(input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window) {
return std::make_unique<XInputInputDriver>(window);
}
} // namespace xinput

View File

@ -18,7 +18,7 @@ namespace xe {
namespace hid {
namespace xinput {
std::unique_ptr<InputDriver> Create(InputSystem* input_system);
std::unique_ptr<InputDriver> Create(xe::ui::Window* window);
} // namespace xinput
} // namespace hid

View File

@ -19,8 +19,8 @@ namespace xe {
namespace hid {
namespace xinput {
XInputInputDriver::XInputInputDriver(InputSystem* input_system)
: InputDriver(input_system) {
XInputInputDriver::XInputInputDriver(xe::ui::Window* window)
: InputDriver(window) {
XInputEnable(TRUE);
}

View File

@ -18,7 +18,7 @@ namespace xinput {
class XInputInputDriver : public InputDriver {
public:
explicit XInputInputDriver(InputSystem* input_system);
explicit XInputInputDriver(xe::ui::Window* window);
~XInputInputDriver() override;
X_STATUS Setup() override;