From 4079a7bb8a911f36593fd2817ddcdf58df49a88e Mon Sep 17 00:00:00 2001 From: emoose Date: Thu, 2 Jan 2020 23:59:50 +0000 Subject: [PATCH] [HID] Allow winkey driver to use the first unused user index This removes the user_index == 0 requirement from the InputSystem code, and updates WinKeyInputDriver to use the first non-connected user index if it can. Eg. if you had 2 XInput controllers plugged in, those two will take up user index 0 and 1, and keyboard will take user index 2. If all four indexes are taken up already, the WinKey driver will be disabled. (This is done by passing already-setup drivers to each drivers Setup function: since WinKey is the last to be setup, this'll let it query the XInput driver and find which user_index it should handle) --- src/xenia/app/xenia_main.cc | 2 +- src/xenia/hid/input_driver.h | 6 ++- src/xenia/hid/nop/nop_input_driver.cc | 5 ++- src/xenia/hid/nop/nop_input_driver.h | 3 +- src/xenia/hid/winkey/winkey_input_driver.cc | 41 ++++++++++++++++++--- src/xenia/hid/winkey/winkey_input_driver.h | 7 +++- src/xenia/hid/xinput/xinput_input_driver.cc | 3 +- src/xenia/hid/xinput/xinput_input_driver.h | 3 +- src/xenia/kernel/xam/xam_input.cc | 19 ++++++---- 9 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index 10a626efd..fa4cf1fec 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -195,7 +195,7 @@ std::vector> CreateInputDrivers( #endif // XE_PLATFORM_WIN32 factory.Add("sdl", xe::hid::sdl::Create); for (auto& driver : factory.CreateAll(cvars::hid, window)) { - if (XSUCCEEDED(driver->Setup())) { + if (XSUCCEEDED(driver->Setup(drivers))) { drivers.emplace_back(std::move(driver)); } } diff --git a/src/xenia/hid/input_driver.h b/src/xenia/hid/input_driver.h index 6de322ab1..5b18cc076 100644 --- a/src/xenia/hid/input_driver.h +++ b/src/xenia/hid/input_driver.h @@ -10,6 +10,9 @@ #ifndef XENIA_HID_INPUT_DRIVER_H_ #define XENIA_HID_INPUT_DRIVER_H_ +#include +#include + #include "xenia/hid/input.h" #include "xenia/xbox.h" @@ -28,7 +31,8 @@ class InputDriver { public: virtual ~InputDriver(); - virtual X_STATUS Setup() = 0; + virtual X_STATUS Setup( + std::vector>& drivers) = 0; virtual X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) = 0; diff --git a/src/xenia/hid/nop/nop_input_driver.cc b/src/xenia/hid/nop/nop_input_driver.cc index bd22d65e2..31fb71fe2 100644 --- a/src/xenia/hid/nop/nop_input_driver.cc +++ b/src/xenia/hid/nop/nop_input_driver.cc @@ -19,7 +19,10 @@ NopInputDriver::NopInputDriver(xe::ui::Window* window) : InputDriver(window) {} NopInputDriver::~NopInputDriver() = default; -X_STATUS NopInputDriver::Setup() { return X_STATUS_SUCCESS; } +X_STATUS NopInputDriver::Setup( + std::vector>& drivers) { + return X_STATUS_SUCCESS; +} // TODO(benvanik): spoof a device so that games don't stop waiting for // a controller to be plugged in. diff --git a/src/xenia/hid/nop/nop_input_driver.h b/src/xenia/hid/nop/nop_input_driver.h index be949f016..4df7585c9 100644 --- a/src/xenia/hid/nop/nop_input_driver.h +++ b/src/xenia/hid/nop/nop_input_driver.h @@ -21,7 +21,8 @@ class NopInputDriver : public InputDriver { explicit NopInputDriver(xe::ui::Window* window); ~NopInputDriver() override; - X_STATUS Setup() override; + X_STATUS Setup( + std::vector>& drivers) override; X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) override; diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index 30ce09309..1a017d553 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -45,11 +45,40 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window) WinKeyInputDriver::~WinKeyInputDriver() = default; -X_STATUS WinKeyInputDriver::Setup() { return X_STATUS_SUCCESS; } +X_STATUS WinKeyInputDriver::Setup( + std::vector>& drivers) { + int index = 0; + X_INPUT_STATE state; + + // Search already added drivers for an index that none of them can use + while (index < 4) { + bool not_connected = false; + + for (auto& driver : drivers) { + if (driver.get()->GetState(index, &state) != + X_ERROR_DEVICE_NOT_CONNECTED) { + not_connected = false; + break; + } + not_connected = true; + } + + if (not_connected) { + user_index_ = index; + return X_STATUS_SUCCESS; + } + index++; + } + + // All indexes are in use... + user_index_ = -1; + // Return error so this driver won't get used + return X_ERROR_DEVICE_NOT_CONNECTED; +} X_RESULT WinKeyInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) { - if (user_index != 0) { + if (user_index != user_index_) { return X_ERROR_DEVICE_NOT_CONNECTED; } @@ -74,7 +103,7 @@ X_RESULT WinKeyInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags, X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, X_INPUT_STATE* out_state) { - if (user_index != 0) { + if (user_index != user_index_) { return X_ERROR_DEVICE_NOT_CONNECTED; } @@ -214,7 +243,7 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, X_RESULT WinKeyInputDriver::SetState(uint32_t user_index, X_INPUT_VIBRATION* vibration) { - if (user_index != 0) { + if (user_index != user_index_) { return X_ERROR_DEVICE_NOT_CONNECTED; } @@ -223,7 +252,7 @@ X_RESULT WinKeyInputDriver::SetState(uint32_t user_index, X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE* out_keystroke) { - if (user_index != 0) { + if (user_index != user_index_) { return X_ERROR_DEVICE_NOT_CONNECTED; } @@ -356,7 +385,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, out_keystroke->virtual_key = virtual_key; out_keystroke->unicode = unicode; out_keystroke->flags = keystroke_flags; - out_keystroke->user_index = 0; + out_keystroke->user_index = user_index_; out_keystroke->hid_code = hid_code; // X_ERROR_EMPTY if no new keys diff --git a/src/xenia/hid/winkey/winkey_input_driver.h b/src/xenia/hid/winkey/winkey_input_driver.h index 2bc923f39..36ba37551 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.h +++ b/src/xenia/hid/winkey/winkey_input_driver.h @@ -24,7 +24,8 @@ class WinKeyInputDriver : public InputDriver { explicit WinKeyInputDriver(xe::ui::Window* window); ~WinKeyInputDriver() override; - X_STATUS Setup() override; + X_STATUS Setup( + std::vector>& drivers) override; X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) override; @@ -33,6 +34,8 @@ class WinKeyInputDriver : public InputDriver { X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE* out_keystroke) override; + void user_index(uint32_t index) { user_index_ = index; } + protected: struct KeyEvent { int vkey = 0; @@ -45,6 +48,8 @@ class WinKeyInputDriver : public InputDriver { std::queue key_events_; uint32_t packet_number_; + + uint32_t user_index_ = 1; }; } // namespace winkey diff --git a/src/xenia/hid/xinput/xinput_input_driver.cc b/src/xenia/hid/xinput/xinput_input_driver.cc index 830daa0e4..1251b04f4 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.cc +++ b/src/xenia/hid/xinput/xinput_input_driver.cc @@ -42,7 +42,8 @@ XInputInputDriver::~XInputInputDriver() { } } -X_STATUS XInputInputDriver::Setup() { +X_STATUS XInputInputDriver::Setup( + std::vector>& drivers) { HMODULE module = LoadLibraryW(L"xinput1_4.dll"); if (!module) { module = LoadLibraryW(L"xinput1_3.dll"); diff --git a/src/xenia/hid/xinput/xinput_input_driver.h b/src/xenia/hid/xinput/xinput_input_driver.h index dcde26197..ac586bf55 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.h +++ b/src/xenia/hid/xinput/xinput_input_driver.h @@ -21,7 +21,8 @@ class XInputInputDriver : public InputDriver { explicit XInputInputDriver(xe::ui::Window* window); ~XInputInputDriver() override; - X_STATUS Setup() override; + X_STATUS Setup( + std::vector>& drivers) override; X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) override; diff --git a/src/xenia/kernel/xam/xam_input.cc b/src/xenia/kernel/xam/xam_input.cc index 7aead257d..08bd723df 100644 --- a/src/xenia/kernel/xam/xam_input.cc +++ b/src/xenia/kernel/xam/xam_input.cc @@ -101,7 +101,7 @@ dword_result_t XamInputGetState(dword_t user_index, dword_t flags, } auto input_system = kernel_state()->emulator()->input_system(); - return input_system->GetState(user_index, input_state); + return input_system->GetState(actual_user_index, input_state); } DECLARE_XAM_EXPORT1(XamInputGetState, kInput, kImplemented); @@ -119,7 +119,7 @@ dword_result_t XamInputSetState(dword_t user_index, dword_t unk, } auto input_system = kernel_state()->emulator()->input_system(); - return input_system->SetState(user_index, vibration); + return input_system->SetState(actual_user_index, vibration); } DECLARE_XAM_EXPORT1(XamInputSetState, kInput, kImplemented); @@ -182,12 +182,17 @@ X_HRESULT_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk, // Games check the result - usually with some masking. // If this function fails they assume zero, so let's fail AND // set zero just to be safe. - *out_ptr = 0; - if (!user_index || (user_index & 0xFF) == 0xFF) { - return X_E_SUCCESS; - } else { - return X_E_DEVICE_NOT_CONNECTED; + // *out_ptr = 0; + + uint32_t actual_user_index = user_index; + if ((user_index & 0xFF) == 0xFF) { + // Always pin user to 0. + actual_user_index = 0; } + + auto input_system = kernel_state()->emulator()->input_system(); + X_INPUT_STATE state; + return input_system->GetState(actual_user_index, &state); } DECLARE_XAM_EXPORT1(XamUserGetDeviceContext, kInput, kStub);