diff --git a/pcsx2/Input/InputManager.cpp b/pcsx2/Input/InputManager.cpp index 2f706e4abfe08..8929a4a90f44c 100644 --- a/pcsx2/Input/InputManager.cpp +++ b/pcsx2/Input/InputManager.cpp @@ -92,7 +92,6 @@ namespace InputManager static std::optional ParseHostKeyboardKey(const std::string_view source, const std::string_view sub_binding); static std::optional ParsePointerKey(const std::string_view source, const std::string_view sub_binding); - 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 PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed); static void AddBinding(const std::string_view binding, const InputEventHandler& handler); @@ -752,7 +751,7 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index) const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f); const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f); AddBindings( - bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](float value) { + bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) { Pad::SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value)); }}); } @@ -772,9 +771,9 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index) if (!bindings.empty()) { const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Deadzone", macro_button_index + 1).c_str(), 0.0f); - AddBindings(bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](float value) { + AddBindings(bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](InputBindingKey key, float value) { const bool state = (value > deadzone); - Pad::SetMacroButtonState(pad_index, macro_button_index, state); + Pad::SetMacroButtonState(key, pad_index, macro_button_index, state); }}); } } @@ -836,7 +835,7 @@ void InputManager::AddUSBBindings(SettingsInterface& si, u32 port) { const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f); const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f); - AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](float value) { + AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) { USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value)); }}); } @@ -977,7 +976,7 @@ bool InputManager::ProcessEvent(InputBindingKey key, float value, bool skip_butt if (IsAxisHandler(binding->handler)) { if (value_to_pass >= 0.0f && (!skip_button_handlers || value_to_pass == 0.0f)) - std::get(binding->handler)(value_to_pass); + std::get(binding->handler)(key, value_to_pass); } else if (binding->num_keys >= min_num_keys) { @@ -1056,7 +1055,7 @@ void InputManager::ClearBindStateFromSource(InputBindingKey key) if (binding->keys[i].MaskDirection() != match_key) continue; - std::get(binding->handler)(0.0f); + std::get(binding->handler)(key, 0.0f); break; } } diff --git a/pcsx2/Input/InputManager.h b/pcsx2/Input/InputManager.h index 51b93e1fe9681..af27fafb5b5dc 100644 --- a/pcsx2/Input/InputManager.h +++ b/pcsx2/Input/InputManager.h @@ -95,7 +95,7 @@ struct InputBindingKeyHash using InputButtonEventHandler = std::function; /// Callback types for a normalized event. Usually used for pads. -using InputAxisEventHandler = std::function; +using InputAxisEventHandler = std::function; /// Input monitoring for external access. struct InputInterceptHook @@ -211,6 +211,9 @@ namespace InputManager /// Represents a binding with icon fonts, if available. bool PrettifyInputBinding(SmallStringBase& binding); + /// Splits a chord into individual bindings. + std::vector SplitChord(const std::string_view binding); + /// Returns a list of all hotkeys. std::vector GetHotkeyList(); diff --git a/pcsx2/SIO/Pad/Pad.cpp b/pcsx2/SIO/Pad/Pad.cpp index a0fd1ceedd60d..a4fc84ba0b5b8 100644 --- a/pcsx2/SIO/Pad/Pad.cpp +++ b/pcsx2/SIO/Pad/Pad.cpp @@ -28,11 +28,15 @@ #include +//Map of actively pressed keys so that chords work +using KeyMap = std::unordered_multimap; + namespace Pad { struct MacroButton { std::vector buttons; ///< Buttons to activate. + KeyMap active_buttons; ///< Currently active buttons. float pressure; ///< Pressure to apply when macro is active. u16 toggle_frequency; ///< Interval at which the buttons will be toggled, if not 0. u16 toggle_counter; ///< When this counter reaches zero, buttons will be toggled. @@ -670,8 +674,12 @@ void Pad::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, const Cont } } -void Pad::SetMacroButtonState(u32 pad, u32 index, bool state) +void Pad::SetMacroButtonState(InputBindingKey& key, u32 pad, u32 index, bool state) { + //0 appears for some reason and breaks mb.active_buttons.size() != binding_count + if (key.bits == 0) + return; + if (pad >= Pad::NUM_CONTROLLER_PORTS || index >= NUM_MACRO_BUTTONS_PER_CONTROLLER) return; @@ -679,6 +687,30 @@ void Pad::SetMacroButtonState(u32 pad, u32 index, bool state) if (mb.buttons.empty()) return; + SettingsInterface& sif = *Host::GetSettingsInterface(); + std::vector data = sif.GetStringList(fmt::format("Pad{}", pad+1).c_str(), fmt::format("Macro{}", index+1).c_str()); + size_t binding_count = 0; + //just in case there's more than one index + for (std::string bind : data) + { + binding_count += InputManager::SplitChord(bind).size(); + } + if (mb.active_buttons.find(key.bits) != mb.active_buttons.end()) + mb.active_buttons.erase(key.bits); + + mb.active_buttons.emplace(key.bits, state); + + if (mb.active_buttons.size() != binding_count) + return; + + if (mb.active_buttons.size() > 1 && state) + { + for (auto it = mb.active_buttons.begin(); it != mb.active_buttons.end(); ++it) + { + if (!it->second) + return; + } + } const bool trigger_state = (mb.trigger_toggle ? (state ? !mb.trigger_state : mb.trigger_state) : state); if (mb.trigger_state == trigger_state) return; diff --git a/pcsx2/SIO/Pad/Pad.h b/pcsx2/SIO/Pad/Pad.h index dccd04cc134b8..97114274c82d0 100644 --- a/pcsx2/SIO/Pad/Pad.h +++ b/pcsx2/SIO/Pad/Pad.h @@ -4,6 +4,7 @@ #pragma once #include "Config.h" +#include "Input/InputManager.h" #include "SIO/Pad/PadTypes.h" #include @@ -68,6 +69,6 @@ namespace Pad bool Freeze(StateWrapper& sw); // Sets the state of the specified macro button. - void SetMacroButtonState(u32 pad, u32 index, bool state); + void SetMacroButtonState(InputBindingKey& key, u32 pad, u32 index, bool state); void UpdateMacroButtons(); }; // namespace Pad