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> 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 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<InputAxisEventHandler>(binding->handler)(value_to_pass);
std::get<InputAxisEventHandler>(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<InputAxisEventHandler>(binding->handler)(0.0f);
std::get<InputAxisEventHandler>(binding->handler)(key, 0.0f);
break;
}
}

View File

@ -95,7 +95,7 @@ struct InputBindingKeyHash
using InputButtonEventHandler = std::function<void(s32 value)>;
/// 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.
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<std::string_view> SplitChord(const std::string_view binding);
/// Returns a list of all hotkeys.
std::vector<const HotkeyInfo*> GetHotkeyList();

View File

@ -28,11 +28,15 @@
#include <vector>
//Map of actively pressed keys so that chords work
using KeyMap = std::unordered_multimap<u64, bool>;
namespace Pad
{
struct MacroButton
{
std::vector<u32> 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<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);
if (mb.trigger_state == trigger_state)
return;

View File

@ -4,6 +4,7 @@
#pragma once
#include "Config.h"
#include "Input/InputManager.h"
#include "SIO/Pad/PadTypes.h"
#include <memory>
@ -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