InputManager: Sync effect state on connection

Fixes mic/RGB LED not synchronizing on new device connection.

Apparently I forgot that it doesn't reload bindings, only when the
InputSource list changes.
This commit is contained in:
Stenzek
2025-10-05 00:57:15 +10:00
parent e373be9fd3
commit 24a3dcb412

View File

@@ -29,6 +29,7 @@
#include <memory>
#include <mutex>
#include <sstream>
#include <tuple>
#include <unordered_map>
#include <variant>
#include <vector>
@@ -73,6 +74,16 @@ struct PadVibrationBinding
Timer::Value last_update_time; ///< Last time this motor was updated.
InputSource* source; ///< Input source for this motor.
float last_intensity; ///< Last intensity we sent to the motor.
ALWAYS_INLINE static u64 PackPadAndBindIndex(u32 pad_index, u32 bind_index)
{
return (static_cast<u64>(pad_index) << 32) | static_cast<u64>(bind_index);
}
ALWAYS_INLINE static std::tuple<u32, u32> UnpackPadAndBindIndex(u64 packed)
{
return {static_cast<u32>(packed >> 32), static_cast<u32>(packed)};
}
};
struct PadLEDBinding
@@ -132,6 +143,7 @@ static float ApplySingleBindingScale(float sensitivity, float deadzone, float va
static void AddHotkeyBindings(const SettingsInterface& si);
static void AddPadBindings(const SettingsInterface& si, const std::string& section, u32 pad,
const Controller::ControllerInfo& cinfo);
static void SynchronizePadEffectBindings(InputBindingKey key);
static void UpdateContinuedVibration();
static void GenerateRelativeMouseEvents();
@@ -149,11 +161,6 @@ static void UpdateInputSourceState(const SettingsInterface& si, std::unique_lock
static const KeyCodeData* FindKeyCodeData(u32 usb_code);
ALWAYS_INLINE static u64 PackPadAndBindIndex(u32 pad_index, u32 bind_index)
{
return (static_cast<u64>(pad_index) << 32) | static_cast<u64>(bind_index);
}
// ------------------------------------------------------------------------
// Tracking host mouse movement and turning into relative events
// 4 axes: pointer left/right, wheel vertical/horizontal. Last/Next/Normalized.
@@ -617,7 +624,7 @@ void InputManager::AddVibrationBinding(u32 pad_index, u32 bind_index, const Inpu
InputSource* source)
{
s_state.pad_vibration_array.push_back(
PadVibrationBinding{.pad_and_bind_index = PackPadAndBindIndex(pad_index, bind_index),
PadVibrationBinding{.pad_and_bind_index = PadVibrationBinding::PackPadAndBindIndex(pad_index, bind_index),
.binding = binding,
.last_update_time = 0,
.source = source,
@@ -1016,7 +1023,7 @@ void InputManager::AddPadBindings(const SettingsInterface& si, const std::string
PadVibrationBinding vib_binding;
if (ParseBindingAndGetSource(binding, &vib_binding.binding, &vib_binding.source))
{
vib_binding.pad_and_bind_index = PackPadAndBindIndex(pad_index, bi.bind_index);
vib_binding.pad_and_bind_index = PadVibrationBinding::PackPadAndBindIndex(pad_index, bi.bind_index);
vib_binding.last_update_time = 0;
// If we're reloading bindings due to e.g. device connection, sync the vibration state.
@@ -1070,6 +1077,37 @@ void InputManager::AddPadBindings(const SettingsInterface& si, const std::string
}
}
void InputManager::SynchronizePadEffectBindings(InputBindingKey key)
{
for (PadVibrationBinding& vib_binding : s_state.pad_vibration_array)
{
// only matching devices
if (vib_binding.binding.source_type != key.source_type && vib_binding.binding.source_index != key.source_index)
continue;
// need to find the max intensity for this binding, might be more than one if combined motors
float max_intensity = 0.0f;
for (PadVibrationBinding& other_vib_binding : s_state.pad_vibration_array)
{
if (vib_binding.binding == other_vib_binding.binding)
max_intensity = std::max(max_intensity, other_vib_binding.last_intensity);
}
if (max_intensity > 0.0f)
vib_binding.source->UpdateMotorState(vib_binding.binding, max_intensity);
}
for (PadLEDBinding& led_binding : s_state.pad_led_array)
{
// only matching devices
if (led_binding.binding.source_type != key.source_type && led_binding.binding.source_index != key.source_index)
continue;
// Need to pass it through unconditionally, otherwise if the LED was on it'll stay on.
led_binding.source->UpdateLEDState(led_binding.binding, led_binding.last_intensity);
}
}
// ------------------------------------------------------------------------
// Event Handling
// ------------------------------------------------------------------------
@@ -1791,6 +1829,7 @@ void InputManager::OnInputDeviceConnected(InputBindingKey key, std::string_view
std::string_view device_name)
{
INFO_LOG("Device '{}' connected: '{}'", identifier, device_name);
SynchronizePadEffectBindings(key);
Host::OnInputDeviceConnected(key, identifier, device_name);
}
@@ -1819,7 +1858,7 @@ std::unique_ptr<ForceFeedbackDevice> InputManager::CreateForceFeedbackDevice(con
void InputManager::SetPadVibrationIntensity(u32 pad_index, u32 bind_index, float intensity)
{
const u64 pad_and_bind_index = PackPadAndBindIndex(pad_index, bind_index);
const u64 pad_and_bind_index = PadVibrationBinding::PackPadAndBindIndex(pad_index, bind_index);
for (PadVibrationBinding& vib : s_state.pad_vibration_array)
{
if (vib.pad_and_bind_index == pad_and_bind_index && vib.last_intensity != intensity)