Make macro chords work

This commit is contained in:
Glebux 2025-02-08 09:20:23 +03:00
parent 865b75bcbb
commit 09855dd18a
4 changed files with 45 additions and 10 deletions

View File

@ -92,7 +92,6 @@ namespace InputManager
static std::optional<InputBindingKey> ParseHostKeyboardKey(const std::string_view source, const std::string_view sub_binding); static std::optional<InputBindingKey> ParseHostKeyboardKey(const std::string_view source, const std::string_view sub_binding);
static std::optional<InputBindingKey> ParsePointerKey(const std::string_view source, const std::string_view sub_binding); static std::optional<InputBindingKey> ParsePointerKey(const std::string_view source, const std::string_view sub_binding);
static std::vector<std::string_view> SplitChord(const std::string_view binding);
static bool SplitBinding(const std::string_view binding, std::string_view* source, std::string_view* sub_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 PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed);
static void AddBinding(const std::string_view binding, const InputEventHandler& handler); 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 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); const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
AddBindings( 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)); 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()) if (!bindings.empty())
{ {
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Deadzone", macro_button_index + 1).c_str(), 0.0f); 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); 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 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); 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)); 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 (IsAxisHandler(binding->handler))
{ {
if (value_to_pass >= 0.0f && (!skip_button_handlers || value_to_pass == 0.0f)) if (value_to_pass >= 0.0f && (!skip_button_handlers || value_to_pass == 0.0f))
std::get<InputAxisEventHandler>(binding->handler)(value_to_pass); std::get<InputAxisEventHandler>(binding->handler)(key, value_to_pass);
} }
else if (binding->num_keys >= min_num_keys) else if (binding->num_keys >= min_num_keys)
{ {
@ -1056,7 +1055,7 @@ void InputManager::ClearBindStateFromSource(InputBindingKey key)
if (binding->keys[i].MaskDirection() != match_key) if (binding->keys[i].MaskDirection() != match_key)
continue; continue;
std::get<InputAxisEventHandler>(binding->handler)(0.0f); std::get<InputAxisEventHandler>(binding->handler)(key, 0.0f);
break; break;
} }
} }

View File

@ -95,7 +95,7 @@ struct InputBindingKeyHash
using InputButtonEventHandler = std::function<void(s32 value)>; using InputButtonEventHandler = std::function<void(s32 value)>;
/// Callback types for a normalized event. Usually used for pads. /// Callback types for a normalized event. Usually used for pads.
using InputAxisEventHandler = std::function<void(float value)>; using InputAxisEventHandler = std::function<void(InputBindingKey key, float value)>;
/// Input monitoring for external access. /// Input monitoring for external access.
struct InputInterceptHook struct InputInterceptHook
@ -211,6 +211,9 @@ namespace InputManager
/// Represents a binding with icon fonts, if available. /// Represents a binding with icon fonts, if available.
bool PrettifyInputBinding(SmallStringBase& binding); bool PrettifyInputBinding(SmallStringBase& binding);
/// Splits a chord into individual bindings.
std::vector<std::string_view> SplitChord(const std::string_view binding);
/// Returns a list of all hotkeys. /// Returns a list of all hotkeys.
std::vector<const HotkeyInfo*> GetHotkeyList(); std::vector<const HotkeyInfo*> GetHotkeyList();

View File

@ -28,11 +28,15 @@
#include <vector> #include <vector>
//Map of actively pressed keys so that chords work
using KeyMap = std::unordered_multimap<u64, bool>;
namespace Pad namespace Pad
{ {
struct MacroButton struct MacroButton
{ {
std::vector<u32> buttons; ///< Buttons to activate. std::vector<u32> buttons; ///< Buttons to activate.
KeyMap active_buttons; ///< Currently active buttons.
float pressure; ///< Pressure to apply when macro is active. 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_frequency; ///< Interval at which the buttons will be toggled, if not 0.
u16 toggle_counter; ///< When this counter reaches zero, buttons will be toggled. 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) if (pad >= Pad::NUM_CONTROLLER_PORTS || index >= NUM_MACRO_BUTTONS_PER_CONTROLLER)
return; return;
@ -679,6 +687,30 @@ void Pad::SetMacroButtonState(u32 pad, u32 index, bool state)
if (mb.buttons.empty()) if (mb.buttons.empty())
return; return;
SettingsInterface& sif = *Host::GetSettingsInterface();
std::vector<std::string> 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); const bool trigger_state = (mb.trigger_toggle ? (state ? !mb.trigger_state : mb.trigger_state) : state);
if (mb.trigger_state == trigger_state) if (mb.trigger_state == trigger_state)
return; return;

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "Config.h" #include "Config.h"
#include "Input/InputManager.h"
#include "SIO/Pad/PadTypes.h" #include "SIO/Pad/PadTypes.h"
#include <memory> #include <memory>
@ -68,6 +69,6 @@ namespace Pad
bool Freeze(StateWrapper& sw); bool Freeze(StateWrapper& sw);
// Sets the state of the specified macro button. // 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(); void UpdateMacroButtons();
}; // namespace Pad }; // namespace Pad