[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)
This commit is contained in:
emoose 2020-01-02 23:59:50 +00:00 committed by illusion
parent 0a2489d44c
commit 4079a7bb8a
9 changed files with 69 additions and 20 deletions

View File

@ -195,7 +195,7 @@ std::vector<std::unique_ptr<hid::InputDriver>> 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));
}
}

View File

@ -10,6 +10,9 @@
#ifndef XENIA_HID_INPUT_DRIVER_H_
#define XENIA_HID_INPUT_DRIVER_H_
#include <memory>
#include <vector>
#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<std::unique_ptr<hid::InputDriver>>& drivers) = 0;
virtual X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags,
X_INPUT_CAPABILITIES* out_caps) = 0;

View File

@ -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<std::unique_ptr<InputDriver>>& drivers) {
return X_STATUS_SUCCESS;
}
// TODO(benvanik): spoof a device so that games don't stop waiting for
// a controller to be plugged in.

View File

@ -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<std::unique_ptr<hid::InputDriver>>& drivers) override;
X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags,
X_INPUT_CAPABILITIES* out_caps) override;

View File

@ -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<std::unique_ptr<hid::InputDriver>>& 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

View File

@ -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<std::unique_ptr<hid::InputDriver>>& 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<KeyEvent> key_events_;
uint32_t packet_number_;
uint32_t user_index_ = 1;
};
} // namespace winkey

View File

@ -42,7 +42,8 @@ XInputInputDriver::~XInputInputDriver() {
}
}
X_STATUS XInputInputDriver::Setup() {
X_STATUS XInputInputDriver::Setup(
std::vector<std::unique_ptr<InputDriver>>& drivers) {
HMODULE module = LoadLibraryW(L"xinput1_4.dll");
if (!module) {
module = LoadLibraryW(L"xinput1_3.dll");

View File

@ -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<std::unique_ptr<hid::InputDriver>>& drivers) override;
X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags,
X_INPUT_CAPABILITIES* out_caps) override;

View File

@ -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);