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:
@ -24,6 +24,14 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename)
|
||||
_countof(cfg->device_name),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"dinput",
|
||||
L"pedalsName",
|
||||
L"",
|
||||
cfg->pedals_name,
|
||||
_countof(cfg->pedals_name),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"dinput",
|
||||
L"shifterName",
|
||||
@ -79,7 +87,7 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename)
|
||||
cfg->single_stick_steering = GetPrivateProfileIntW(
|
||||
L"xinput",
|
||||
L"singleStickSteering",
|
||||
0,
|
||||
1,
|
||||
filename);
|
||||
|
||||
cfg->linear_steering = GetPrivateProfileIntW(
|
||||
|
@ -11,6 +11,7 @@ struct idz_shifter_config {
|
||||
struct idz_di_config {
|
||||
wchar_t device_name[64];
|
||||
wchar_t shifter_name[64];
|
||||
wchar_t pedals_name[64];
|
||||
wchar_t brake_axis[16];
|
||||
wchar_t accel_axis[16];
|
||||
uint8_t start;
|
||||
|
95
idzio/di.c
95
idzio/di.c
@ -26,6 +26,9 @@ static const struct idz_di_axis *idz_di_get_axis(const wchar_t *name);
|
||||
static BOOL CALLBACK idz_di_enum_callback(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
void *ctx);
|
||||
static BOOL CALLBACK idz_di_enum_callback_pedals(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
void *ctx);
|
||||
static BOOL CALLBACK idz_di_enum_callback_shifter(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
void *ctx);
|
||||
@ -57,6 +60,7 @@ static const struct idz_io_backend idz_di_backend = {
|
||||
static HWND idz_di_wnd;
|
||||
static IDirectInput8W *idz_di_api;
|
||||
static IDirectInputDevice8W *idz_di_dev;
|
||||
static IDirectInputDevice8W *idz_di_pedals;
|
||||
static IDirectInputDevice8W *idz_di_shifter;
|
||||
static IDirectInputEffect *idz_di_fx;
|
||||
static size_t idz_di_off_brake;
|
||||
@ -66,6 +70,7 @@ static uint8_t idz_di_shift_up;
|
||||
static uint8_t idz_di_view_chg;
|
||||
static uint8_t idz_di_start;
|
||||
static uint8_t idz_di_gear[6];
|
||||
static bool idz_di_use_pedals;
|
||||
static bool idz_di_reverse_brake_axis;
|
||||
static bool idz_di_reverse_accel_axis;
|
||||
|
||||
@ -168,6 +173,37 @@ HRESULT idz_di_init(
|
||||
|
||||
idz_di_dev_start_fx(idz_di_dev, &idz_di_fx);
|
||||
|
||||
if (cfg->pedals_name[0] != L'\0') {
|
||||
hr = IDirectInput8_EnumDevices(
|
||||
idz_di_api,
|
||||
DI8DEVCLASS_GAMECTRL,
|
||||
idz_di_enum_callback_pedals,
|
||||
(void *) cfg,
|
||||
DIEDFL_ATTACHEDONLY);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (idz_di_dev == NULL) {
|
||||
dprintf("Pedals: Controller not found\n");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
hr = idz_di_dev_start(idz_di_pedals, idz_di_wnd);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
idz_di_use_pedals = true;
|
||||
} else {
|
||||
idz_di_use_pedals = false;
|
||||
}
|
||||
|
||||
if (cfg->shifter_name[0] != L'\0') {
|
||||
hr = IDirectInput8_EnumDevices(
|
||||
idz_di_api,
|
||||
@ -262,8 +298,10 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg)
|
||||
dprintf("Wheel: --- Begin configuration ---\n");
|
||||
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
||||
cfg->device_name);
|
||||
dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name);
|
||||
dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name);
|
||||
if (cfg->pedals_name[0] == L'\0') {
|
||||
dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name);
|
||||
dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name);
|
||||
}
|
||||
dprintf("Wheel: Start button . . . : %i\n", cfg->start);
|
||||
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
||||
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
||||
@ -272,6 +310,15 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg)
|
||||
dprintf("Wheel: Reverse Accel Axis : %i\n", cfg->reverse_accel_axis);
|
||||
dprintf("Wheel: --- End configuration ---\n");
|
||||
|
||||
if (cfg->pedals_name[0] != L'\0') {
|
||||
dprintf("Pedals: --- Begin configuration ---\n");
|
||||
dprintf("Pedals: Device name . . . : Contains \"%S\"\n",
|
||||
cfg->pedals_name);
|
||||
dprintf("Pedals: Brake axis . . . . : %S\n", brake_axis->name);
|
||||
dprintf("Pedals: Accel axis . . . . : %S\n", accel_axis->name);
|
||||
dprintf("Pedals: --- End configuration ---\n");
|
||||
}
|
||||
|
||||
if (cfg->shifter_name[0] != L'\0') {
|
||||
dprintf("Shifter: --- Begin configuration ---\n");
|
||||
dprintf("Shifter: Device name . . . : Contains \"%S\"\n",
|
||||
@ -346,6 +393,34 @@ static BOOL CALLBACK idz_di_enum_callback(
|
||||
return DIENUM_STOP;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK idz_di_enum_callback_pedals(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
void *ctx)
|
||||
{
|
||||
const struct idz_di_config *cfg;
|
||||
HRESULT hr;
|
||||
|
||||
cfg = ctx;
|
||||
|
||||
if (wcsstr(dev->tszProductName, cfg->pedals_name) == NULL) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
dprintf("Pedals: Using DirectInput device \"%S\"\n", dev->tszProductName);
|
||||
|
||||
hr = IDirectInput8_CreateDevice(
|
||||
idz_di_api,
|
||||
&dev->guidInstance,
|
||||
&idz_di_pedals,
|
||||
NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr);
|
||||
}
|
||||
|
||||
return DIENUM_STOP;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK idz_di_enum_callback_shifter(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
void *ctx)
|
||||
@ -492,6 +567,7 @@ static void idz_di_jvs_read_shifter_virt(uint8_t *gear)
|
||||
static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||
{
|
||||
union idz_di_state state;
|
||||
union idz_di_state pedals_state;
|
||||
const LONG *brake;
|
||||
const LONG *accel;
|
||||
HRESULT hr;
|
||||
@ -504,8 +580,19 @@ static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||
return;
|
||||
}
|
||||
|
||||
brake = (LONG *) &state.bytes[idz_di_off_brake];
|
||||
accel = (LONG *) &state.bytes[idz_di_off_accel];
|
||||
if (idz_di_use_pedals) {
|
||||
hr = idz_di_dev_poll(idz_di_pedals, idz_di_wnd, &pedals_state);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
brake = (LONG *) &pedals_state.bytes[idz_di_off_brake];
|
||||
accel = (LONG *) &pedals_state.bytes[idz_di_off_accel];
|
||||
} else {
|
||||
brake = (LONG *) &state.bytes[idz_di_off_brake];
|
||||
accel = (LONG *) &state.bytes[idz_di_off_accel];
|
||||
}
|
||||
|
||||
out->wheel = state.st.lX - 32768;
|
||||
|
||||
|
77
idzio/xi.c
77
idzio/xi.c
@ -31,6 +31,11 @@ static bool idz_xi_linear_steering;
|
||||
static uint16_t idz_xi_left_stick_deadzone;
|
||||
static uint16_t idz_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 idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend)
|
||||
{
|
||||
HRESULT hr;
|
||||
@ -143,29 +148,39 @@ static void idz_xi_jvs_read_shifter(uint8_t *gear)
|
||||
*gear = idz_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 idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||
@ -182,27 +197,9 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||
left = xi.Gamepad.sThumbLX;
|
||||
right = xi.Gamepad.sThumbRX;
|
||||
|
||||
if (!idz_xi_linear_steering) {
|
||||
// Apply non-linear transform for both sticks
|
||||
left = apply_non_linear_transform(left, idz_xi_left_stick_deadzone);
|
||||
right = apply_non_linear_transform(right, idz_xi_right_stick_deadzone);
|
||||
} else {
|
||||
if (left < -idz_xi_left_stick_deadzone) {
|
||||
left += idz_xi_left_stick_deadzone;
|
||||
} else if (left > idz_xi_left_stick_deadzone) {
|
||||
left -= idz_xi_left_stick_deadzone;
|
||||
} else {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
if (right < -idz_xi_right_stick_deadzone) {
|
||||
right += idz_xi_right_stick_deadzone;
|
||||
} else if (right > idz_xi_right_stick_deadzone) {
|
||||
right -= idz_xi_right_stick_deadzone;
|
||||
} else {
|
||||
right = 0;
|
||||
}
|
||||
}
|
||||
// normalize the steering axis
|
||||
left = calculate_norm_steering(left, idz_xi_left_stick_deadzone, idz_xi_linear_steering);
|
||||
right = calculate_norm_steering(right, idz_xi_right_stick_deadzone, idz_xi_linear_steering);
|
||||
|
||||
if(idz_xi_single_stick_steering) {
|
||||
out->wheel = left;
|
||||
|
Reference in New Issue
Block a user