mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
InputCommon: XInput cleanups.
This commit is contained in:
parent
86e8745169
commit
e7400cafd2
@ -10,22 +10,13 @@
|
||||
|
||||
namespace ciface::XInput
|
||||
{
|
||||
class Battery : public Core::Device::Input
|
||||
struct ButtonDef
|
||||
{
|
||||
public:
|
||||
Battery(const ControlState* level) : m_level(*level) {}
|
||||
std::string GetName() const override { return "Battery"; }
|
||||
ControlState GetState() const override { return m_level; }
|
||||
|
||||
private:
|
||||
const ControlState& m_level;
|
||||
const char* name;
|
||||
WORD bitmask;
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char* const name;
|
||||
const WORD bitmask;
|
||||
} named_buttons[] = {{"Button A", XINPUT_GAMEPAD_A},
|
||||
static constexpr std::array<ButtonDef, 15> named_buttons{{
|
||||
{"Button A", XINPUT_GAMEPAD_A},
|
||||
{"Button B", XINPUT_GAMEPAD_B},
|
||||
{"Button X", XINPUT_GAMEPAD_X},
|
||||
{"Button Y", XINPUT_GAMEPAD_Y},
|
||||
@ -39,13 +30,99 @@ static const struct
|
||||
{"Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER},
|
||||
{"Guide", XINPUT_GAMEPAD_GUIDE},
|
||||
{"Thumb L", XINPUT_GAMEPAD_LEFT_THUMB},
|
||||
{"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB}};
|
||||
{"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB},
|
||||
}};
|
||||
|
||||
static const char* const named_triggers[] = {"Trigger L", "Trigger R"};
|
||||
static constexpr std::array named_triggers{"Trigger L", "Trigger R"};
|
||||
|
||||
static const char* const named_axes[] = {"Left X", "Left Y", "Right X", "Right Y"};
|
||||
static constexpr std::array named_axes{"Left X", "Left Y", "Right X", "Right Y"};
|
||||
|
||||
static const char* const named_motors[] = {"Motor L", "Motor R"};
|
||||
static constexpr std::array named_motors{"Motor L", "Motor R"};
|
||||
|
||||
class Button final : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Button(u8 index, const WORD& buttons) : m_buttons(buttons), m_index(index) {}
|
||||
std::string GetName() const override { return named_buttons[m_index].name; }
|
||||
ControlState GetState() const override
|
||||
{
|
||||
return (m_buttons & named_buttons[m_index].bitmask) > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const WORD& m_buttons;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Axis final : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Axis(u8 index, const SHORT& axis, SHORT range) : m_axis(axis), m_range(range), m_index(index) {}
|
||||
std::string GetName() const override
|
||||
{
|
||||
return std::string(named_axes[m_index]) + (m_range < 0 ? '-' : '+');
|
||||
}
|
||||
ControlState GetState() const override { return ControlState(m_axis) / m_range; }
|
||||
|
||||
private:
|
||||
const SHORT& m_axis;
|
||||
const SHORT m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Trigger final : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Trigger(u8 index, const BYTE& trigger, BYTE range)
|
||||
: m_trigger(trigger), m_range(range), m_index(index)
|
||||
{
|
||||
}
|
||||
std::string GetName() const override { return named_triggers[m_index]; }
|
||||
ControlState GetState() const override { return ControlState(m_trigger) / m_range; }
|
||||
|
||||
private:
|
||||
const BYTE& m_trigger;
|
||||
const BYTE m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Motor final : public Core::Device::Output
|
||||
{
|
||||
public:
|
||||
Motor(u8 index, Device* parent, WORD& motor, WORD range)
|
||||
: m_motor(motor), m_range(range), m_index(index), m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
std::string GetName() const override { return named_motors[m_index]; }
|
||||
void SetState(ControlState state) override
|
||||
{
|
||||
const auto old_value = m_motor;
|
||||
m_motor = (WORD)(state * m_range);
|
||||
|
||||
// Only update if the state changed.
|
||||
if (m_motor != old_value)
|
||||
m_parent->UpdateMotors();
|
||||
}
|
||||
|
||||
private:
|
||||
WORD& m_motor;
|
||||
const WORD m_range;
|
||||
const u8 m_index;
|
||||
Device* m_parent;
|
||||
};
|
||||
|
||||
class Battery final : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Battery(const ControlState* level) : m_level(*level) {}
|
||||
std::string GetName() const override { return "Battery"; }
|
||||
ControlState GetState() const override { return m_level; }
|
||||
bool IsDetectable() override { return false; }
|
||||
|
||||
private:
|
||||
const ControlState& m_level;
|
||||
};
|
||||
|
||||
static HMODULE hXInput = nullptr;
|
||||
|
||||
@ -59,7 +136,7 @@ static XInputSetState_t PXInputSetState = nullptr;
|
||||
static XInputGetState_t PXInputGetState = nullptr;
|
||||
static XInputGetBatteryInformation_t PXInputGetBatteryInformation = nullptr;
|
||||
|
||||
static bool haveGuideButton = false;
|
||||
static bool s_have_guide_button = false;
|
||||
|
||||
void Init()
|
||||
{
|
||||
@ -86,9 +163,10 @@ void Init()
|
||||
// Ordinal 100 is the same as XInputGetState, except it doesn't dummy out the guide
|
||||
// button info. Try loading it and fall back if needed.
|
||||
PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, (LPCSTR)100);
|
||||
if (PXInputGetState)
|
||||
haveGuideButton = true;
|
||||
else
|
||||
|
||||
s_have_guide_button = PXInputGetState != nullptr;
|
||||
|
||||
if (!PXInputGetState)
|
||||
PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, "XInputGetState");
|
||||
|
||||
if (!PXInputGetCapabilities || !PXInputSetState || !PXInputGetState ||
|
||||
@ -128,35 +206,33 @@ Device::Device(const XINPUT_CAPABILITIES& caps, u8 index) : m_subtype(caps.SubTy
|
||||
// XInputGetCaps can be broken on some devices, so we'll just ignore it
|
||||
// and assume all gamepad + vibration capabilities are supported
|
||||
|
||||
// get supported buttons
|
||||
for (int i = 0; i != sizeof(named_buttons) / sizeof(*named_buttons); ++i)
|
||||
// Buttons.
|
||||
for (size_t i = 0; i != size(named_buttons); ++i)
|
||||
{
|
||||
// Only add guide button if we have the 100 ordinal XInputGetState
|
||||
if (!(named_buttons[i].bitmask & XINPUT_GAMEPAD_GUIDE) || haveGuideButton)
|
||||
AddInput(new Button(i, m_state_in.Gamepad.wButtons));
|
||||
// Only add guide button if we have the 100 ordinal XInputGetState.
|
||||
if (named_buttons[i].bitmask == XINPUT_GAMEPAD_GUIDE && !s_have_guide_button)
|
||||
continue;
|
||||
|
||||
AddInput(new Button(u8(i), m_state_in.Gamepad.wButtons));
|
||||
}
|
||||
|
||||
// get supported triggers
|
||||
for (int i = 0; i != sizeof(named_triggers) / sizeof(*named_triggers); ++i)
|
||||
{
|
||||
AddInput(new Trigger(i, (&m_state_in.Gamepad.bLeftTrigger)[i], 255));
|
||||
}
|
||||
// Triggers.
|
||||
for (size_t i = 0; i != size(named_triggers); ++i)
|
||||
AddInput(new Trigger(u8(i), (&m_state_in.Gamepad.bLeftTrigger)[i], 255));
|
||||
|
||||
// get supported axes
|
||||
for (int i = 0; i != sizeof(named_axes) / sizeof(*named_axes); ++i)
|
||||
// Axes.
|
||||
for (size_t i = 0; i != size(named_axes); ++i)
|
||||
{
|
||||
const SHORT& ax = (&m_state_in.Gamepad.sThumbLX)[i];
|
||||
|
||||
// each axis gets a negative and a positive input instance associated with it
|
||||
AddInput(new Axis(i, ax, -32768));
|
||||
AddInput(new Axis(i, ax, 32767));
|
||||
// Each axis gets a negative and a positive input instance associated with it.
|
||||
AddInput(new Axis(u8(i), ax, -32768));
|
||||
AddInput(new Axis(u8(i), ax, 32767));
|
||||
}
|
||||
|
||||
// get supported motors
|
||||
for (int i = 0; i != sizeof(named_motors) / sizeof(*named_motors); ++i)
|
||||
{
|
||||
AddOutput(new Motor(i, this, (&m_state_out.wLeftMotorSpeed)[i], 65535));
|
||||
}
|
||||
// Rumble motors.
|
||||
for (size_t i = 0; i != size(named_motors); ++i)
|
||||
AddOutput(new Motor(u8(i), this, (&m_state_out.wLeftMotorSpeed)[i], 65535));
|
||||
|
||||
AddInput(new Battery(&m_battery_level));
|
||||
}
|
||||
@ -189,8 +265,6 @@ std::string Device::GetSource() const
|
||||
return "XInput";
|
||||
}
|
||||
|
||||
// Update I/O
|
||||
|
||||
void Device::UpdateInput()
|
||||
{
|
||||
PXInputGetState(m_index, &m_state_in);
|
||||
@ -217,14 +291,7 @@ void Device::UpdateInput()
|
||||
|
||||
void Device::UpdateMotors()
|
||||
{
|
||||
// this if statement is to make rumble work better when multiple ControllerInterfaces are using
|
||||
// the device
|
||||
// only calls XInputSetState if the state changed
|
||||
if (memcmp(&m_state_out, &m_current_state_out, sizeof(m_state_out)))
|
||||
{
|
||||
m_current_state_out = m_state_out;
|
||||
PXInputSetState(m_index, &m_state_out);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> Device::GetPreferredId() const
|
||||
@ -232,48 +299,4 @@ std::optional<int> Device::GetPreferredId() const
|
||||
return m_index;
|
||||
}
|
||||
|
||||
// GET name/source/id
|
||||
|
||||
std::string Device::Button::GetName() const
|
||||
{
|
||||
return named_buttons[m_index].name;
|
||||
}
|
||||
|
||||
std::string Device::Axis::GetName() const
|
||||
{
|
||||
return std::string(named_axes[m_index]) + (m_range < 0 ? '-' : '+');
|
||||
}
|
||||
|
||||
std::string Device::Trigger::GetName() const
|
||||
{
|
||||
return named_triggers[m_index];
|
||||
}
|
||||
|
||||
std::string Device::Motor::GetName() const
|
||||
{
|
||||
return named_motors[m_index];
|
||||
}
|
||||
|
||||
// GET / SET STATES
|
||||
|
||||
ControlState Device::Button::GetState() const
|
||||
{
|
||||
return (m_buttons & named_buttons[m_index].bitmask) > 0;
|
||||
}
|
||||
|
||||
ControlState Device::Trigger::GetState() const
|
||||
{
|
||||
return ControlState(m_trigger) / m_range;
|
||||
}
|
||||
|
||||
ControlState Device::Axis::GetState() const
|
||||
{
|
||||
return ControlState(m_axis) / m_range;
|
||||
}
|
||||
|
||||
void Device::Motor::SetState(ControlState state)
|
||||
{
|
||||
m_motor = (WORD)(state * m_range);
|
||||
m_parent->UpdateMotors();
|
||||
}
|
||||
} // namespace ciface::XInput
|
||||
|
@ -24,82 +24,22 @@ void Init();
|
||||
void PopulateDevices();
|
||||
void DeInit();
|
||||
|
||||
class Device : public Core::Device
|
||||
class Device final : public Core::Device
|
||||
{
|
||||
private:
|
||||
class Button : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Button(u8 index, const WORD& buttons) : m_buttons(buttons), m_index(index) {}
|
||||
std::string GetName() const override;
|
||||
ControlState GetState() const override;
|
||||
|
||||
private:
|
||||
const WORD& m_buttons;
|
||||
u8 m_index;
|
||||
};
|
||||
|
||||
class Axis : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Axis(u8 index, const SHORT& axis, SHORT range) : m_axis(axis), m_range(range), m_index(index) {}
|
||||
std::string GetName() const override;
|
||||
ControlState GetState() const override;
|
||||
|
||||
private:
|
||||
const SHORT& m_axis;
|
||||
const SHORT m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Trigger : public Core::Device::Input
|
||||
{
|
||||
public:
|
||||
Trigger(u8 index, const BYTE& trigger, BYTE range)
|
||||
: m_trigger(trigger), m_range(range), m_index(index)
|
||||
{
|
||||
}
|
||||
std::string GetName() const override;
|
||||
ControlState GetState() const override;
|
||||
|
||||
private:
|
||||
const BYTE& m_trigger;
|
||||
const BYTE m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Motor : public Core::Device::Output
|
||||
{
|
||||
public:
|
||||
Motor(u8 index, Device* parent, WORD& motor, WORD range)
|
||||
: m_motor(motor), m_range(range), m_index(index), m_parent(parent)
|
||||
{
|
||||
}
|
||||
std::string GetName() const override;
|
||||
void SetState(ControlState state) override;
|
||||
|
||||
private:
|
||||
WORD& m_motor;
|
||||
const WORD m_range;
|
||||
const u8 m_index;
|
||||
Device* m_parent;
|
||||
};
|
||||
|
||||
public:
|
||||
void UpdateInput() override;
|
||||
|
||||
Device(const XINPUT_CAPABILITIES& capabilities, u8 index);
|
||||
|
||||
std::string GetName() const final override;
|
||||
std::string GetSource() const final override;
|
||||
std::optional<int> GetPreferredId() const final override;
|
||||
std::string GetName() const override;
|
||||
std::string GetSource() const override;
|
||||
std::optional<int> GetPreferredId() const override;
|
||||
|
||||
void UpdateInput() override;
|
||||
|
||||
void UpdateMotors();
|
||||
|
||||
private:
|
||||
XINPUT_STATE m_state_in{};
|
||||
XINPUT_VIBRATION m_state_out{};
|
||||
XINPUT_VIBRATION m_current_state_out{};
|
||||
ControlState m_battery_level{};
|
||||
const BYTE m_subtype;
|
||||
const u8 m_index;
|
||||
|
Loading…
Reference in New Issue
Block a user