diff --git a/src/frontend-common/input_manager.cpp b/src/frontend-common/input_manager.cpp index 6b6a50d4d..95bc28aff 100644 --- a/src/frontend-common/input_manager.cpp +++ b/src/frontend-common/input_manager.cpp @@ -36,14 +36,6 @@ enum : u32 LAST_EXTERNAL_INPUT_SOURCE = static_cast(InputSourceType::Count), }; -// ------------------------------------------------------------------------ -// Event Handler Type -// ------------------------------------------------------------------------ -// This class acts as an adapter to convert from normalized values to -// binary values when the callback is a binary/button handler. That way -// you don't need to convert float->bool in your callbacks. -using InputEventHandler = std::variant; - // ------------------------------------------------------------------------ // Binding Type // ------------------------------------------------------------------------ @@ -107,7 +99,6 @@ static std::optional ParseSensorKey(const std::string_view& sou static std::vector SplitChord(const std::string_view& binding); static bool SplitBinding(const std::string_view& binding, std::string_view* source, std::string_view* sub_binding); static void AddBindings(const std::vector& bindings, const InputEventHandler& handler); -static bool ParseBindingAndGetSource(const std::string_view& binding, InputBindingKey* key, InputSource** source); static bool IsAxisHandler(const InputEventHandler& handler); @@ -341,45 +332,68 @@ std::string InputManager::ConvertInputBindingKeysToString(const InputBindingKey* void InputManager::AddBindings(const std::vector& bindings, const InputEventHandler& handler) { for (const std::string& binding : bindings) + AddBinding(binding, handler); +} + +void InputManager::AddBinding(const std::string_view& binding, const InputEventHandler& handler) +{ + std::shared_ptr ibinding; + const std::vector chord_bindings(SplitChord(binding)); + + for (const std::string_view& chord_binding : chord_bindings) { - std::shared_ptr ibinding; - const std::vector chord_bindings(SplitChord(binding)); + std::optional key = ParseInputBindingKey(chord_binding); + if (!key.has_value()) + { + Log_ErrorPrintf("Invalid binding: '%.*s'", static_cast(binding.size()), binding.data()); + ibinding.reset(); + break; + } - for (const std::string_view& chord_binding : chord_bindings) + if (!ibinding) { - std::optional key = ParseInputBindingKey(chord_binding); - if (!key.has_value()) - { - Log_ErrorPrintf("Invalid binding: '%s'", binding.c_str()); - ibinding.reset(); - break; - } + ibinding = std::make_shared(); + ibinding->handler = handler; + } - if (!ibinding) - { - ibinding = std::make_shared(); - ibinding->handler = handler; - } + if (ibinding->num_keys == MAX_KEYS_PER_BINDING) + { + Log_ErrorPrintf("Too many chord parts, max is %u (%.*s)", MAX_KEYS_PER_BINDING, static_cast(binding.size()), + binding.data()); + ibinding.reset(); + break; + } - if (ibinding->num_keys == MAX_KEYS_PER_BINDING) - { - Log_ErrorPrintf("Too many chord parts, max is %u (%s)", MAX_KEYS_PER_BINDING, binding.c_str()); - ibinding.reset(); - break; - } + ibinding->keys[ibinding->num_keys] = key.value(); + ibinding->full_mask |= (static_cast(1) << ibinding->num_keys); + ibinding->num_keys++; + } - ibinding->keys[ibinding->num_keys] = key.value(); - ibinding->full_mask |= (static_cast(1) << ibinding->num_keys); - ibinding->num_keys++; - } + if (!ibinding) + return; - if (!ibinding) - continue; + // plop it in the input map for all the keys + for (u32 i = 0; i < ibinding->num_keys; i++) + s_binding_map.emplace(ibinding->keys[i].MaskDirection(), ibinding); +} - // plop it in the input map for all the keys - for (u32 i = 0; i < ibinding->num_keys; i++) - s_binding_map.emplace(ibinding->keys[i].MaskDirection(), ibinding); +void InputManager::AddVibrationBinding(u32 pad_index, const InputBindingKey* motor_0_binding, + InputSource* motor_0_source, const InputBindingKey* motor_1_binding, + InputSource* motor_1_source) +{ + PadVibrationBinding vib; + vib.pad_index = pad_index; + if (motor_0_binding) + { + vib.motors[0].binding = *motor_0_binding; + vib.motors[0].source = motor_0_source; + } + if (motor_1_binding) + { + vib.motors[1].binding = *motor_1_binding; + vib.motors[1].source = motor_1_source; } + s_pad_vibration_array.push_back(std::move(vib)); } // ------------------------------------------------------------------------ @@ -1356,10 +1370,9 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind if (!cinfo || cinfo->type == ControllerType::None) continue; - // NOTE: Macros can be overridden per-game. const std::string section(Controller::GetSettingsSection(pad)); AddPadBindings(binding_si, section, pad, cinfo); - LoadMacroButtonConfig(si, section, pad, cinfo); + LoadMacroButtonConfig(binding_si, section, pad, cinfo); } for (u32 axis = 0; axis < static_cast(InputPointerAxis::Count); axis++) diff --git a/src/frontend-common/input_manager.h b/src/frontend-common/input_manager.h index f9b2449aa..690b9b846 100644 --- a/src/frontend-common/input_manager.h +++ b/src/frontend-common/input_manager.h @@ -91,6 +91,14 @@ using InputButtonEventHandler = std::function; /// Callback types for a normalized event. Usually used for pads. using InputAxisEventHandler = std::function; +/// ------------------------------------------------------------------------ +/// Event Handler Type +/// ------------------------------------------------------------------------ +/// This class acts as an adapter to convert from normalized values to +/// binary values when the callback is a binary/button handler. That way +/// you don't need to convert float->bool in your callbacks. +using InputEventHandler = std::variant; + /// Input monitoring for external access. struct InputInterceptHook { @@ -226,6 +234,16 @@ bool HasAnyBindingsForKey(InputBindingKey key); /// Can be safely called on another thread. bool HasAnyBindingsForSource(InputBindingKey key); +/// Parses a string binding into its components. Use with external AddBinding(). +bool ParseBindingAndGetSource(const std::string_view& binding, InputBindingKey* key, InputSource** source); + +/// Externally adds a fixed binding. Be sure to call *after* ReloadBindings() otherwise it will be lost. +void AddBinding(const std::string_view& binding, const InputEventHandler& handler); + +/// Adds an external vibration binding. +void AddVibrationBinding(u32 pad_index, const InputBindingKey* motor_0_binding, InputSource* motor_0_source, + const InputBindingKey* motor_1_binding, InputSource* motor_1_source); + /// Updates internal state for any binds for this key, and fires callbacks as needed. /// Returns true if anything was bound to this key, otherwise false. bool InvokeEvents(InputBindingKey key, float value, GenericInputBinding generic_key);