Files
spice2x.github.io/src/spice2x/overlay/windows/controller_presets.h
T
bicarus 96950b6b4e rawinput: reimplement analog relative mode and delay (#674)
## Link to GitHub Issue or related Pull Request, if one exists
#181 

## Description of change
Implement analog relative mode and delay option using a new
millisecond-based algorithm.

## Testing
WIP
2026-05-04 22:50:11 -07:00

161 lines
5.7 KiB
C++

#pragma once
#include <set>
#include <string>
#include <vector>
#include "cfg/analog.h"
#include "cfg/button.h"
namespace overlay::windows {
// single button binding entry (primary or alternative)
struct TemplateButtonEntry {
unsigned short vKey = INVALID_VKEY;
ButtonAnalogType analog_type = BAT_NONE;
std::string device_identifier;
bool invert = false;
double debounce_up = 0.0;
double debounce_down = 0.0;
int bat_threshold = 0;
unsigned short velocity_threshold = 0;
bool is_naive() const { return device_identifier.empty() && vKey != INVALID_VKEY; }
bool is_device() const { return !device_identifier.empty(); }
bool is_unbound() const { return device_identifier.empty() && vKey == INVALID_VKEY; }
static TemplateButtonEntry FromButton(const Button &btn) {
TemplateButtonEntry e;
e.vKey = btn.getVKey();
e.analog_type = btn.getAnalogType();
e.device_identifier = btn.getDeviceIdentifier();
e.invert = btn.getInvert();
e.debounce_up = btn.getDebounceUp();
e.debounce_down = btn.getDebounceDown();
e.bat_threshold = btn.getBatThreshold();
e.velocity_threshold = btn.getVelocityThreshold();
return e;
}
};
// button binding with primary + alternatives
struct TemplateButtonBinding {
std::string name;
TemplateButtonEntry primary;
std::vector<TemplateButtonEntry> alternatives;
TemplateButtonBinding() = default;
TemplateButtonBinding(std::string name, TemplateButtonEntry primary,
std::vector<TemplateButtonEntry> alternatives)
: name(std::move(name)), primary(std::move(primary)),
alternatives(std::move(alternatives)) {}
explicit TemplateButtonBinding(Button &btn) {
name = btn.getName();
primary = TemplateButtonEntry::FromButton(btn);
for (auto &alt : btn.getAlternatives()) {
alternatives.push_back(TemplateButtonEntry::FromButton(alt));
}
}
};
// analog binding
struct TemplateAnalogBinding {
std::string name;
std::string device_identifier;
unsigned short index = 0xFF;
float sensitivity = 1.f;
float deadzone = 0.f;
bool deadzone_mirror = false;
bool invert = false;
bool smoothing = false;
int multiplier = 1;
bool relative_mode = false;
uint32_t delay_ms = 0;
bool is_device() const { return !device_identifier.empty(); }
bool is_unbound() const { return device_identifier.empty() && index == 0xFF; }
TemplateAnalogBinding() = default;
explicit TemplateAnalogBinding(Analog &a) {
name = a.getName();
device_identifier = a.getDeviceIdentifier();
index = a.getIndex();
sensitivity = a.getSensitivity();
deadzone = a.getDeadzone();
deadzone_mirror = a.getDeadzoneMirror();
invert = a.getInvert();
smoothing = a.getSmoothing();
multiplier = a.getMultiplier();
relative_mode = a.isRelativeMode();
delay_ms = a.getDelayMs();
}
};
// single light binding entry (primary or alternative)
struct TemplateLightEntry {
std::string device_identifier;
unsigned int index = 0;
bool is_device() const { return !device_identifier.empty(); }
bool is_unbound() const { return device_identifier.empty(); }
};
// light binding with primary + alternatives
struct TemplateLightBinding {
std::string name;
TemplateLightEntry primary;
std::vector<TemplateLightEntry> alternatives;
TemplateLightBinding() = default;
TemplateLightBinding(std::string name, TemplateLightEntry primary,
std::vector<TemplateLightEntry> alternatives)
: name(std::move(name)), primary(std::move(primary)),
alternatives(std::move(alternatives)) {}
};
// controller preset
struct ControllerTemplate {
std::string name;
std::string game_name;
bool is_builtin = false;
std::vector<TemplateButtonBinding> buttons;
std::vector<TemplateButtonBinding> keypad_buttons;
std::vector<TemplateAnalogBinding> analogs;
std::vector<TemplateLightBinding> lights;
// helpers
int count_naive_buttons() const;
int count_device_buttons() const;
int count_device_analogs() const;
int count_device_lights() const;
std::set<std::string> get_used_devices() const;
// get all binding sources (device_identifier strings used in this preset)
std::vector<std::string> get_binding_sources() const;
// get summary of bindings for a specific source (for tooltip display)
std::string get_source_summary(const std::string &source) const;
// replace all occurrences of a source device_identifier with a new one
void rename_source(const std::string &old_id, const std::string &new_id);
};
// template management API
std::vector<ControllerTemplate> get_templates_for_game(const std::string &game_name);
std::vector<ControllerTemplate> load_user_templates();
bool save_user_template(
const ControllerTemplate &tmpl,
const bool save_buttons,
const bool save_keypads,
const bool save_analogs,
const bool save_lights);
bool delete_user_template(const std::string &game_name, const std::string &template_name);
bool rename_user_template(const std::string &game_name,
const std::string &old_name, const std::string &new_name);
}