forked from TeamTofuShop/segatools
idz, idac, swdc: Added separate pedals config, better XInput controls
- Configure separate pedals which are not part of the steering wheel (base) - It is now possible to have a different steering wheel, pedal and shifter brand all connected to 3 different USB ports - XInput does not have a deadzone at the end of the max steering anymore and the `restrict` setting works as intended
This commit is contained in:
77
idacio/xi.c
77
idacio/xi.c
@ -30,6 +30,11 @@ static bool idac_xi_linear_steering;
|
||||
static uint16_t idac_xi_left_stick_deadzone;
|
||||
static uint16_t idac_xi_right_stick_deadzone;
|
||||
|
||||
const uint16_t max_stick_value = 32767;
|
||||
/* Apply steering wheel restriction. Real cabs only report about 76% of
|
||||
the output value when the wheel is turned to either of its maximum positions. */
|
||||
const uint16_t max_wheel_value = 24831;
|
||||
|
||||
HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) {
|
||||
HRESULT hr;
|
||||
assert(cfg != NULL);
|
||||
@ -143,29 +148,39 @@ static void idac_xi_get_shifter(uint8_t *gear) {
|
||||
*gear = idac_shifter_current_gear();
|
||||
}
|
||||
|
||||
static int apply_non_linear_transform(int value, int deadzone_center) {
|
||||
const int max_input = 32767;
|
||||
const double power_factor = 3.0;
|
||||
static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) {
|
||||
// determine how far the controller is pushed
|
||||
float magnitude = sqrt(axis*axis);
|
||||
|
||||
// Apply deadzone only after passing the center threshold
|
||||
if (abs(value) < deadzone_center) {
|
||||
return 0;
|
||||
// determine the direction the controller is pushed
|
||||
float norm_axis = axis / magnitude;
|
||||
|
||||
float norm_magnitude = 0.0;
|
||||
|
||||
// check if the controller is outside a circular dead zone
|
||||
if (magnitude > deadzone)
|
||||
{
|
||||
// clip the magnitude at its expected maximum value
|
||||
if (magnitude > max_stick_value) magnitude = max_stick_value;
|
||||
|
||||
// adjust magnitude relative to the end of the dead zone
|
||||
magnitude -= deadzone;
|
||||
|
||||
// optionally normalize the magnitude with respect to its expected range
|
||||
// giving a magnitude value of 0.0 to 1.0
|
||||
norm_magnitude = magnitude / (max_stick_value - deadzone);
|
||||
} else // if the controller is in the deadzone zero out the magnitude
|
||||
{
|
||||
magnitude = 0.0;
|
||||
norm_magnitude = 0.0;
|
||||
}
|
||||
|
||||
// Scale the value to the range [-1.0, 1.0]
|
||||
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
||||
// apply non-linear transform to the axis
|
||||
if (!linear_steering) {
|
||||
return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value;
|
||||
}
|
||||
|
||||
// Apply a non-linear transform (cubing in this case) and preserve the sign
|
||||
double signed_value = copysign(pow(scaled_value, power_factor), value);
|
||||
|
||||
// Scale the value back to the range [-32770, 32767]
|
||||
int transformed_value = (int)(signed_value * max_input);
|
||||
|
||||
// Clamp the value to the range [-32767, 32767]
|
||||
transformed_value = (transformed_value > max_input) ? max_input : transformed_value;
|
||||
transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value;
|
||||
|
||||
return transformed_value;
|
||||
return norm_axis * norm_magnitude * max_wheel_value;
|
||||
}
|
||||
|
||||
static void idac_xi_get_analogs(struct idac_io_analog_state *out) {
|
||||
@ -181,27 +196,9 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) {
|
||||
left = xi.Gamepad.sThumbLX;
|
||||
right = xi.Gamepad.sThumbRX;
|
||||
|
||||
if (!idac_xi_linear_steering) {
|
||||
// Apply non-linear transform for both sticks
|
||||
left = apply_non_linear_transform(left, idac_xi_left_stick_deadzone);
|
||||
right = apply_non_linear_transform(right, idac_xi_right_stick_deadzone);
|
||||
} else {
|
||||
if (left < -idac_xi_left_stick_deadzone) {
|
||||
left += idac_xi_left_stick_deadzone;
|
||||
} else if (left > idac_xi_left_stick_deadzone) {
|
||||
left -= idac_xi_left_stick_deadzone;
|
||||
} else {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
if (right < -idac_xi_right_stick_deadzone) {
|
||||
right += idac_xi_right_stick_deadzone;
|
||||
} else if (right > idac_xi_right_stick_deadzone) {
|
||||
right -= idac_xi_right_stick_deadzone;
|
||||
} else {
|
||||
right = 0;
|
||||
}
|
||||
}
|
||||
// normalize the steering axis
|
||||
left = calculate_norm_steering(left, idac_xi_left_stick_deadzone, idac_xi_linear_steering);
|
||||
right = calculate_norm_steering(right, idac_xi_right_stick_deadzone, idac_xi_linear_steering);
|
||||
|
||||
if (idac_xi_single_stick_steering) {
|
||||
out->wheel = left;
|
||||
|
Reference in New Issue
Block a user