[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:
parent
919ee3ef55
commit
e3073f3c9e
|
@ -180,7 +180,7 @@ std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
|
|||
factory.Add("winkey", xe::hid::winkey::Create);
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
for (auto& driver : factory.CreateAll(cvars::hid, window)) {
|
||||
if (XSUCCEEDED(driver->Setup())) {
|
||||
if (XSUCCEEDED(driver->Setup(drivers))) {
|
||||
drivers.emplace_back(std::move(driver));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -50,10 +46,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_) {
|
||||
X_RESULT result = driver->GetState(user_index, out_state);
|
||||
|
@ -71,10 +63,6 @@ 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_) {
|
||||
X_RESULT result = driver->SetState(user_index, vibration);
|
||||
|
@ -92,10 +80,6 @@ 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_) {
|
||||
X_RESULT result = driver->GetKeystroke(user_index, flags, out_keystroke);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -41,7 +41,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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue