forked from Dniel97/segatools
idac, idz, swdc: Fixed DInput brake/accel, added cubic steering
This commit is contained in:
parent
28ef2d719a
commit
3dc2ec6e69
21
dist/idac/segatools.ini
vendored
21
dist/idac/segatools.ini
vendored
@ -65,6 +65,18 @@ path=
|
|||||||
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Input settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
|
||||||
|
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||||
|
;
|
||||||
|
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||||
|
;
|
||||||
|
; This is, admittedly, not the most user-friendly configuration method in the
|
||||||
|
; world. An improved solution will be provided later.
|
||||||
|
|
||||||
[io4]
|
[io4]
|
||||||
; Test button virtual-key code. Default is the 1 key.
|
; Test button virtual-key code. Default is the 1 key.
|
||||||
test=0x31
|
test=0x31
|
||||||
@ -72,6 +84,7 @@ test=0x31
|
|||||||
service=0x32
|
service=0x32
|
||||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||||
coin=0x33
|
coin=0x33
|
||||||
|
|
||||||
; Input API selection for IO4 input emulator.
|
; Input API selection for IO4 input emulator.
|
||||||
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
||||||
mode=xinput
|
mode=xinput
|
||||||
@ -79,20 +92,22 @@ mode=xinput
|
|||||||
; pressed (e.g. when navigating menus between races).
|
; pressed (e.g. when navigating menus between races).
|
||||||
autoNeutral=1
|
autoNeutral=1
|
||||||
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
||||||
; Not recommended as it will not give you the precision needed for this game
|
; Not recommended as it will not give you the precision needed for this game.
|
||||||
singleStickSteering=1
|
singleStickSteering=1
|
||||||
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
|
linearSteering=0
|
||||||
; Adjust scaling for steering wheel input.
|
; Adjust scaling for steering wheel input.
|
||||||
;
|
;
|
||||||
; This setting scales the steering wheel input so that the maximum positive
|
; This setting scales the steering wheel input so that the maximum positive
|
||||||
; and minimum negative steering inputs reported in the operator menu's input
|
; and minimum negative steering inputs reported in the operator menu's input
|
||||||
; test screen do not exceed the value below. The maximum possible value is 128,
|
; test screen do not exceed the value below. The maximum possible value is 128,
|
||||||
; and the value that matches the input range of a real cabinet is 97.
|
; and the value that matches the input range of a real cabinet is 128.
|
||||||
;
|
;
|
||||||
; NOTE: This is not the same thing as DirectInput steering wheel movement
|
; NOTE: This is not the same thing as DirectInput steering wheel movement
|
||||||
; range! Segatools cannot control the maximum angle of your physical steering
|
; range! Segatools cannot control the maximum angle of your physical steering
|
||||||
; wheel controller, this setting is vendor-specific and can only be adjusted
|
; wheel controller, this setting is vendor-specific and can only be adjusted
|
||||||
; in the Control Panel.
|
; in the Control Panel.
|
||||||
restrict=97
|
restrict=128
|
||||||
|
|
||||||
[dinput]
|
[dinput]
|
||||||
; Name of the DirectInput wheel to use (or any text that occurs in its name)
|
; Name of the DirectInput wheel to use (or any text that occurs in its name)
|
||||||
|
30
dist/idz/segatools.ini
vendored
30
dist/idz/segatools.ini
vendored
@ -8,6 +8,11 @@ option=
|
|||||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||||
appdata=
|
appdata=
|
||||||
|
|
||||||
|
[aime]
|
||||||
|
; Controls emulation of the Aime card reader assembly.
|
||||||
|
enable=1
|
||||||
|
aimePath=DEVICE\aime.txt
|
||||||
|
|
||||||
[dns]
|
[dns]
|
||||||
; Insert the hostname or IP address of the server you wish to use here.
|
; Insert the hostname or IP address of the server you wish to use here.
|
||||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||||
@ -50,7 +55,26 @@ path=
|
|||||||
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Input settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
|
||||||
|
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||||
|
;
|
||||||
|
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||||
|
;
|
||||||
|
; This is, admittedly, not the most user-friendly configuration method in the
|
||||||
|
; world. An improved solution will be provided later.
|
||||||
|
|
||||||
[io3]
|
[io3]
|
||||||
|
; Test button virtual-key code. Default is the 1 key.
|
||||||
|
test=0x31
|
||||||
|
; Service button virtual-key code. Default is the 2 key.
|
||||||
|
service=0x32
|
||||||
|
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||||
|
coin=0x33
|
||||||
|
|
||||||
; Input API selection for JVS input emulator.
|
; Input API selection for JVS input emulator.
|
||||||
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
||||||
mode=xinput
|
mode=xinput
|
||||||
@ -58,8 +82,10 @@ mode=xinput
|
|||||||
; pressed (e.g. when navigating menus between races).
|
; pressed (e.g. when navigating menus between races).
|
||||||
autoNeutral=1
|
autoNeutral=1
|
||||||
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
||||||
; Not recommended as it will not give you the precision needed for this game
|
; Not recommended as it will not give you the precision needed for this game.
|
||||||
singleStickSteering=0
|
singleStickSteering=1
|
||||||
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
|
linearSteering=0
|
||||||
; Adjust scaling for steering wheel input.
|
; Adjust scaling for steering wheel input.
|
||||||
;
|
;
|
||||||
; This setting scales the steering wheel input so that the maximum positive
|
; This setting scales the steering wheel input so that the maximum positive
|
||||||
|
21
dist/swdc/segatools.ini
vendored
21
dist/swdc/segatools.ini
vendored
@ -40,6 +40,18 @@ path=
|
|||||||
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Input settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
|
||||||
|
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||||
|
;
|
||||||
|
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||||
|
;
|
||||||
|
; This is, admittedly, not the most user-friendly configuration method in the
|
||||||
|
; world. An improved solution will be provided later.
|
||||||
|
|
||||||
[io4]
|
[io4]
|
||||||
; Test button virtual-key code. Default is the 1 key.
|
; Test button virtual-key code. Default is the 1 key.
|
||||||
test=0x31
|
test=0x31
|
||||||
@ -49,22 +61,25 @@ service=0x32
|
|||||||
coin=0x33
|
coin=0x33
|
||||||
; Input API selection for IO4 input emulator.
|
; Input API selection for IO4 input emulator.
|
||||||
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
||||||
|
|
||||||
mode=xinput
|
mode=xinput
|
||||||
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
||||||
; Not recommended as it will not give you the precision needed for this game
|
; Not recommended as it will not give you the precision needed for this game.
|
||||||
singleStickSteering=1
|
singleStickSteering=1
|
||||||
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
|
linearSteering=0
|
||||||
; Adjust scaling for steering wheel input.
|
; Adjust scaling for steering wheel input.
|
||||||
;
|
;
|
||||||
; This setting scales the steering wheel input so that the maximum positive
|
; This setting scales the steering wheel input so that the maximum positive
|
||||||
; and minimum negative steering inputs reported in the operator menu's input
|
; and minimum negative steering inputs reported in the operator menu's input
|
||||||
; test screen do not exceed the value below. The maximum possible value is 128,
|
; test screen do not exceed the value below. The maximum possible value is 128,
|
||||||
; and the value that matches the input range of a real cabinet is 97.
|
; and the value that matches the input range of a real cabinet is 128.
|
||||||
;
|
;
|
||||||
; NOTE: This is not the same thing as DirectInput steering wheel movement
|
; NOTE: This is not the same thing as DirectInput steering wheel movement
|
||||||
; range! Segatools cannot control the maximum angle of your physical steering
|
; range! Segatools cannot control the maximum angle of your physical steering
|
||||||
; wheel controller, this setting is vendor-specific and can only be adjusted
|
; wheel controller, this setting is vendor-specific and can only be adjusted
|
||||||
; in the Control Panel.
|
; in the Control Panel.
|
||||||
restrict=97
|
restrict=128
|
||||||
|
|
||||||
[dinput]
|
[dinput]
|
||||||
; Name of the DirectInput wheel to use (or any text that occurs in its name)
|
; Name of the DirectInput wheel to use (or any text that occurs in its name)
|
||||||
|
@ -81,6 +81,12 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename)
|
|||||||
L"singleStickSteering",
|
L"singleStickSteering",
|
||||||
0,
|
0,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
cfg->linear_steering = GetPrivateProfileIntW(
|
||||||
|
L"io4",
|
||||||
|
L"linearSteering",
|
||||||
|
0,
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename)
|
void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename)
|
||||||
|
@ -24,6 +24,7 @@ struct idac_di_config {
|
|||||||
|
|
||||||
struct idac_xi_config {
|
struct idac_xi_config {
|
||||||
bool single_stick_steering;
|
bool single_stick_steering;
|
||||||
|
bool linear_steering;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct idac_io_config {
|
struct idac_io_config {
|
||||||
|
@ -262,8 +262,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
|||||||
dprintf("Wheel: --- Begin configuration ---\n");
|
dprintf("Wheel: --- Begin configuration ---\n");
|
||||||
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
||||||
cfg->device_name);
|
cfg->device_name);
|
||||||
dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name);
|
dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name);
|
||||||
dprintf("Wheel: Accelerator 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: Start button . . . : %i\n", cfg->start);
|
||||||
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
||||||
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
||||||
@ -286,8 +286,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
|||||||
dprintf("Shifter: --- End configuration ---\n");
|
dprintf("Shifter: --- End configuration ---\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
idac_di_off_brake = accel_axis->off;
|
idac_di_off_brake = brake_axis->off;
|
||||||
idac_di_off_accel = brake_axis->off;
|
idac_di_off_accel = accel_axis->off;
|
||||||
idac_di_start = cfg->start;
|
idac_di_start = cfg->start;
|
||||||
idac_di_view_chg = cfg->view_chg;
|
idac_di_view_chg = cfg->view_chg;
|
||||||
idac_di_shift_dn = cfg->shift_dn;
|
idac_di_shift_dn = cfg->shift_dn;
|
||||||
|
64
idacio/xi.c
64
idacio/xi.c
@ -1,16 +1,16 @@
|
|||||||
#include <windows.h>
|
#include "idacio/xi.h"
|
||||||
#include <xinput.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <xinput.h>
|
||||||
|
|
||||||
#include "idacio/backend.h"
|
#include "idacio/backend.h"
|
||||||
#include "idacio/config.h"
|
#include "idacio/config.h"
|
||||||
#include "idacio/idacio.h"
|
#include "idacio/idacio.h"
|
||||||
#include "idacio/shifter.h"
|
#include "idacio/shifter.h"
|
||||||
#include "idacio/xi.h"
|
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out);
|
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out);
|
||||||
@ -26,9 +26,9 @@ static const struct idac_io_backend idac_xi_backend = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool idac_xi_single_stick_steering;
|
static bool idac_xi_single_stick_steering;
|
||||||
|
static bool idac_xi_linear_steering;
|
||||||
|
|
||||||
HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend)
|
HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) {
|
||||||
{
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(backend != NULL);
|
assert(backend != NULL);
|
||||||
@ -45,24 +45,23 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT idac_io_poll(void)
|
HRESULT idac_io_poll(void) {
|
||||||
{
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg)
|
static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) {
|
||||||
{
|
|
||||||
dprintf("XInput: --- Begin configuration ---\n");
|
dprintf("XInput: --- Begin configuration ---\n");
|
||||||
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
||||||
|
dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering);
|
||||||
dprintf("XInput: --- End configuration ---\n");
|
dprintf("XInput: --- End configuration ---\n");
|
||||||
|
|
||||||
idac_xi_single_stick_steering = cfg->single_stick_steering;
|
idac_xi_single_stick_steering = cfg->single_stick_steering;
|
||||||
|
idac_xi_linear_steering = cfg->linear_steering;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out)
|
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) {
|
||||||
{
|
|
||||||
uint8_t gamebtn;
|
uint8_t gamebtn;
|
||||||
XINPUT_STATE xi;
|
XINPUT_STATE xi;
|
||||||
WORD xb;
|
WORD xb;
|
||||||
@ -102,8 +101,7 @@ static void idac_xi_get_gamebtns(uint8_t *gamebtn_out)
|
|||||||
*gamebtn_out = gamebtn;
|
*gamebtn_out = gamebtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void idac_xi_get_shifter(uint8_t *gear)
|
static void idac_xi_get_shifter(uint8_t *gear) {
|
||||||
{
|
|
||||||
bool shift_dn;
|
bool shift_dn;
|
||||||
bool shift_up;
|
bool shift_up;
|
||||||
XINPUT_STATE xi;
|
XINPUT_STATE xi;
|
||||||
@ -144,8 +142,32 @@ static void idac_xi_get_shifter(uint8_t *gear)
|
|||||||
*gear = idac_shifter_current_gear();
|
*gear = idac_shifter_current_gear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void idac_xi_get_analogs(struct idac_io_analog_state *out)
|
static int apply_non_linear_transform(int value, int deadzone_center) {
|
||||||
{
|
const int max_input = 32767;
|
||||||
|
const double power_factor = 3.0;
|
||||||
|
|
||||||
|
// Apply deadzone only after passing the center threshold
|
||||||
|
if (abs(value) < deadzone_center) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the value to the range [-1.0, 1.0]
|
||||||
|
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idac_xi_get_analogs(struct idac_io_analog_state *out) {
|
||||||
XINPUT_STATE xi;
|
XINPUT_STATE xi;
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
@ -156,7 +178,13 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out)
|
|||||||
XInputGetState(0, &xi);
|
XInputGetState(0, &xi);
|
||||||
|
|
||||||
left = xi.Gamepad.sThumbLX;
|
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, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||||
|
right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
|
||||||
|
} else {
|
||||||
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
||||||
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
@ -165,8 +193,6 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out)
|
|||||||
left = 0;
|
left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
right = xi.Gamepad.sThumbRX;
|
|
||||||
|
|
||||||
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
||||||
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
@ -174,9 +200,11 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out)
|
|||||||
} else {
|
} else {
|
||||||
right = 0;
|
right = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (idac_xi_single_stick_steering) {
|
if (idac_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
|
// dprintf("XInput: Single Stick Steering: %i\n", out->wheel);
|
||||||
} else {
|
} else {
|
||||||
out->wheel = (left + right) / 2;
|
out->wheel = (left + right) / 2;
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,12 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename)
|
|||||||
L"singleStickSteering",
|
L"singleStickSteering",
|
||||||
0,
|
0,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
cfg->linear_steering = GetPrivateProfileIntW(
|
||||||
|
L"io3",
|
||||||
|
L"linearSteering",
|
||||||
|
0,
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename)
|
void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename)
|
||||||
|
@ -24,6 +24,7 @@ struct idz_di_config {
|
|||||||
|
|
||||||
struct idz_xi_config {
|
struct idz_xi_config {
|
||||||
bool single_stick_steering;
|
bool single_stick_steering;
|
||||||
|
bool linear_steering;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct idz_io_config {
|
struct idz_io_config {
|
||||||
|
@ -262,8 +262,8 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg)
|
|||||||
dprintf("Wheel: --- Begin configuration ---\n");
|
dprintf("Wheel: --- Begin configuration ---\n");
|
||||||
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
||||||
cfg->device_name);
|
cfg->device_name);
|
||||||
dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name);
|
dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name);
|
||||||
dprintf("Wheel: Accelerator 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: Start button . . . : %i\n", cfg->start);
|
||||||
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
||||||
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
||||||
@ -286,8 +286,8 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg)
|
|||||||
dprintf("Shifter: --- End configuration ---\n");
|
dprintf("Shifter: --- End configuration ---\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
idz_di_off_brake = accel_axis->off;
|
idz_di_off_brake = brake_axis->off;
|
||||||
idz_di_off_accel = brake_axis->off;
|
idz_di_off_accel = accel_axis->off;
|
||||||
idz_di_start = cfg->start;
|
idz_di_start = cfg->start;
|
||||||
idz_di_view_chg = cfg->view_chg;
|
idz_di_view_chg = cfg->view_chg;
|
||||||
idz_di_shift_dn = cfg->shift_dn;
|
idz_di_shift_dn = cfg->shift_dn;
|
||||||
|
38
idzio/xi.c
38
idzio/xi.c
@ -1,6 +1,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <xinput.h>
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -26,6 +27,7 @@ static const struct idz_io_backend idz_xi_backend = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool idz_xi_single_stick_steering;
|
static bool idz_xi_single_stick_steering;
|
||||||
|
static bool idz_xi_linear_steering;
|
||||||
|
|
||||||
HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend)
|
HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend)
|
||||||
{
|
{
|
||||||
@ -49,9 +51,11 @@ static HRESULT idz_xi_config_apply(const struct idz_xi_config *cfg)
|
|||||||
{
|
{
|
||||||
dprintf("XInput: --- Begin configuration ---\n");
|
dprintf("XInput: --- Begin configuration ---\n");
|
||||||
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
||||||
|
dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering);
|
||||||
dprintf("XInput: --- End configuration ---\n");
|
dprintf("XInput: --- End configuration ---\n");
|
||||||
|
|
||||||
idz_xi_single_stick_steering = cfg->single_stick_steering;
|
idz_xi_single_stick_steering = cfg->single_stick_steering;
|
||||||
|
idz_xi_linear_steering = cfg->linear_steering;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -123,6 +127,31 @@ static void idz_xi_jvs_read_shifter(uint8_t *gear)
|
|||||||
*gear = idz_shifter_current_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;
|
||||||
|
|
||||||
|
// Apply deadzone only after passing the center threshold
|
||||||
|
if (abs(value) < deadzone_center) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the value to the range [-1.0, 1.0]
|
||||||
|
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||||
{
|
{
|
||||||
XINPUT_STATE xi;
|
XINPUT_STATE xi;
|
||||||
@ -135,7 +164,13 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
|||||||
XInputGetState(0, &xi);
|
XInputGetState(0, &xi);
|
||||||
|
|
||||||
left = xi.Gamepad.sThumbLX;
|
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, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||||
|
right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
|
||||||
|
} else {
|
||||||
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
||||||
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
@ -144,8 +179,6 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
|||||||
left = 0;
|
left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
right = xi.Gamepad.sThumbRX;
|
|
||||||
|
|
||||||
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
||||||
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
@ -153,6 +186,7 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
|||||||
} else {
|
} else {
|
||||||
right = 0;
|
right = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(idz_xi_single_stick_steering) {
|
if(idz_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
|
@ -71,6 +71,12 @@ void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename)
|
|||||||
L"singleStickSteering",
|
L"singleStickSteering",
|
||||||
0,
|
0,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
cfg->linear_steering = GetPrivateProfileIntW(
|
||||||
|
L"io4",
|
||||||
|
L"linearSteering",
|
||||||
|
0,
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename)
|
void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename)
|
||||||
|
@ -26,6 +26,7 @@ struct swdc_di_config {
|
|||||||
|
|
||||||
struct swdc_xi_config {
|
struct swdc_xi_config {
|
||||||
bool single_stick_steering;
|
bool single_stick_steering;
|
||||||
|
bool linear_steering;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct swdc_io_config {
|
struct swdc_io_config {
|
||||||
|
@ -246,8 +246,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg)
|
|||||||
dprintf("Wheel: --- Begin configuration ---\n");
|
dprintf("Wheel: --- Begin configuration ---\n");
|
||||||
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
dprintf("Wheel: Device name . . . . : Contains \"%S\"\n",
|
||||||
cfg->device_name);
|
cfg->device_name);
|
||||||
dprintf("Wheel: Brake axis . . . . . . : %S\n", accel_axis->name);
|
dprintf("Wheel: Brake axis . . . . . . : %S\n", brake_axis->name);
|
||||||
dprintf("Wheel: Accelerator 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: Start button . . . . . : %i\n", cfg->start);
|
||||||
dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg);
|
dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg);
|
||||||
dprintf("Wheel: Shift Down button . . : %i\n", cfg->shift_dn);
|
dprintf("Wheel: Shift Down button . . : %i\n", cfg->shift_dn);
|
||||||
@ -260,8 +260,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg)
|
|||||||
dprintf("Wheel: Reverse Accel Axis . . : %i\n", cfg->reverse_accel_axis);
|
dprintf("Wheel: Reverse Accel Axis . . : %i\n", cfg->reverse_accel_axis);
|
||||||
dprintf("Wheel: --- End configuration ---\n");
|
dprintf("Wheel: --- End configuration ---\n");
|
||||||
|
|
||||||
swdc_di_off_brake = accel_axis->off;
|
swdc_di_off_brake = brake_axis->off;
|
||||||
swdc_di_off_accel = brake_axis->off;
|
swdc_di_off_accel = accel_axis->off;
|
||||||
swdc_di_start = cfg->start;
|
swdc_di_start = cfg->start;
|
||||||
swdc_di_view_chg = cfg->view_chg;
|
swdc_di_view_chg = cfg->view_chg;
|
||||||
swdc_di_shift_dn = cfg->shift_dn;
|
swdc_di_shift_dn = cfg->shift_dn;
|
||||||
|
38
swdcio/xi.c
38
swdcio/xi.c
@ -1,6 +1,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <xinput.h>
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -23,6 +24,7 @@ static const struct swdc_io_backend swdc_xi_backend = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool swdc_xi_single_stick_steering;
|
static bool swdc_xi_single_stick_steering;
|
||||||
|
static bool swdc_xi_linear_steering;
|
||||||
|
|
||||||
HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend)
|
HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend)
|
||||||
{
|
{
|
||||||
@ -51,9 +53,11 @@ static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg)
|
|||||||
{
|
{
|
||||||
dprintf("XInput: --- Begin configuration ---\n");
|
dprintf("XInput: --- Begin configuration ---\n");
|
||||||
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering);
|
||||||
|
dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering);
|
||||||
dprintf("XInput: --- End configuration ---\n");
|
dprintf("XInput: --- End configuration ---\n");
|
||||||
|
|
||||||
swdc_xi_single_stick_steering = cfg->single_stick_steering;
|
swdc_xi_single_stick_steering = cfg->single_stick_steering;
|
||||||
|
swdc_xi_linear_steering = cfg->linear_steering;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -123,6 +127,31 @@ static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out)
|
|||||||
*gamebtn_out = gamebtn;
|
*gamebtn_out = gamebtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int apply_non_linear_transform(int value, int deadzone_center) {
|
||||||
|
const int max_input = 32767;
|
||||||
|
const double power_factor = 3.0;
|
||||||
|
|
||||||
|
// Apply deadzone only after passing the center threshold
|
||||||
|
if (abs(value) < deadzone_center) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the value to the range [-1.0, 1.0]
|
||||||
|
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
||||||
{
|
{
|
||||||
XINPUT_STATE xi;
|
XINPUT_STATE xi;
|
||||||
@ -135,7 +164,13 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
|||||||
XInputGetState(0, &xi);
|
XInputGetState(0, &xi);
|
||||||
|
|
||||||
left = xi.Gamepad.sThumbLX;
|
left = xi.Gamepad.sThumbLX;
|
||||||
|
right = xi.Gamepad.sThumbRX;
|
||||||
|
|
||||||
|
if (!swdc_xi_linear_steering) {
|
||||||
|
// Apply non-linear transform for both sticks
|
||||||
|
left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||||
|
right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
|
||||||
|
} else {
|
||||||
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
||||||
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
} else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||||
@ -144,8 +179,6 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
|||||||
left = 0;
|
left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
right = xi.Gamepad.sThumbRX;
|
|
||||||
|
|
||||||
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
||||||
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
} else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||||
@ -153,6 +186,7 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
|||||||
} else {
|
} else {
|
||||||
right = 0;
|
right = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (swdc_xi_single_stick_steering) {
|
if (swdc_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
|
Loading…
Reference in New Issue
Block a user