diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index 6f4d85595..bff6b6da3 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -194,7 +194,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/input_system.cc b/src/xenia/hid/input_system.cc index 2cfcb9781..a77d5b548 100644 --- a/src/xenia/hid/input_system.cc +++ b/src/xenia/hid/input_system.cc @@ -30,10 +30,6 @@ X_RESULT InputSystem::GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) { SCOPE_profile_cpu_f("hid"); - if (user_index && user_index != 0xFF) { - return X_ERROR_NO_SUCH_USER; - } - bool any_connected = false; for (auto& driver : drivers_) { X_RESULT result = driver->GetCapabilities(user_index, flags, out_caps); @@ -49,10 +45,6 @@ X_RESULT InputSystem::GetCapabilities(uint32_t user_index, uint32_t flags, X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE* out_state) { SCOPE_profile_cpu_f("hid"); - - if (user_index && user_index != 0xFF) { - return X_ERROR_NO_SUCH_USER; - } bool any_connected = false; for (auto& driver : drivers_) { @@ -70,10 +62,6 @@ X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE* out_state) { X_RESULT InputSystem::SetState(uint32_t user_index, X_INPUT_VIBRATION* vibration) { SCOPE_profile_cpu_f("hid"); - - if (user_index && user_index != 0xFF) { - return X_ERROR_NO_SUCH_USER; - } bool any_connected = false; for (auto& driver : drivers_) { @@ -91,10 +79,6 @@ X_RESULT InputSystem::SetState(uint32_t user_index, X_RESULT InputSystem::GetKeystroke(uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE* out_keystroke) { SCOPE_profile_cpu_f("hid"); - - if (user_index && user_index != 0xFF) { - return X_ERROR_NO_SUCH_USER; - } bool any_connected = false; for (auto& driver : drivers_) { 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 9e6d2f90c..a6dc6726e 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.cc +++ b/src/xenia/hid/xinput/xinput_input_driver.cc @@ -41,7 +41,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 eb83d27a9..04ccc9c00 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); @@ -183,11 +183,16 @@ X_HRESULT_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk, // 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; + + 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);