From 086d7e9da7309e2c987fac16deb7993ad6e1e4a6 Mon Sep 17 00:00:00 2001 From: gibbed Date: Thu, 22 Nov 2018 10:46:48 -0600 Subject: [PATCH] [Input] Dynamically link to XInput. --- src/xenia/app/xenia_main.cc | 13 +++- src/xenia/hid/xinput/xinput_input_driver.cc | 74 ++++++++++++++++----- src/xenia/hid/xinput/xinput_input_driver.h | 6 ++ src/xenia/xbox.h | 2 + 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index ee474485b..827584af0 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -119,11 +119,18 @@ std::vector> CreateInputDrivers( 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)); + } + for (auto it = drivers.begin(); it != drivers.end();) { + if (XFAILED((*it)->Setup())) { + it = drivers.erase(it); + } else { + ++it; } } + if (drivers.empty()) { + // Fallback to nop if none created. + drivers.emplace_back(xe::hid::nop::Create(window)); + } return drivers; } diff --git a/src/xenia/hid/xinput/xinput_input_driver.cc b/src/xenia/hid/xinput/xinput_input_driver.cc index 937b66801..9e6d2f90c 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.cc +++ b/src/xenia/hid/xinput/xinput_input_driver.cc @@ -21,26 +21,64 @@ namespace hid { namespace xinput { XInputInputDriver::XInputInputDriver(xe::ui::Window* window) - : InputDriver(window) { -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8 && _WIN32_WINNT < _WIN32_WINNT_WIN10) - // TODO(gibbed): Is this necessary? - XInputEnable(TRUE); -#endif -} + : InputDriver(window), + module_(nullptr), + XInputGetCapabilities_(nullptr), + XInputGetState_(nullptr), + XInputGetKeystroke_(nullptr), + XInputSetState_(nullptr), + XInputEnable_(nullptr) {} XInputInputDriver::~XInputInputDriver() { -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8 && _WIN32_WINNT < _WIN32_WINNT_WIN10) - // TODO(gibbed): Is this necessary? - XInputEnable(FALSE); -#endif + if (module_) { + FreeLibrary((HMODULE)module_); + module_ = nullptr; + XInputGetCapabilities_ = nullptr; + XInputGetState_ = nullptr; + XInputGetKeystroke_ = nullptr; + XInputSetState_ = nullptr; + XInputEnable_ = nullptr; + } } -X_STATUS XInputInputDriver::Setup() { return X_STATUS_SUCCESS; } +X_STATUS XInputInputDriver::Setup() { + HMODULE module = LoadLibraryW(L"xinput1_4.dll"); + if (!module) { + module = LoadLibraryW(L"xinput1_3.dll"); + } + if (!module) { + return X_STATUS_DLL_NOT_FOUND; + } + + // Required. + auto xigc = GetProcAddress(module, "XInputGetCapabilities"); + auto xigs = GetProcAddress(module, "XInputGetState"); + auto xigk = GetProcAddress(module, "XInputGetKeystroke"); + auto xiss = GetProcAddress(module, "XInputSetState"); + + // Not required. + auto xie = GetProcAddress(module, "XInputEnable"); + + // Only fail when we don't have the bare essentials; + if (!xigc || !xigs || !xigk || !xiss) { + FreeLibrary(module); + return X_STATUS_PROCEDURE_NOT_FOUND; + } + + module_ = module; + XInputGetCapabilities_ = xigc; + XInputGetState_ = xigs; + XInputGetKeystroke_ = xigk; + XInputSetState_ = xiss; + XInputEnable_ = xie; + return X_STATUS_SUCCESS; +} X_RESULT XInputInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) { XINPUT_CAPABILITIES native_caps; - DWORD result = XInputGetCapabilities(user_index, flags, &native_caps); + auto xigc = (decltype(&XInputGetCapabilities))XInputGetCapabilities_; + DWORD result = xigc(user_index, flags, &native_caps); if (result) { return result; } @@ -65,7 +103,8 @@ X_RESULT XInputInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags, X_RESULT XInputInputDriver::GetState(uint32_t user_index, X_INPUT_STATE* out_state) { XINPUT_STATE native_state; - DWORD result = XInputGetState(user_index, &native_state); + auto xigs = (decltype(&XInputGetState))XInputGetState_; + DWORD result = xigs(user_index, &native_state); if (result) { return result; } @@ -87,7 +126,8 @@ X_RESULT XInputInputDriver::SetState(uint32_t user_index, XINPUT_VIBRATION native_vibration; native_vibration.wLeftMotorSpeed = vibration->left_motor_speed; native_vibration.wRightMotorSpeed = vibration->right_motor_speed; - DWORD result = XInputSetState(user_index, &native_vibration); + auto xiss = (decltype(&XInputSetState))XInputSetState_; + DWORD result = xiss(user_index, &native_vibration); return result; } @@ -104,13 +144,15 @@ X_RESULT XInputInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, // So we first check if the device is connected via XInputGetCapabilities, so // we are not passing back an uninitialized X_INPUT_KEYSTROKE structure: XINPUT_CAPABILITIES caps; - result = XInputGetCapabilities(user_index, 0, &caps); + auto xigc = (decltype(&XInputGetCapabilities))XInputGetCapabilities_; + result = xigc(user_index, 0, &caps); if (result) { return result; } XINPUT_KEYSTROKE native_keystroke; - result = XInputGetKeystroke(user_index, 0, &native_keystroke); + auto xigk = (decltype(&XInputGetKeystroke))XInputGetKeystroke_; + result = xigk(user_index, 0, &native_keystroke); if (result) { return result; } diff --git a/src/xenia/hid/xinput/xinput_input_driver.h b/src/xenia/hid/xinput/xinput_input_driver.h index fbf75c422..dcde26197 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.h +++ b/src/xenia/hid/xinput/xinput_input_driver.h @@ -31,6 +31,12 @@ class XInputInputDriver : public InputDriver { X_INPUT_KEYSTROKE* out_keystroke) override; protected: + void* module_; + void* XInputGetCapabilities_; + void* XInputGetState_; + void* XInputGetKeystroke_; + void* XInputSetState_; + void* XInputEnable_; }; } // namespace xinput diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index a98edd24a..4884c260e 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -60,6 +60,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_OBJECT_NAME_COLLISION ((X_STATUS)0xC0000035L) #define X_STATUS_INVALID_PAGE_PROTECTION ((X_STATUS)0xC0000045L) #define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L) +#define X_STATUS_PROCEDURE_NOT_FOUND ((X_STATUS)0xC000007AL) #define X_STATUS_INSUFFICIENT_RESOURCES ((X_STATUS)0xC000009AL) #define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L) #define X_STATUS_NOT_SUPPORTED ((X_STATUS)0xC00000BBL) @@ -67,6 +68,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_INVALID_PARAMETER_2 ((X_STATUS)0xC00000F0L) #define X_STATUS_INVALID_PARAMETER_3 ((X_STATUS)0xC00000F1L) #define X_STATUS_DLL_NOT_FOUND ((X_STATUS)0xC0000135L) +#define X_STATUS_ENTRYPOINT_NOT_FOUND ((X_STATUS)0xC0000139L) #define X_STATUS_MAPPED_ALIGNMENT ((X_STATUS)0xC0000220L) #define X_STATUS_NOT_FOUND ((X_STATUS)0xC0000225L) #define X_STATUS_DRIVER_ORDINAL_NOT_FOUND ((X_STATUS)0xC0000262L)