rawinput: remove experimental analog features (delay and relative axis mode) (#668)

## Link to GitHub Issue or related Pull Request, if one exists
Related to #181 

## Description of change
This PR removes two features marked as "experimental" for analog axis -
`Delay` and `Relative Axis`.

They have been in spice as experimental option for almost 2 years.. but
they have a fundamental problem of being tied to how often the analog is
polled. Not just how often the game's I/O emulation code polls it, but
literally any source (spice API, overlay, etc).

For `Delay`, the only real usage I'm aware of is for #181 which is
delaying IIDX turntable input. For this, I will follow up with a
separate PR that adds back the delay option specifically for IIDX.

For `Relative Axis` - I'm not quite sure if any one actually uses this.
This could be implemented per-game if some game demands it. Polaris
Chord already has one, for example.

## Testing
This commit is contained in:
bicarus
2026-05-02 00:51:21 -07:00
committed by GitHub
parent 7b862768b0
commit c5a4e954f9
8 changed files with 43 additions and 188 deletions
+1 -2
View File
@@ -237,8 +237,7 @@ float Analog::applyDeadzone(float raw_value) {
deadzone = -deadzone;
}
// relative mode assumes that user is using a stick, so center is neutral regardless of analog type
if (getType() != GameAPI::Analogs::AnalogType::LinearPositive || isRelativeMode()) {
if (getType() != GameAPI::Analogs::AnalogType::LinearPositive) {
// calculate values
const auto delta = value - 0.5f;
-37
View File
@@ -63,14 +63,6 @@ private:
float divisor_previous_value = 0.5f;
unsigned short divisor_region = 0;
// relative input mode
float absolute_value_for_rel_mode = 0.5f;
bool relative_mode = false;
// circular buffer (delayed input)
int delay_buffer_depth = 0;
std::queue<float> delay_buffer;
float calculateAngularDifference(float old_rads, float new_rads);
float normalizeAngle(float rads);
float normalizeAnalogValue(float value);
@@ -106,8 +98,6 @@ public:
smoothing = false;
deadzone_mirror = false;
setMultiplier(1);
setRelativeMode(false);
setDelayBufferDepth(0);
setLastState(0.5f);
}
@@ -205,33 +195,6 @@ public:
this->last_state = last_state;
}
inline bool isRelativeMode() const {
return this->relative_mode;
}
inline void setRelativeMode(bool relative_mode) {
this->relative_mode = relative_mode;
this->absolute_value_for_rel_mode = 0.5f;
}
inline float getAbsoluteValue(float relative_delta) {
this->absolute_value_for_rel_mode =
normalizeAnalogValue(this->absolute_value_for_rel_mode + relative_delta);
return this->absolute_value_for_rel_mode;
}
inline int getDelayBufferDepth() const {
return this->delay_buffer_depth;
}
inline void setDelayBufferDepth(int depth) {
this->delay_buffer_depth = depth;
}
inline std::queue<float> &getDelayBuffer() {
return this->delay_buffer;
}
inline GameAPI::Analogs::AnalogType getType() const {
return this->type;
}
+3 -48
View File
@@ -679,34 +679,12 @@ float GameAPI::Analogs::getState(rawinput::RawInputManager *manager, rawinput::D
}
// deadzone
// do not apply deadzone to circular analogs since it doesn't make sense (except in relative mode)
if (analog.isDeadzoneSet() &&
(analog.getType() != AnalogType::Circular || analog.isRelativeMode())) {
// do not apply deadzone to circular analogs since it doesn't make sense
if (analog.isDeadzoneSet() && analog.getType() != AnalogType::Circular) {
value = analog.applyDeadzone(value);
}
if (analog.isRelativeMode()) {
float relative_delta = value - 0.5f;
// built-in scaling to make values reasonable
relative_delta /= 80.f;
// integer multiplier/divisor
const auto mult = analog.getMultiplier();
if (mult < -1) {
relative_delta /= -mult;
} else if (1 < mult) {
relative_delta *= mult;
}
// sensitivity (ranges from 0.0 to 4.0)
if (analog.isSensitivitySet()) {
relative_delta *= analog.getSensitivity();
}
// translate relative movement to absolute value
value = analog.getAbsoluteValue(relative_delta);
} else if (analog.getType() == AnalogType::Circular) {
if (analog.getType() == AnalogType::Circular) {
// integer multiplier
value = analog.applyMultiplier(value);
@@ -782,29 +760,6 @@ float GameAPI::Analogs::getState(rawinput::RawInputManager *manager, rawinput::D
value = std::clamp(value, 0.f, 1.f);
}
}
// delay
if (0 < analog.getDelayBufferDepth()) {
auto& queue = analog.getDelayBuffer();
// ensure the queue isn't too long; drop old values
while (analog.getDelayBufferDepth() <= (int)queue.size()) {
queue.pop();
}
// always push new value
queue.push(value);
// get a new value to return
if ((int)queue.size() < analog.getDelayBufferDepth()) {
// not enough in the queue, stall for now, shouldn't happen often
value = analog.getLastState();
} else {
value = queue.front();
queue.pop();
}
}
break;
}
case rawinput::MIDI: {
-22
View File
@@ -252,8 +252,6 @@ bool Config::addGame(Game &game) {
bool invert = false;
bool smoothing = false;
int multiplier = 1;
bool relative_mode = false;
int delay_buffer_depth = 0;
tinyxml2::XMLError err1 = gameAnalogNode->QueryIntAttribute("index", &index);
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
@@ -261,8 +259,6 @@ bool Config::addGame(Game &game) {
gameAnalogNode->QueryBoolAttribute("invert", &invert);
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
gameAnalogNode->QueryBoolAttribute("relative", &relative_mode);
gameAnalogNode->QueryIntAttribute("delay", &delay_buffer_depth);
const char *devid = gameAnalogNode->Attribute("devid");
if (err1 != tinyxml2::XMLError::XML_SUCCESS || !devid) {
@@ -277,8 +273,6 @@ bool Config::addGame(Game &game) {
gameAnalogNode->SetAttribute("invert", it.getInvert());
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
gameAnalogNode->SetAttribute("delay", it.getDelayBufferDepth());
gameAnalogsNode->InsertEndChild(gameAnalogNode);
} else {
it.setIndex(static_cast<unsigned short int>(index));
@@ -289,8 +283,6 @@ bool Config::addGame(Game &game) {
it.setInvert(invert);
it.setSmoothing(smoothing);
it.setMultiplier(multiplier);
it.setRelativeMode(relative_mode);
it.setDelayBufferDepth(delay_buffer_depth);
}
} else {
gameAnalogNode = this->configFile.NewElement("analog");
@@ -302,8 +294,6 @@ bool Config::addGame(Game &game) {
gameAnalogNode->SetAttribute("invert", it.getInvert());
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
gameAnalogNode->SetAttribute("delay", it.getDelayBufferDepth());
gameAnalogNode->SetAttribute("devid", it.getDeviceIdentifier().c_str());
gameAnalogsNode->InsertEndChild(gameAnalogNode);
}
@@ -457,8 +447,6 @@ bool Config::addGame(Game &game) {
gameAnalogNode->SetAttribute("invert", it.getInvert());
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
gameAnalogNode->SetAttribute("delay", it.getDelayBufferDepth());
gameAnalogsNode->InsertEndChild(gameAnalogNode);
}
@@ -691,8 +679,6 @@ bool Config::updateBinding(const Game &game, const Analog &analog) {
gameAnalogNode->SetAttribute("invert", analog.getInvert());
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
gameAnalogNode->SetAttribute("relative", analog.isRelativeMode());
gameAnalogNode->SetAttribute("delay", analog.getDelayBufferDepth());
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
} else {
gameAnalogNode = this->configFile.NewElement("analog");
@@ -703,8 +689,6 @@ bool Config::updateBinding(const Game &game, const Analog &analog) {
gameAnalogNode->SetAttribute("invert", analog.getInvert());
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
gameAnalogNode->SetAttribute("relative", analog.isRelativeMode());
gameAnalogNode->SetAttribute("delay", analog.getDelayBufferDepth());
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
gameAnalogsNode->InsertEndChild(gameAnalogNode);
}
@@ -1141,8 +1125,6 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
bool invert = false;
bool smoothing = false;
int multiplier = 1;
bool relative_mode = false;
int delay_buffer_depth = 0;
gameAnalogNode->QueryIntAttribute("index", &index);
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
@@ -1150,8 +1132,6 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
gameAnalogNode->QueryBoolAttribute("invert", &invert);
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
gameAnalogNode->QueryBoolAttribute("relative", &relative_mode);
gameAnalogNode->QueryIntAttribute("delay", &delay_buffer_depth);
const char *devid = gameAnalogNode->Attribute("devid");
// create analog and add to list
@@ -1163,8 +1143,6 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
analog.setInvert(invert);
analog.setSmoothing(smoothing);
analog.setMultiplier(multiplier);
analog.setRelativeMode(relative_mode);
analog.setDelayBufferDepth(delay_buffer_depth);
if (devid) {
analog.setDeviceIdentifier(devid);
}
-4
View File
@@ -69,8 +69,6 @@ namespace overlay::windows {
el->SetAttribute("invert", analog.invert);
el->SetAttribute("smoothing", analog.smoothing);
el->SetAttribute("multiplier", analog.multiplier);
el->SetAttribute("relative", analog.relative_mode);
el->SetAttribute("delay", analog.delay_buffer_depth);
parent->InsertEndChild(el);
}
@@ -92,8 +90,6 @@ namespace overlay::windows {
el->QueryBoolAttribute("invert", &a.invert);
el->QueryBoolAttribute("smoothing", &a.smoothing);
el->QueryIntAttribute("multiplier", &a.multiplier);
el->QueryBoolAttribute("relative", &a.relative_mode);
el->QueryIntAttribute("delay", &a.delay_buffer_depth);
return a;
}