mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-12 17:34:33 +00:00
InputSource: Support querying current values
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "platform_misc.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
@@ -511,6 +512,45 @@ void DInputSource::CheckForStateChanges(size_t index, const DIJOYSTATE& new_stat
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<float> DInputSource::GetCurrentValue(InputBindingKey key)
|
||||
{
|
||||
std::optional<float> ret;
|
||||
|
||||
if (key.source_type != InputSourceType::DInput)
|
||||
return ret;
|
||||
|
||||
if (key.source_index >= m_controllers.size())
|
||||
return ret;
|
||||
|
||||
const ControllerData& cd = m_controllers[key.source_index];
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < cd.axis_offsets.size())
|
||||
{
|
||||
LONG value;
|
||||
std::memcpy(&value, reinterpret_cast<const u8*>(&cd.last_state) + cd.axis_offsets[key.data], sizeof(value));
|
||||
ret = static_cast<float>(value) / (value < 0 ? 32768.0f : 32767.0f);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton)
|
||||
{
|
||||
if (key.data < cd.num_buttons)
|
||||
{
|
||||
ret = BoolToFloat(cd.last_state.rgbButtons[key.data]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// might be a hat
|
||||
const u32 hat_index = (key.data - cd.num_buttons) / NUM_HAT_DIRECTIONS;
|
||||
const u32 hat_direction = (key.data - cd.num_buttons) % NUM_HAT_DIRECTIONS;
|
||||
if (hat_index < cd.num_hats)
|
||||
{
|
||||
const std::array<bool, NUM_HAT_DIRECTIONS> buttons(GetHatButtons(cd.last_state.rgdwPOV[hat_index]));
|
||||
ret = BoolToFloat(buttons[hat_direction]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputSource> InputSource::CreateDInputSource()
|
||||
{
|
||||
return std::make_unique<DInputSource>();
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::optional<float> GetCurrentValue(InputBindingKey key) override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
|
||||
@@ -25,16 +25,34 @@ public:
|
||||
InputSource();
|
||||
virtual ~InputSource();
|
||||
|
||||
// Sets up the input source.
|
||||
virtual bool Initialize(const SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
||||
|
||||
/// Updates the settings for this input source. This should be called when settings change.
|
||||
virtual void UpdateSettings(const SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
||||
|
||||
/// Reloads the devices for this input source. This should be called when a device change is detected.
|
||||
virtual bool ReloadDevices() = 0;
|
||||
|
||||
/// Shuts down the input source, releasing any resources it holds.
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
/// Polls the input source for events. This should be called at a regular interval, such as every frame.
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
/// Returns the current value for the specified device and key.
|
||||
virtual std::optional<float> GetCurrentValue(InputBindingKey key) = 0;
|
||||
|
||||
/// Returns true if the source contains the specified device.
|
||||
virtual bool ContainsDevice(std::string_view device) const = 0;
|
||||
|
||||
/// Parses a key string for the specified device. Returns std::nullopt if the key is not valid.
|
||||
virtual std::optional<InputBindingKey> ParseKeyString(std::string_view device, std::string_view binding) = 0;
|
||||
|
||||
/// Converts a key to a string representation. The string should be suitable for parsing with ParseKeyString().
|
||||
virtual TinyString ConvertKeyToString(InputBindingKey key) = 0;
|
||||
|
||||
/// Converts a key to an icon representation. The icon is suitable for display in the UI.
|
||||
virtual TinyString ConvertKeyToIcon(InputBindingKey key, InputManager::BindingIconMappingFunction mapper) = 0;
|
||||
|
||||
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
|
||||
|
||||
@@ -1145,6 +1145,46 @@ bool SDLInputSource::HandleJoystickHatEvent(const SDL_JoyHatEvent* ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<float> SDLInputSource::GetCurrentValue(InputBindingKey key)
|
||||
{
|
||||
std::optional<float> ret;
|
||||
if (key.source_type != InputSourceType::SDL)
|
||||
return ret;
|
||||
|
||||
const auto cd = GetControllerDataForPlayerId(static_cast<int>(key.source_index));
|
||||
if (cd == m_controllers.end())
|
||||
return ret;
|
||||
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis)
|
||||
{
|
||||
if (cd->gamepad && key.data < std::size(s_sdl_axis_names))
|
||||
ret = NormalizeS16(SDL_GetGamepadAxis(cd->gamepad, static_cast<SDL_GamepadAxis>(key.data)));
|
||||
else if (key.data >= std::size(s_sdl_axis_names))
|
||||
ret = NormalizeS16(SDL_GetJoystickAxis(cd->joystick, static_cast<int>(key.data - std::size(s_sdl_axis_names))));
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton)
|
||||
{
|
||||
if (cd->gamepad && key.data < std::size(s_sdl_button_names))
|
||||
{
|
||||
ret = BoolToFloat(SDL_GetGamepadButton(cd->gamepad, static_cast<SDL_GamepadButton>(key.data)));
|
||||
}
|
||||
else if (key.data >= std::size(s_sdl_axis_names))
|
||||
{
|
||||
ret =
|
||||
BoolToFloat(SDL_GetJoystickButton(cd->joystick, static_cast<int>(key.data - std::size(s_sdl_button_names))));
|
||||
}
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerHat)
|
||||
{
|
||||
const u32 hat_index = key.data / static_cast<u32>(std::size(s_sdl_hat_direction_names));
|
||||
const u8 hat_direction = Truncate8(key.data % static_cast<u32>(std::size(s_sdl_hat_direction_names)));
|
||||
const u8 hat_value = SDL_GetJoystickHat(cd->joystick, static_cast<int>(hat_index));
|
||||
ret = BoolToFloat((hat_value & (1u << hat_direction)) != 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
InputManager::VibrationMotorList SDLInputSource::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
InputManager::VibrationMotorList ret;
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::optional<float> GetCurrentValue(InputBindingKey key) override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
|
||||
@@ -76,6 +76,12 @@ void Win32RawInputSource::PollEvents()
|
||||
// noop, handled by message pump
|
||||
}
|
||||
|
||||
std::optional<float> Win32RawInputSource::GetCurrentValue(InputBindingKey key)
|
||||
{
|
||||
// not really used
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
InputManager::DeviceList Win32RawInputSource::EnumerateDevices()
|
||||
{
|
||||
InputManager::DeviceList ret;
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::optional<float> GetCurrentValue(InputBindingKey key) override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
|
||||
@@ -508,6 +508,44 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
|
||||
cd.last_state = new_state;
|
||||
}
|
||||
|
||||
std::optional<float> XInputSource::GetCurrentValue(InputBindingKey key)
|
||||
{
|
||||
std::optional<float> ret;
|
||||
if (key.source_type != InputSourceType::XInput || key.source_index >= NUM_CONTROLLERS)
|
||||
return ret;
|
||||
|
||||
const ControllerData& cd = m_controllers[key.source_index];
|
||||
if (!cd.connected)
|
||||
return ret;
|
||||
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < NUM_AXES)
|
||||
{
|
||||
const XINPUT_GAMEPAD& state = cd.last_state.Gamepad;
|
||||
#define CHECK_AXIS(field, axis, min_value, max_value) \
|
||||
case axis: \
|
||||
ret = static_cast<float>(state.field) / ((state.field < 0) ? min_value : max_value);
|
||||
|
||||
// Y axes is inverted in XInput when compared to SDL.
|
||||
switch (key.data)
|
||||
{
|
||||
CHECK_AXIS(sThumbLX, AXIS_LEFTX, 32768, 32767);
|
||||
CHECK_AXIS(sThumbLY, AXIS_LEFTY, -32768, -32767);
|
||||
CHECK_AXIS(sThumbRX, AXIS_RIGHTX, 32768, 32767);
|
||||
CHECK_AXIS(sThumbRY, AXIS_RIGHTY, -32768, -32767);
|
||||
CHECK_AXIS(bLeftTrigger, AXIS_LEFTTRIGGER, 0, 255);
|
||||
CHECK_AXIS(bRightTrigger, AXIS_RIGHTTRIGGER, 0, 255);
|
||||
}
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < NUM_BUTTONS)
|
||||
{
|
||||
const XINPUT_GAMEPAD& state = cd.last_state.Gamepad;
|
||||
const u16 button_mask = s_button_masks[key.data];
|
||||
ret = BoolToFloat((state.wButtons & button_mask) != 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void XInputSource::UpdateMotorState(InputBindingKey key, float intensity)
|
||||
{
|
||||
if (key.source_subtype != InputSubclass::ControllerMotor || key.source_index >= NUM_CONTROLLERS)
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::optional<float> GetCurrentValue(InputBindingKey key) override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
|
||||
Reference in New Issue
Block a user