summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2020-02-09 09:29:00 -0500
committerGitHub <noreply@github.com>2020-02-09 09:29:00 -0500
commit5ab846ad121d2da5e0df1e7c29f32f01afcefe6d (patch)
treeee01c57f49a778e203f408c90f025d686eb969a6 /Source/Core/InputCommon/ControllerInterface
parent3cec5443cdaac2d889007c683a0cccaaef582397 (diff)
parente7400cafd2c3c708444cbc3dddaab872d0959d89 (diff)
Merge pull request #8614 from jordan-woyak/xinput-battery
InputCommon/XInput: Expose battery as input and cleanups.
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp268
-rw-r--r--Source/Core/InputCommon/ControllerInterface/XInput/XInput.h75
2 files changed, 171 insertions, 172 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
index cda20a08db..14462165fa 100644
--- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
@@ -10,43 +10,133 @@
namespace ciface::XInput
{
-static const struct
-{
- const char* const name;
- const WORD bitmask;
-} named_buttons[] = {{"Button A", XINPUT_GAMEPAD_A},
- {"Button B", XINPUT_GAMEPAD_B},
- {"Button X", XINPUT_GAMEPAD_X},
- {"Button Y", XINPUT_GAMEPAD_Y},
- {"Pad N", XINPUT_GAMEPAD_DPAD_UP},
- {"Pad S", XINPUT_GAMEPAD_DPAD_DOWN},
- {"Pad W", XINPUT_GAMEPAD_DPAD_LEFT},
- {"Pad E", XINPUT_GAMEPAD_DPAD_RIGHT},
- {"Start", XINPUT_GAMEPAD_START},
- {"Back", XINPUT_GAMEPAD_BACK},
- {"Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER},
- {"Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER},
- {"Guide", XINPUT_GAMEPAD_GUIDE},
- {"Thumb L", XINPUT_GAMEPAD_LEFT_THUMB},
- {"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB}};
-
-static const char* const named_triggers[] = {"Trigger L", "Trigger R"};
-
-static const char* const named_axes[] = {"Left X", "Left Y", "Right X", "Right Y"};
-
-static const char* const named_motors[] = {"Motor L", "Motor R"};
+struct ButtonDef
+{
+ const char* name;
+ WORD bitmask;
+};
+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},
+ {"Pad N", XINPUT_GAMEPAD_DPAD_UP},
+ {"Pad S", XINPUT_GAMEPAD_DPAD_DOWN},
+ {"Pad W", XINPUT_GAMEPAD_DPAD_LEFT},
+ {"Pad E", XINPUT_GAMEPAD_DPAD_RIGHT},
+ {"Start", XINPUT_GAMEPAD_START},
+ {"Back", XINPUT_GAMEPAD_BACK},
+ {"Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER},
+ {"Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER},
+ {"Guide", XINPUT_GAMEPAD_GUIDE},
+ {"Thumb L", XINPUT_GAMEPAD_LEFT_THUMB},
+ {"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB},
+}};
+
+static constexpr std::array named_triggers{"Trigger L", "Trigger R"};
+
+static constexpr std::array named_axes{"Left X", "Left Y", "Right X", "Right Y"};
+
+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;
typedef decltype(&XInputGetCapabilities) XInputGetCapabilities_t;
typedef decltype(&XInputSetState) XInputSetState_t;
typedef decltype(&XInputGetState) XInputGetState_t;
+typedef decltype(&XInputGetBatteryInformation) XInputGetBatteryInformation_t;
static XInputGetCapabilities_t PXInputGetCapabilities = nullptr;
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()
{
@@ -67,16 +157,20 @@ void Init()
PXInputGetCapabilities =
(XInputGetCapabilities_t)::GetProcAddress(hXInput, "XInputGetCapabilities");
PXInputSetState = (XInputSetState_t)::GetProcAddress(hXInput, "XInputSetState");
+ PXInputGetBatteryInformation =
+ (XInputGetBatteryInformation_t)::GetProcAddress(hXInput, "XInputGetBatteryInformation");
// 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)
+ if (!PXInputGetCapabilities || !PXInputSetState || !PXInputGetState ||
+ !PXInputGetBatteryInformation)
{
::FreeLibrary(hXInput);
hXInput = nullptr;
@@ -112,37 +206,35 @@ 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;
- // 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));
+ AddInput(new Button(u8(i), m_state_in.Gamepad.wButtons));
}
- // get supported axes
- for (int i = 0; i != sizeof(named_axes) / sizeof(*named_axes); ++i)
+ // Triggers.
+ for (size_t i = 0; i != size(named_triggers); ++i)
+ AddInput(new Trigger(u8(i), (&m_state_in.Gamepad.bLeftTrigger)[i], 255));
+
+ // 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));
- ZeroMemory(&m_state_in, sizeof(m_state_in));
+ AddInput(new Battery(&m_battery_level));
}
std::string Device::GetName() const
@@ -173,72 +265,38 @@ std::string Device::GetSource() const
return "XInput";
}
-// Update I/O
-
void Device::UpdateInput()
{
PXInputGetState(m_index, &m_state_in);
-}
-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)))
+ XINPUT_BATTERY_INFORMATION battery_info = {};
+ if (SUCCEEDED(PXInputGetBatteryInformation(m_index, BATTERY_DEVTYPE_GAMEPAD, &battery_info)))
{
- m_current_state_out = m_state_out;
- PXInputSetState(m_index, &m_state_out);
+ switch (battery_info.BatteryType)
+ {
+ case BATTERY_TYPE_DISCONNECTED:
+ case BATTERY_TYPE_UNKNOWN:
+ m_battery_level = 0;
+ break;
+ case BATTERY_TYPE_WIRED:
+ m_battery_level = BATTERY_INPUT_MAX_VALUE;
+ break;
+ default:
+ m_battery_level =
+ battery_info.BatteryLevel / ControlState(BATTERY_LEVEL_FULL) * BATTERY_INPUT_MAX_VALUE;
+ break;
+ }
}
}
-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
+void Device::UpdateMotors()
{
- return ControlState(m_trigger) / m_range;
+ PXInputSetState(m_index, &m_state_out);
}
-ControlState Device::Axis::GetState() const
+std::optional<int> Device::GetPreferredId() const
{
- return ControlState(m_axis) / m_range;
+ return m_index;
}
-void Device::Motor::SetState(ControlState state)
-{
- m_motor = (WORD)(state * m_range);
- m_parent->UpdateMotors();
-}
} // namespace ciface::XInput
diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h
index 3c543fb18f..5417f350b5 100644
--- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h
+++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h
@@ -24,82 +24,23 @@ 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_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;
};