mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
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
This commit is contained in:
@@ -39,8 +39,8 @@
|
|||||||
<button name="VEFX" vkey="10" analogtype="0" devid="Player 1" invert="false" debounce_up="0" debounce_down="0" velocity_threshold="0"/>
|
<button name="VEFX" vkey="10" analogtype="0" devid="Player 1" invert="false" debounce_up="0" debounce_down="0" velocity_threshold="0"/>
|
||||||
</buttons>
|
</buttons>
|
||||||
<analogs>
|
<analogs>
|
||||||
<analog name="Turntable P1" devid="Player 1" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Turntable P1" devid="Player 1" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Turntable P2" devid="Player 2" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Turntable P2" devid="Player 2" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
</analogs>
|
</analogs>
|
||||||
<lights>
|
<lights>
|
||||||
<light name="P1 1" devid="Player 1" index="0"/>
|
<light name="P1 1" devid="Player 1" index="0"/>
|
||||||
@@ -117,8 +117,8 @@
|
|||||||
<keypad_buttons/>
|
<keypad_buttons/>
|
||||||
<!-- Assumes analog mode. Need to invert direction since this FW is designed for INF. -->
|
<!-- Assumes analog mode. Need to invert direction since this FW is designed for INF. -->
|
||||||
<analogs>
|
<analogs>
|
||||||
<analog name="Turntable P1" devid="arcin (1p)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="true" smoothing="false" multiplier="1"/>
|
<analog name="Turntable P1" devid="arcin (1p)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="true" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Turntable P2" devid="arcin (2p)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="true" smoothing="false" multiplier="1"/>
|
<analog name="Turntable P2" devid="arcin (2p)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="true" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
</analogs>
|
</analogs>
|
||||||
<lights>
|
<lights>
|
||||||
<light name="P1 1" devid="arcin (1p)" index="0"/>
|
<light name="P1 1" devid="arcin (1p)" index="0"/>
|
||||||
@@ -144,34 +144,34 @@
|
|||||||
<buttons/>
|
<buttons/>
|
||||||
<keypad_buttons/>
|
<keypad_buttons/>
|
||||||
<analogs>
|
<analogs>
|
||||||
<analog name="Key 1" devid="Analogs key 01-28" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 1" devid="Analogs key 01-28" index="4" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 2" devid="Analogs key 01-28" index="5" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 2" devid="Analogs key 01-28" index="5" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 3" devid="Analogs key 01-28" index="6" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 3" devid="Analogs key 01-28" index="6" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 4" devid="Analogs key 01-28" index="7" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 4" devid="Analogs key 01-28" index="7" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 5" devid="Analogs key 01-28" index="8" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 5" devid="Analogs key 01-28" index="8" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 6" devid="Analogs key 01-28" index="9" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 6" devid="Analogs key 01-28" index="9" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 7" devid="Analogs key 01-28" index="10" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 7" devid="Analogs key 01-28" index="10" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 8" devid="Analogs key 01-28" index="11" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 8" devid="Analogs key 01-28" index="11" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 9" devid="Analogs key 01-28" index="12" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 9" devid="Analogs key 01-28" index="12" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 10" devid="Analogs key 01-28" index="13" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 10" devid="Analogs key 01-28" index="13" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 11" devid="Analogs key 01-28" index="14" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 11" devid="Analogs key 01-28" index="14" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 12" devid="Analogs key 01-28" index="15" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 12" devid="Analogs key 01-28" index="15" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 13" devid="Analogs key 01-28" index="16" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 13" devid="Analogs key 01-28" index="16" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 14" devid="Analogs key 01-28" index="17" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 14" devid="Analogs key 01-28" index="17" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 15" devid="Analogs key 01-28" index="18" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 15" devid="Analogs key 01-28" index="18" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 16" devid="Analogs key 01-28" index="19" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 16" devid="Analogs key 01-28" index="19" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 17" devid="Analogs key 01-28" index="20" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 17" devid="Analogs key 01-28" index="20" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 18" devid="Analogs key 01-28" index="21" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 18" devid="Analogs key 01-28" index="21" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 19" devid="Analogs key 01-28" index="22" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 19" devid="Analogs key 01-28" index="22" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 20" devid="Analogs key 01-28" index="23" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 20" devid="Analogs key 01-28" index="23" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 21" devid="Analogs key 01-28" index="24" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 21" devid="Analogs key 01-28" index="24" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 22" devid="Analogs key 01-28" index="25" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 22" devid="Analogs key 01-28" index="25" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 23" devid="Analogs key 01-28" index="26" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 23" devid="Analogs key 01-28" index="26" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 24" devid="Analogs key 01-28" index="27" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 24" devid="Analogs key 01-28" index="27" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 25" devid="Analogs key 01-28" index="28" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 25" devid="Analogs key 01-28" index="28" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 26" devid="Analogs key 01-28" index="29" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 26" devid="Analogs key 01-28" index="29" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 27" devid="Analogs key 01-28" index="30" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 27" devid="Analogs key 01-28" index="30" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Key 28" devid="Analogs key 01-28" index="31" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Key 28" devid="Analogs key 01-28" index="31" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
</analogs>
|
</analogs>
|
||||||
<lights>
|
<lights>
|
||||||
<light name="Key 1 R" devid="Lights 01-14" index="0"/>
|
<light name="Key 1 R" devid="Lights 01-14" index="0"/>
|
||||||
@@ -277,9 +277,9 @@
|
|||||||
</buttons>
|
</buttons>
|
||||||
<keypad_buttons/>
|
<keypad_buttons/>
|
||||||
<analogs>
|
<analogs>
|
||||||
<analog name="Guitar P1 Wail X" devid="Gitaller P1" index="1" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Guitar P1 Wail X" devid="Gitaller P1" index="1" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Guitar P1 Wail Y" devid="Gitaller P1" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Guitar P1 Wail Y" devid="Gitaller P1" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="Guitar P1 Wail Z" devid="Gitaller P1" index="5" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="Guitar P1 Wail Z" devid="Gitaller P1" index="5" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
</analogs>
|
</analogs>
|
||||||
<lights/>
|
<lights/>
|
||||||
<!-- Gen 1 FAUCETWO in HID mode; should also work for later gens -->
|
<!-- Gen 1 FAUCETWO in HID mode; should also work for later gens -->
|
||||||
@@ -296,8 +296,8 @@
|
|||||||
</buttons>
|
</buttons>
|
||||||
<keypad_buttons/>
|
<keypad_buttons/>
|
||||||
<analogs>
|
<analogs>
|
||||||
<analog name="VOL-L" devid="Buttons (MI_01)" index="1" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="VOL-L" devid="Buttons (MI_01)" index="1" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
<analog name="VOL-R" devid="Buttons (MI_01)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1"/>
|
<analog name="VOL-R" devid="Buttons (MI_01)" index="0" sensivity="1" deadzone="0" deadzone_mirror="false" invert="false" smoothing="false" multiplier="1" relative="false" delay_ms="0"/>
|
||||||
</analogs>
|
</analogs>
|
||||||
<lights>
|
<lights>
|
||||||
<light name="BT-A" devid="Lights (MI_02)" index="24"/>
|
<light name="BT-A" devid="Lights (MI_02)" index="24"/>
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ float Analog::applyDeadzone(float raw_value) {
|
|||||||
deadzone = -deadzone;
|
deadzone = -deadzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getType() != GameAPI::Analogs::AnalogType::LinearPositive) {
|
// relative mode assumes that user is using a stick, so center is neutral regardless of analog type
|
||||||
|
if (getType() != GameAPI::Analogs::AnalogType::LinearPositive || isRelativeMode()) {
|
||||||
|
|
||||||
// calculate values
|
// calculate values
|
||||||
const auto delta = value - 0.5f;
|
const auto delta = value - 0.5f;
|
||||||
@@ -291,3 +292,74 @@ float Analog::applyDeadzone(float raw_value) {
|
|||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Analog::getRelativeModeValue(float raw_value) {
|
||||||
|
const auto now = get_performance_seconds();
|
||||||
|
auto delta_time = now - this->rel_mode_last_read_time_s;
|
||||||
|
|
||||||
|
if (this->rel_mode_last_read_time_s != 0.f) {
|
||||||
|
// some heuristics to prevent huge jumps:
|
||||||
|
// * if we went for more than 250ms without polls, discard it (e.g., during loading screens)
|
||||||
|
// * cap the delta at 100ms to prevent huge jumps in case of very infrequent polling
|
||||||
|
if (delta_time < 0.f || 0.25f < delta_time) {
|
||||||
|
delta_time = 0.f;
|
||||||
|
} else if (delta_time > 0.1f) {
|
||||||
|
delta_time = 0.1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale [0, 1] to [-1, 1] to simplify calculations
|
||||||
|
const auto delta_raw_value = (raw_value - 0.5f) * 2.f;
|
||||||
|
|
||||||
|
// target is one revolution per second at max speed at 1.0 sensitivity
|
||||||
|
auto adjusted_delta_value = delta_raw_value * delta_time;
|
||||||
|
|
||||||
|
// multiplier / divisor
|
||||||
|
if (this->getMultiplier() > 1) {
|
||||||
|
adjusted_delta_value *= this->getMultiplier();
|
||||||
|
} else if (this->getMultiplier() < -1) {
|
||||||
|
adjusted_delta_value /= -this->getMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
// sensitivity
|
||||||
|
if (this->isSensitivitySet()) {
|
||||||
|
adjusted_delta_value *= this->getSensitivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the new absolute value
|
||||||
|
this->rel_mode_absolute_value += adjusted_delta_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update for next poll
|
||||||
|
this->rel_mode_last_read_time_s = now;
|
||||||
|
this->rel_mode_absolute_value = normalizeAnalogValue(this->rel_mode_absolute_value);
|
||||||
|
return this->rel_mode_absolute_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Analog::getDelayedValue(float raw_value) {
|
||||||
|
const double delay_ms = static_cast<double>(this->getDelayMs());
|
||||||
|
if (delay_ms == 0.0) {
|
||||||
|
return raw_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always push a new value
|
||||||
|
const auto now = get_performance_milliseconds();
|
||||||
|
this->delayed_inputs.emplace(now, raw_value);
|
||||||
|
|
||||||
|
// drain the queue down to reasonable length to prevent unconstrained growth
|
||||||
|
// this would accommodate 1 second at ~1000Hz which is overkill
|
||||||
|
// (UI only allows for 250ms of delay)
|
||||||
|
while (this->delayed_inputs.size() > 1024) {
|
||||||
|
this->delayed_inputs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop until we find the oldest value still inside the delay window
|
||||||
|
while (this->delayed_inputs.size() > 1) {
|
||||||
|
const auto delta_t = now - this->delayed_inputs.front().time_in_ms;
|
||||||
|
if (delta_t <= delay_ms) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->delayed_inputs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->delayed_inputs.front().value;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -34,6 +35,11 @@ struct AnalogMovingAverage {
|
|||||||
float cosine;
|
float cosine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AnalogDelayEntry {
|
||||||
|
double time_in_ms;
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
class Analog {
|
class Analog {
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -63,6 +69,15 @@ private:
|
|||||||
float divisor_previous_value = 0.5f;
|
float divisor_previous_value = 0.5f;
|
||||||
unsigned short divisor_region = 0;
|
unsigned short divisor_region = 0;
|
||||||
|
|
||||||
|
// relative input mode
|
||||||
|
float rel_mode_absolute_value = 0.5f;
|
||||||
|
float rel_mode_last_read_time_s = 0.f;
|
||||||
|
bool relative_mode = false;
|
||||||
|
|
||||||
|
// delay
|
||||||
|
uint32_t delay_ms = 0;
|
||||||
|
std::queue<AnalogDelayEntry> delayed_inputs;
|
||||||
|
|
||||||
float calculateAngularDifference(float old_rads, float new_rads);
|
float calculateAngularDifference(float old_rads, float new_rads);
|
||||||
float normalizeAngle(float rads);
|
float normalizeAngle(float rads);
|
||||||
float normalizeAnalogValue(float value);
|
float normalizeAnalogValue(float value);
|
||||||
@@ -83,6 +98,8 @@ public:
|
|||||||
float applyAngularSensitivity(float raw_rads);
|
float applyAngularSensitivity(float raw_rads);
|
||||||
float applyMultiplier(float raw_value);
|
float applyMultiplier(float raw_value);
|
||||||
float applyDeadzone(float raw_value);
|
float applyDeadzone(float raw_value);
|
||||||
|
float getRelativeModeValue(float raw_value);
|
||||||
|
float getDelayedValue(float raw_value);
|
||||||
|
|
||||||
inline bool isSet() {
|
inline bool isSet() {
|
||||||
if (this->override_enabled) {
|
if (this->override_enabled) {
|
||||||
@@ -98,7 +115,9 @@ public:
|
|||||||
smoothing = false;
|
smoothing = false;
|
||||||
deadzone_mirror = false;
|
deadzone_mirror = false;
|
||||||
setMultiplier(1);
|
setMultiplier(1);
|
||||||
|
setRelativeMode(false);
|
||||||
setLastState(0.5f);
|
setLastState(0.5f);
|
||||||
|
setDelayMs(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void clearBindings() {
|
inline void clearBindings() {
|
||||||
@@ -195,6 +214,19 @@ public:
|
|||||||
this->last_state = last_state;
|
this->last_state = last_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isRelativeMode() const {
|
||||||
|
return this->relative_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setRelativeMode(bool relative_mode) {
|
||||||
|
if (relative_mode) {
|
||||||
|
this->smoothing = false;
|
||||||
|
}
|
||||||
|
this->relative_mode = relative_mode;
|
||||||
|
this->rel_mode_absolute_value = 0.5f;
|
||||||
|
this->rel_mode_last_read_time_s = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
inline GameAPI::Analogs::AnalogType getType() const {
|
inline GameAPI::Analogs::AnalogType getType() const {
|
||||||
return this->type;
|
return this->type;
|
||||||
}
|
}
|
||||||
@@ -202,4 +234,12 @@ public:
|
|||||||
inline void setType(GameAPI::Analogs::AnalogType type) {
|
inline void setType(GameAPI::Analogs::AnalogType type) {
|
||||||
this->type = type;
|
this->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32_t getDelayMs() const {
|
||||||
|
return this->delay_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setDelayMs(uint32_t delay_ms) {
|
||||||
|
this->delay_ms = delay_ms;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-2
@@ -679,12 +679,18 @@ float GameAPI::Analogs::getState(rawinput::RawInputManager *manager, rawinput::D
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deadzone
|
// deadzone
|
||||||
// do not apply deadzone to circular analogs since it doesn't make sense
|
// do not apply deadzone to circular analogs since it doesn't make sense (except in relative mode)
|
||||||
if (analog.isDeadzoneSet() && analog.getType() != AnalogType::Circular) {
|
if (analog.isDeadzoneSet() &&
|
||||||
|
(analog.getType() != AnalogType::Circular || analog.isRelativeMode())) {
|
||||||
value = analog.applyDeadzone(value);
|
value = analog.applyDeadzone(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (analog.getType() == AnalogType::Circular) {
|
if (analog.getType() == AnalogType::Circular) {
|
||||||
|
|
||||||
|
if (analog.isRelativeMode()) {
|
||||||
|
value = analog.getRelativeModeValue(value);
|
||||||
|
|
||||||
|
} else {
|
||||||
// integer multiplier
|
// integer multiplier
|
||||||
value = analog.applyMultiplier(value);
|
value = analog.applyMultiplier(value);
|
||||||
|
|
||||||
@@ -712,6 +718,7 @@ float GameAPI::Analogs::getState(rawinput::RawInputManager *manager, rawinput::D
|
|||||||
// apply to value
|
// apply to value
|
||||||
value = rads * (float) M_1_TAU;
|
value = rads * (float) M_1_TAU;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// sensitivity
|
// sensitivity
|
||||||
if (analog.isSensitivitySet()) {
|
if (analog.isSensitivitySet()) {
|
||||||
@@ -760,6 +767,12 @@ float GameAPI::Analogs::getState(rawinput::RawInputManager *manager, rawinput::D
|
|||||||
value = std::clamp(value, 0.f, 1.f);
|
value = std::clamp(value, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delay
|
||||||
|
if (analog.getDelayMs() > 0) {
|
||||||
|
value = analog.getDelayedValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case rawinput::MIDI: {
|
case rawinput::MIDI: {
|
||||||
|
|||||||
@@ -252,6 +252,8 @@ bool Config::addGame(Game &game) {
|
|||||||
bool invert = false;
|
bool invert = false;
|
||||||
bool smoothing = false;
|
bool smoothing = false;
|
||||||
int multiplier = 1;
|
int multiplier = 1;
|
||||||
|
bool relative_mode = false;
|
||||||
|
uint32_t delay = 0;
|
||||||
tinyxml2::XMLError err1 = gameAnalogNode->QueryIntAttribute("index", &index);
|
tinyxml2::XMLError err1 = gameAnalogNode->QueryIntAttribute("index", &index);
|
||||||
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
|
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
|
||||||
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
|
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
|
||||||
@@ -259,6 +261,8 @@ bool Config::addGame(Game &game) {
|
|||||||
gameAnalogNode->QueryBoolAttribute("invert", &invert);
|
gameAnalogNode->QueryBoolAttribute("invert", &invert);
|
||||||
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
|
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
|
||||||
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
|
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
|
||||||
|
gameAnalogNode->QueryBoolAttribute("relative", &relative_mode);
|
||||||
|
gameAnalogNode->QueryUnsignedAttribute("delay_ms", &delay);
|
||||||
const char *devid = gameAnalogNode->Attribute("devid");
|
const char *devid = gameAnalogNode->Attribute("devid");
|
||||||
|
|
||||||
if (err1 != tinyxml2::XMLError::XML_SUCCESS || !devid) {
|
if (err1 != tinyxml2::XMLError::XML_SUCCESS || !devid) {
|
||||||
@@ -273,6 +277,8 @@ bool Config::addGame(Game &game) {
|
|||||||
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
||||||
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
||||||
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
||||||
|
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
|
||||||
|
gameAnalogNode->SetAttribute("delay_ms", it.getDelayMs());
|
||||||
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
||||||
} else {
|
} else {
|
||||||
it.setIndex(static_cast<unsigned short int>(index));
|
it.setIndex(static_cast<unsigned short int>(index));
|
||||||
@@ -283,6 +289,8 @@ bool Config::addGame(Game &game) {
|
|||||||
it.setInvert(invert);
|
it.setInvert(invert);
|
||||||
it.setSmoothing(smoothing);
|
it.setSmoothing(smoothing);
|
||||||
it.setMultiplier(multiplier);
|
it.setMultiplier(multiplier);
|
||||||
|
it.setRelativeMode(relative_mode);
|
||||||
|
it.setDelayMs(delay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gameAnalogNode = this->configFile.NewElement("analog");
|
gameAnalogNode = this->configFile.NewElement("analog");
|
||||||
@@ -294,6 +302,8 @@ bool Config::addGame(Game &game) {
|
|||||||
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
||||||
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
||||||
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
||||||
|
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
|
||||||
|
gameAnalogNode->SetAttribute("delay_ms", it.getDelayMs());
|
||||||
gameAnalogNode->SetAttribute("devid", it.getDeviceIdentifier().c_str());
|
gameAnalogNode->SetAttribute("devid", it.getDeviceIdentifier().c_str());
|
||||||
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
||||||
}
|
}
|
||||||
@@ -447,6 +457,8 @@ bool Config::addGame(Game &game) {
|
|||||||
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
gameAnalogNode->SetAttribute("invert", it.getInvert());
|
||||||
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
gameAnalogNode->SetAttribute("smoothing", it.getSmoothing());
|
||||||
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
gameAnalogNode->SetAttribute("multiplier", it.getMultiplier());
|
||||||
|
gameAnalogNode->SetAttribute("relative", it.isRelativeMode());
|
||||||
|
gameAnalogNode->SetAttribute("delay_ms", it.getDelayMs());
|
||||||
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,6 +691,8 @@ bool Config::updateBinding(const Game &game, const Analog &analog) {
|
|||||||
gameAnalogNode->SetAttribute("invert", analog.getInvert());
|
gameAnalogNode->SetAttribute("invert", analog.getInvert());
|
||||||
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
|
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
|
||||||
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
|
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
|
||||||
|
gameAnalogNode->SetAttribute("relative", analog.isRelativeMode());
|
||||||
|
gameAnalogNode->SetAttribute("delay_ms", analog.getDelayMs());
|
||||||
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
|
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
|
||||||
} else {
|
} else {
|
||||||
gameAnalogNode = this->configFile.NewElement("analog");
|
gameAnalogNode = this->configFile.NewElement("analog");
|
||||||
@@ -689,6 +703,8 @@ bool Config::updateBinding(const Game &game, const Analog &analog) {
|
|||||||
gameAnalogNode->SetAttribute("invert", analog.getInvert());
|
gameAnalogNode->SetAttribute("invert", analog.getInvert());
|
||||||
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
|
gameAnalogNode->SetAttribute("smoothing", analog.getSmoothing());
|
||||||
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
|
gameAnalogNode->SetAttribute("multiplier", analog.getMultiplier());
|
||||||
|
gameAnalogNode->SetAttribute("relative", analog.isRelativeMode());
|
||||||
|
gameAnalogNode->SetAttribute("delay_ms", analog.getDelayMs());
|
||||||
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
|
gameAnalogNode->SetAttribute("devid", analog.getDeviceIdentifier().c_str());
|
||||||
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
gameAnalogsNode->InsertEndChild(gameAnalogNode);
|
||||||
}
|
}
|
||||||
@@ -1125,6 +1141,8 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
|
|||||||
bool invert = false;
|
bool invert = false;
|
||||||
bool smoothing = false;
|
bool smoothing = false;
|
||||||
int multiplier = 1;
|
int multiplier = 1;
|
||||||
|
bool relative_mode = false;
|
||||||
|
uint32_t delay = 0;
|
||||||
gameAnalogNode->QueryIntAttribute("index", &index);
|
gameAnalogNode->QueryIntAttribute("index", &index);
|
||||||
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
|
gameAnalogNode->QueryFloatAttribute("sensivity", &sensitivity);
|
||||||
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
|
gameAnalogNode->QueryFloatAttribute("deadzone", &deadzone);
|
||||||
@@ -1132,6 +1150,8 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
|
|||||||
gameAnalogNode->QueryBoolAttribute("invert", &invert);
|
gameAnalogNode->QueryBoolAttribute("invert", &invert);
|
||||||
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
|
gameAnalogNode->QueryBoolAttribute("smoothing", &smoothing);
|
||||||
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
|
gameAnalogNode->QueryIntAttribute("multiplier", &multiplier);
|
||||||
|
gameAnalogNode->QueryBoolAttribute("relative", &relative_mode);
|
||||||
|
gameAnalogNode->QueryUnsignedAttribute("delay_ms", &delay);
|
||||||
const char *devid = gameAnalogNode->Attribute("devid");
|
const char *devid = gameAnalogNode->Attribute("devid");
|
||||||
|
|
||||||
// create analog and add to list
|
// create analog and add to list
|
||||||
@@ -1143,6 +1163,8 @@ std::vector<Analog> Config::getAnalogs(const std::string &gameName) {
|
|||||||
analog.setInvert(invert);
|
analog.setInvert(invert);
|
||||||
analog.setSmoothing(smoothing);
|
analog.setSmoothing(smoothing);
|
||||||
analog.setMultiplier(multiplier);
|
analog.setMultiplier(multiplier);
|
||||||
|
analog.setRelativeMode(relative_mode);
|
||||||
|
analog.setDelayMs(delay);
|
||||||
if (devid) {
|
if (devid) {
|
||||||
analog.setDeviceIdentifier(devid);
|
analog.setDeviceIdentifier(devid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ namespace overlay::windows {
|
|||||||
el->SetAttribute("invert", analog.invert);
|
el->SetAttribute("invert", analog.invert);
|
||||||
el->SetAttribute("smoothing", analog.smoothing);
|
el->SetAttribute("smoothing", analog.smoothing);
|
||||||
el->SetAttribute("multiplier", analog.multiplier);
|
el->SetAttribute("multiplier", analog.multiplier);
|
||||||
|
el->SetAttribute("relative", analog.relative_mode);
|
||||||
|
el->SetAttribute("delay_ms", analog.delay_ms);
|
||||||
parent->InsertEndChild(el);
|
parent->InsertEndChild(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +92,8 @@ namespace overlay::windows {
|
|||||||
el->QueryBoolAttribute("invert", &a.invert);
|
el->QueryBoolAttribute("invert", &a.invert);
|
||||||
el->QueryBoolAttribute("smoothing", &a.smoothing);
|
el->QueryBoolAttribute("smoothing", &a.smoothing);
|
||||||
el->QueryIntAttribute("multiplier", &a.multiplier);
|
el->QueryIntAttribute("multiplier", &a.multiplier);
|
||||||
|
el->QueryBoolAttribute("relative", &a.relative_mode);
|
||||||
|
el->QueryUnsignedAttribute("delay_ms", &a.delay_ms);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -783,42 +783,7 @@ namespace games::iidx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return higher 8 bit
|
// return higher 8 bit
|
||||||
uint8_t result = (uint8_t) (ret_value >> 2);
|
return (uint8_t)(ret_value >> 2);
|
||||||
|
|
||||||
// delay
|
|
||||||
if ((player == 0 && TT_DELAY_P1 > 0) ||
|
|
||||||
(player == 1 && TT_DELAY_P2 > 0)) {
|
|
||||||
|
|
||||||
static std::queue<std::pair<double, uint8_t>> delay_queue[2];
|
|
||||||
auto &queue = delay_queue[player];
|
|
||||||
|
|
||||||
const auto max_delta_ms =
|
|
||||||
static_cast<double>((player == 0) ? TT_DELAY_P1 : TT_DELAY_P2);
|
|
||||||
|
|
||||||
// always push a new value
|
|
||||||
const auto now = get_performance_milliseconds();
|
|
||||||
queue.push(std::make_pair(now, result));
|
|
||||||
|
|
||||||
// drain the queue down to reasonable length to prevent unconstrained growth
|
|
||||||
// this would accommodate 1 second at ~1000Hz
|
|
||||||
// (in reality all three iidx I/O emulation runs well under 500Hz)
|
|
||||||
while (queue.size() > 1024) {
|
|
||||||
queue.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop until we find one that falls just under the time threshold
|
|
||||||
while (!queue.empty()) {
|
|
||||||
const auto delta_t = now - queue.front().first;
|
|
||||||
if (delta_t <= max_delta_ms) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
queue.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
result = queue.front().second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char get_slider(uint8_t slider) {
|
unsigned char get_slider(uint8_t slider) {
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ namespace games::iidx {
|
|||||||
extern bool NATIVE_TOUCH;
|
extern bool NATIVE_TOUCH;
|
||||||
extern std::optional<std::string> SOUND_OUTPUT_DEVICE;
|
extern std::optional<std::string> SOUND_OUTPUT_DEVICE;
|
||||||
extern std::optional<std::string> ASIO_DRIVER;
|
extern std::optional<std::string> ASIO_DRIVER;
|
||||||
extern uint32_t TT_DELAY_P1;
|
|
||||||
extern uint32_t TT_DELAY_P2;
|
|
||||||
extern uint8_t DIGITAL_TT_SENS;
|
extern uint8_t DIGITAL_TT_SENS;
|
||||||
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
||||||
extern std::optional<std::string> SCREEN_MODE;
|
extern std::optional<std::string> SCREEN_MODE;
|
||||||
|
|||||||
@@ -518,12 +518,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::IIDXTDJMode].value_bool()) {
|
if (options[launcher::Options::IIDXTDJMode].value_bool()) {
|
||||||
games::iidx::TDJ_MODE = true;
|
games::iidx::TDJ_MODE = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::IIDXTTDelayP1].is_active()) {
|
|
||||||
games::iidx::TT_DELAY_P1 = options[launcher::Options::IIDXTTDelayP1].value_uint32();
|
|
||||||
}
|
|
||||||
if (options[launcher::Options::IIDXTTDelayP2].is_active()) {
|
|
||||||
games::iidx::TT_DELAY_P2 = options[launcher::Options::IIDXTTDelayP2].value_uint32();
|
|
||||||
}
|
|
||||||
if (options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].is_active()) {
|
if (options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].is_active()) {
|
||||||
games::iidx::DIGITAL_TT_SENS = (uint8_t)
|
games::iidx::DIGITAL_TT_SENS = (uint8_t)
|
||||||
options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].value_uint32();
|
options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].value_uint32();
|
||||||
|
|||||||
@@ -655,30 +655,6 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Beatmania IIDX",
|
.game_name = "Beatmania IIDX",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// IIDXTTDelayP1
|
|
||||||
.title = "IIDX TT Delay ms (Player 1)",
|
|
||||||
.name = "iidxttdelayp1",
|
|
||||||
.desc = "Delays turntable by number of milliseconds. "
|
|
||||||
"Delay will be *at most* the specified period; maximum error is dependent on the game's poll rate. "
|
|
||||||
"As usual, changing any option requires a restart. Default: 0 (no delay).",
|
|
||||||
.type = OptionType::Integer,
|
|
||||||
.setting_name = "(0-500)",
|
|
||||||
.game_name = "Beatmania IIDX",
|
|
||||||
.category = "Game Options (Advanced)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// IIDXTTDelayP2
|
|
||||||
.title = "IIDX TT Delay ms (Player 2)",
|
|
||||||
.name = "iidxttdelayp2",
|
|
||||||
.desc = "Delays turntable by number of milliseconds. "
|
|
||||||
"Delay will be *at most* the specified period; maximum error is dependent on the game's poll rate. "
|
|
||||||
"As usual, changing any option requires a restart. Default: 0 (no delay).",
|
|
||||||
.type = OptionType::Integer,
|
|
||||||
.setting_name = "(0-500)",
|
|
||||||
.game_name = "Beatmania IIDX",
|
|
||||||
.category = "Game Options (Advanced)",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// spice2x_IIDXDigitalTTSensitivity
|
// spice2x_IIDXDigitalTTSensitivity
|
||||||
.title = "IIDX Digital TT Sensitivity",
|
.title = "IIDX Digital TT Sensitivity",
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ namespace launcher {
|
|||||||
IIDXAsioDriver,
|
IIDXAsioDriver,
|
||||||
IIDXBIO2FW,
|
IIDXBIO2FW,
|
||||||
IIDXTDJMode,
|
IIDXTDJMode,
|
||||||
IIDXTTDelayP1,
|
|
||||||
IIDXTTDelayP2,
|
|
||||||
spice2x_IIDXDigitalTTSensitivity,
|
spice2x_IIDXDigitalTTSensitivity,
|
||||||
IIDXDigitalTTSocd,
|
IIDXDigitalTTSocd,
|
||||||
spice2x_IIDXLDJForce720p,
|
spice2x_IIDXLDJForce720p,
|
||||||
|
|||||||
@@ -2539,9 +2539,9 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hide deadzone for circular analog since it doesn't make any sense
|
// hide deadzone for circular analog since it doesn't make any sense (unless in relative mode)
|
||||||
if ((device->type == rawinput::HID || device->type == rawinput::MIDI) &&
|
if ((device->type == rawinput::HID || device->type == rawinput::MIDI) &&
|
||||||
analog.getType() != GameAPI::Analogs::AnalogType::Circular) {
|
((analog.getType() != GameAPI::Analogs::AnalogType::Circular) || analog.isRelativeMode())) {
|
||||||
auto deadzone = analog.getDeadzone();
|
auto deadzone = analog.getDeadzone();
|
||||||
|
|
||||||
// for back compat (before each analog had a type)
|
// for back compat (before each analog had a type)
|
||||||
@@ -2585,17 +2585,47 @@ namespace overlay::windows {
|
|||||||
if (analog.getType() == GameAPI::Analogs::AnalogType::Circular) {
|
if (analog.getType() == GameAPI::Analogs::AnalogType::Circular) {
|
||||||
// smoothing
|
// smoothing
|
||||||
bool smoothing = analog.getSmoothing();
|
bool smoothing = analog.getSmoothing();
|
||||||
|
ImGui::BeginDisabled(analog.isRelativeMode());
|
||||||
ImGui::Checkbox("Smooth Axis (adds latency)", &smoothing);
|
ImGui::Checkbox("Smooth Axis (adds latency)", &smoothing);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::HelpMarker(
|
ImGui::HelpMarker(
|
||||||
"Apply a moving average algorithm; intended for angular input (knobs, turntables). "
|
"Apply a moving average algorithm; intended for angular input (knobs, turntables). "
|
||||||
"Adds a slight bit of latency to input as the algorithm averages out recent input. "
|
"Adds a slight bit of latency to input as the algorithm averages out recent input. "
|
||||||
"Only use in dire situations where the input is too jittery for the game.");
|
"Only use in dire situations where the input is too jittery for the game.");
|
||||||
|
ImGui::EndDisabled();
|
||||||
if (smoothing != analog.getSmoothing()) {
|
if (smoothing != analog.getSmoothing()) {
|
||||||
analog.setSmoothing(smoothing);
|
analog.setSmoothing(smoothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// relative input mode
|
||||||
|
bool relative_analog = analog.isRelativeMode();
|
||||||
|
ImGui::Checkbox("Relative Axis", &relative_analog);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker(
|
||||||
|
"Use relative directional input instead of positional values. "
|
||||||
|
"Can be used to translate analog sticks to knob input.\n\n"
|
||||||
|
"At default settings, max speed is one revolution per second.\n\n"
|
||||||
|
"Adjust sensitivity to increase/decrease max speed, and deadzone to prevent jitter.");
|
||||||
|
if (relative_analog != analog.isRelativeMode()) {
|
||||||
|
analog.setRelativeMode(relative_analog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delay
|
||||||
|
int delay = analog.getDelayMs();
|
||||||
|
if (ImGui::InputInt("Delay (ms)", &delay, 1, 1)) {
|
||||||
|
delay = std::clamp(delay, 0, 250);
|
||||||
|
analog.setDelayMs(delay);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker(
|
||||||
|
"Adds an artificial delay, in milliseconds.\n\n"
|
||||||
|
"Value read by the game engine will be delayed AT MOST this amount of time (coould be slightly less).\n\n"
|
||||||
|
"To minimize quantization error, delay value should be a multiple of the game's poll rate, "
|
||||||
|
"add 0.5ms of buffer, and then round up to the nearest millisecond.\n\n"
|
||||||
|
"If you aren't sure, assume the game polls for input at the same rate as the display FPS."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// current state
|
// current state
|
||||||
@@ -5406,6 +5436,8 @@ namespace overlay::windows {
|
|||||||
a.setInvert(ta.invert);
|
a.setInvert(ta.invert);
|
||||||
a.setSmoothing(ta.smoothing);
|
a.setSmoothing(ta.smoothing);
|
||||||
a.setMultiplier(ta.multiplier);
|
a.setMultiplier(ta.multiplier);
|
||||||
|
a.setRelativeMode(ta.relative_mode);
|
||||||
|
a.setDelayMs(ta.delay_ms);
|
||||||
::Config::getInstance().updateBinding(game, a);
|
::Config::getInstance().updateBinding(game, a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ namespace overlay::windows {
|
|||||||
bool invert = false;
|
bool invert = false;
|
||||||
bool smoothing = false;
|
bool smoothing = false;
|
||||||
int multiplier = 1;
|
int multiplier = 1;
|
||||||
|
bool relative_mode = false;
|
||||||
|
uint32_t delay_ms = 0;
|
||||||
|
|
||||||
bool is_device() const { return !device_identifier.empty(); }
|
bool is_device() const { return !device_identifier.empty(); }
|
||||||
bool is_unbound() const { return device_identifier.empty() && index == 0xFF; }
|
bool is_unbound() const { return device_identifier.empty() && index == 0xFF; }
|
||||||
@@ -87,6 +89,8 @@ namespace overlay::windows {
|
|||||||
invert = a.getInvert();
|
invert = a.getInvert();
|
||||||
smoothing = a.getSmoothing();
|
smoothing = a.getSmoothing();
|
||||||
multiplier = a.getMultiplier();
|
multiplier = a.getMultiplier();
|
||||||
|
relative_mode = a.isRelativeMode();
|
||||||
|
delay_ms = a.getDelayMs();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user