forked from Dniel97/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:
parent
6c45d0995b
commit
d521eeb43e
@ -148,7 +148,6 @@ $(BUILD_DIR_ZIP)/mu3.zip:
|
|||||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE
|
||||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_64)/mu3hook/mu3hook.dll \
|
$(BUILD_DIR_64)/mu3hook/mu3hook.dll \
|
||||||
$(DIST_DIR)/mu3/config_hook.json \
|
|
||||||
$(DIST_DIR)/mu3/segatools.ini \
|
$(DIST_DIR)/mu3/segatools.ini \
|
||||||
$(DIST_DIR)/mu3/start.bat \
|
$(DIST_DIR)/mu3/start.bat \
|
||||||
$(BUILD_DIR_ZIP)/mu3
|
$(BUILD_DIR_ZIP)/mu3
|
||||||
@ -164,7 +163,6 @@ $(BUILD_DIR_ZIP)/mai2.zip:
|
|||||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
|
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
|
||||||
$(DIST_DIR)/mai2/config_hook.json \
|
|
||||||
$(DIST_DIR)/mai2/segatools.ini \
|
$(DIST_DIR)/mai2/segatools.ini \
|
||||||
$(DIST_DIR)/mai2/start.bat \
|
$(DIST_DIR)/mai2/start.bat \
|
||||||
$(BUILD_DIR_ZIP)/mai2
|
$(BUILD_DIR_ZIP)/mai2
|
||||||
@ -180,7 +178,6 @@ $(BUILD_DIR_ZIP)/cm.zip:
|
|||||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE
|
||||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_64)/cmhook/cmhook.dll \
|
$(BUILD_DIR_64)/cmhook/cmhook.dll \
|
||||||
$(DIST_DIR)/cm/config_hook.json \
|
|
||||||
$(DIST_DIR)/cm/segatools.ini \
|
$(DIST_DIR)/cm/segatools.ini \
|
||||||
$(DIST_DIR)/cm/start.bat \
|
$(DIST_DIR)/cm/start.bat \
|
||||||
$(BUILD_DIR_ZIP)/cm
|
$(BUILD_DIR_ZIP)/cm
|
||||||
|
12
dist/idac/segatools.ini
vendored
12
dist/idac/segatools.ini
vendored
@ -110,7 +110,7 @@ autoNeutral=1
|
|||||||
; 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.
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
linearSteering=0
|
linearSteering=1
|
||||||
; Configure deadzones for the left and right thumbsticks.
|
; Configure deadzones for the left and right thumbsticks.
|
||||||
; The default value for the left stick is 7849, max value is 32767.
|
; The default value for the left stick is 7849, max value is 32767.
|
||||||
leftStickDeadzone=7849
|
leftStickDeadzone=7849
|
||||||
@ -123,6 +123,12 @@ rightStickDeadzone=8689
|
|||||||
;
|
;
|
||||||
; If this is left blank then the first DirectInput device will be used.
|
; If this is left blank then the first DirectInput device will be used.
|
||||||
deviceName=
|
deviceName=
|
||||||
|
; Name of the DirectInput pedals to use (or any subset thereof).
|
||||||
|
; Leave blank if you do not have separate pedals; aka the pedals are part of
|
||||||
|
; the wheel.
|
||||||
|
;
|
||||||
|
; The pedals will be mapped to the accelAxis and brakeAxis.
|
||||||
|
pedalsName=
|
||||||
; Name of the positional shifter to use (or any subset thereof).
|
; Name of the positional shifter to use (or any subset thereof).
|
||||||
; Leave blank if you do not have a positional shifter; a positional shifter
|
; Leave blank if you do not have a positional shifter; a positional shifter
|
||||||
; will be simulated using the configured Shift Down and Shift Up buttons
|
; will be simulated using the configured Shift Down and Shift Up buttons
|
||||||
@ -150,8 +156,8 @@ viewChg=2
|
|||||||
left=7
|
left=7
|
||||||
right=8
|
right=8
|
||||||
; Button mappings for the simulated six-speed shifter.
|
; Button mappings for the simulated six-speed shifter.
|
||||||
shiftDn=5
|
shiftDn=6
|
||||||
shiftUp=6
|
shiftUp=5
|
||||||
; Button mappings for the positional shifter, if present.
|
; Button mappings for the positional shifter, if present.
|
||||||
gear1=13
|
gear1=13
|
||||||
gear2=14
|
gear2=14
|
||||||
|
8
dist/idz/segatools.ini
vendored
8
dist/idz/segatools.ini
vendored
@ -108,7 +108,7 @@ autoNeutral=1
|
|||||||
; 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.
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
linearSteering=0
|
linearSteering=1
|
||||||
; Configure deadzones for the left and right thumbsticks.
|
; Configure deadzones for the left and right thumbsticks.
|
||||||
; The default value for the left stick is 7849, max value is 32767.
|
; The default value for the left stick is 7849, max value is 32767.
|
||||||
leftStickDeadzone=7849
|
leftStickDeadzone=7849
|
||||||
@ -130,6 +130,12 @@ deviceName=
|
|||||||
;
|
;
|
||||||
; Example: G29
|
; Example: G29
|
||||||
shifterName=
|
shifterName=
|
||||||
|
; Name of the DirectInput pedals to use (or any subset thereof).
|
||||||
|
; Leave blank if you do not have separate pedals; aka the pedals are part of
|
||||||
|
; the wheel.
|
||||||
|
;
|
||||||
|
; The pedals will be mapped to the accelAxis and brakeAxis.
|
||||||
|
pedalsName=
|
||||||
; Pedal mappings. Valid axis names are:
|
; Pedal mappings. Valid axis names are:
|
||||||
;
|
;
|
||||||
; X, Y, Z, RX, RY, RZ, U, V
|
; X, Y, Z, RX, RY, RZ, U, V
|
||||||
|
8
dist/swdc/segatools.ini
vendored
8
dist/swdc/segatools.ini
vendored
@ -81,7 +81,7 @@ restrict=128
|
|||||||
; 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.
|
; Use linear steering instead of the default non-linear cubing steering.
|
||||||
linearSteering=0
|
linearSteering=1
|
||||||
; Configure deadzones for the left and right thumbsticks.
|
; Configure deadzones for the left and right thumbsticks.
|
||||||
; The default value for the left stick is 7849, max value is 32767.
|
; The default value for the left stick is 7849, max value is 32767.
|
||||||
leftStickDeadzone=7849
|
leftStickDeadzone=7849
|
||||||
@ -94,6 +94,12 @@ rightStickDeadzone=8689
|
|||||||
;
|
;
|
||||||
; If this is left blank then the first DirectInput device will be used.
|
; If this is left blank then the first DirectInput device will be used.
|
||||||
deviceName=
|
deviceName=
|
||||||
|
; Name of the DirectInput pedals to use (or any subset thereof).
|
||||||
|
; Leave blank if you do not have separate pedals; aka the pedals are part of
|
||||||
|
; the wheel.
|
||||||
|
;
|
||||||
|
; The pedals will be mapped to the accelAxis and brakeAxis.
|
||||||
|
pedalsName=
|
||||||
; Pedal mappings. Valid axis names are:
|
; Pedal mappings. Valid axis names are:
|
||||||
;
|
;
|
||||||
; X, Y, Z, RX, RY, RZ, U, V
|
; X, Y, Z, RX, RY, RZ, U, V
|
||||||
|
4
dist/swdc/start.bat
vendored
4
dist/swdc/start.bat
vendored
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
pushd %~dp0
|
pushd %~dp0
|
||||||
|
|
||||||
|
rem Matching Server
|
||||||
|
start /min ..\..\..\Tools\tdrserver.exe
|
||||||
REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json
|
REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json
|
||||||
start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json
|
start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json
|
||||||
REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet
|
REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet
|
||||||
inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
||||||
|
|
||||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
taskkill /f /im tdrserver.exe > nul 2>&1
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Game processes have terminated
|
echo Game processes have terminated
|
||||||
|
@ -92,6 +92,16 @@ don't know the name of your input device, you can find it in the windows
|
|||||||
controller panel. The quickest way to access it is to press Win+R, then type in
|
controller panel. The quickest way to access it is to press Win+R, then type in
|
||||||
`joy.cpl` and look at the list it will display.
|
`joy.cpl` and look at the list it will display.
|
||||||
|
|
||||||
|
### `pedalsName`
|
||||||
|
|
||||||
|
Default ` `
|
||||||
|
|
||||||
|
Name of the pedals to use (or any subset thereof). Leave blank if you do not
|
||||||
|
have separate pedals; aka the pedals are part of the wheel. The pedals will
|
||||||
|
be mapped to the `accelAxis` and `brakeAxis` which would normally be used by
|
||||||
|
the wheel defined under `deviceName`. The quickest way to access it is to press
|
||||||
|
Win+R, then type in `joy.cpl` and look at the list it will display.
|
||||||
|
|
||||||
### `shifterName`
|
### `shifterName`
|
||||||
|
|
||||||
Default ` `
|
Default ` `
|
||||||
|
@ -24,6 +24,14 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename)
|
|||||||
_countof(cfg->device_name),
|
_countof(cfg->device_name),
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"dinput",
|
||||||
|
L"pedalsName",
|
||||||
|
L"",
|
||||||
|
cfg->pedals_name,
|
||||||
|
_countof(cfg->pedals_name),
|
||||||
|
filename);
|
||||||
|
|
||||||
GetPrivateProfileStringW(
|
GetPrivateProfileStringW(
|
||||||
L"dinput",
|
L"dinput",
|
||||||
L"shifterName",
|
L"shifterName",
|
||||||
|
@ -10,6 +10,7 @@ struct idac_shifter_config {
|
|||||||
|
|
||||||
struct idac_di_config {
|
struct idac_di_config {
|
||||||
wchar_t device_name[64];
|
wchar_t device_name[64];
|
||||||
|
wchar_t pedals_name[64];
|
||||||
wchar_t shifter_name[64];
|
wchar_t shifter_name[64];
|
||||||
wchar_t brake_axis[16];
|
wchar_t brake_axis[16];
|
||||||
wchar_t accel_axis[16];
|
wchar_t accel_axis[16];
|
||||||
|
95
idacio/di.c
95
idacio/di.c
@ -26,6 +26,9 @@ static const struct idac_di_axis *idac_di_get_axis(const wchar_t *name);
|
|||||||
static BOOL CALLBACK idac_di_enum_callback(
|
static BOOL CALLBACK idac_di_enum_callback(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
|
static BOOL CALLBACK idac_di_enum_callback_pedals(
|
||||||
|
const DIDEVICEINSTANCEW *dev,
|
||||||
|
void *ctx);
|
||||||
static BOOL CALLBACK idac_di_enum_callback_shifter(
|
static BOOL CALLBACK idac_di_enum_callback_shifter(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
@ -57,6 +60,7 @@ static const struct idac_io_backend idac_di_backend = {
|
|||||||
static HWND idac_di_wnd;
|
static HWND idac_di_wnd;
|
||||||
static IDirectInput8W *idac_di_api;
|
static IDirectInput8W *idac_di_api;
|
||||||
static IDirectInputDevice8W *idac_di_dev;
|
static IDirectInputDevice8W *idac_di_dev;
|
||||||
|
static IDirectInputDevice8W *idac_di_pedals;
|
||||||
static IDirectInputDevice8W *idac_di_shifter;
|
static IDirectInputDevice8W *idac_di_shifter;
|
||||||
static IDirectInputEffect *idac_di_fx;
|
static IDirectInputEffect *idac_di_fx;
|
||||||
static size_t idac_di_off_brake;
|
static size_t idac_di_off_brake;
|
||||||
@ -68,6 +72,7 @@ static uint8_t idac_di_start;
|
|||||||
static uint8_t idac_di_left;
|
static uint8_t idac_di_left;
|
||||||
static uint8_t idac_di_right;
|
static uint8_t idac_di_right;
|
||||||
static uint8_t idac_di_gear[6];
|
static uint8_t idac_di_gear[6];
|
||||||
|
static bool idac_di_use_pedals;
|
||||||
static bool idac_di_reverse_brake_axis;
|
static bool idac_di_reverse_brake_axis;
|
||||||
static bool idac_di_reverse_accel_axis;
|
static bool idac_di_reverse_accel_axis;
|
||||||
|
|
||||||
@ -170,6 +175,37 @@ HRESULT idac_di_init(
|
|||||||
|
|
||||||
idac_di_dev_start_fx(idac_di_dev, &idac_di_fx);
|
idac_di_dev_start_fx(idac_di_dev, &idac_di_fx);
|
||||||
|
|
||||||
|
if (cfg->pedals_name[0] != L'\0') {
|
||||||
|
hr = IDirectInput8_EnumDevices(
|
||||||
|
idac_di_api,
|
||||||
|
DI8DEVCLASS_GAMECTRL,
|
||||||
|
idac_di_enum_callback_pedals,
|
||||||
|
(void *) cfg,
|
||||||
|
DIEDFL_ATTACHEDONLY);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idac_di_dev == NULL) {
|
||||||
|
dprintf("Pedals: Controller not found\n");
|
||||||
|
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = idac_di_dev_start(idac_di_pedals, idac_di_wnd);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
idac_di_use_pedals = true;
|
||||||
|
} else {
|
||||||
|
idac_di_use_pedals = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg->shifter_name[0] != L'\0') {
|
if (cfg->shifter_name[0] != L'\0') {
|
||||||
hr = IDirectInput8_EnumDevices(
|
hr = IDirectInput8_EnumDevices(
|
||||||
idac_di_api,
|
idac_di_api,
|
||||||
@ -276,8 +312,10 @@ 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", brake_axis->name);
|
if (cfg->pedals_name[0] == L'\0') {
|
||||||
dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name);
|
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: 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: Left button . . . . : %i\n", cfg->left);
|
dprintf("Wheel: Left button . . . . : %i\n", cfg->left);
|
||||||
@ -288,6 +326,15 @@ static HRESULT idac_di_config_apply(const struct idac_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");
|
||||||
|
|
||||||
|
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') {
|
if (cfg->shifter_name[0] != L'\0') {
|
||||||
dprintf("Shifter: --- Begin configuration ---\n");
|
dprintf("Shifter: --- Begin configuration ---\n");
|
||||||
dprintf("Shifter: Device name . . . : Contains \"%S\"\n",
|
dprintf("Shifter: Device name . . . : Contains \"%S\"\n",
|
||||||
@ -364,6 +411,34 @@ static BOOL CALLBACK idac_di_enum_callback(
|
|||||||
return DIENUM_STOP;
|
return DIENUM_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK idac_di_enum_callback_pedals(
|
||||||
|
const DIDEVICEINSTANCEW *dev,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
const struct idac_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(
|
||||||
|
idac_di_api,
|
||||||
|
&dev->guidInstance,
|
||||||
|
&idac_di_pedals,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DIENUM_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL CALLBACK idac_di_enum_callback_shifter(
|
static BOOL CALLBACK idac_di_enum_callback_shifter(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx)
|
void *ctx)
|
||||||
@ -518,6 +593,7 @@ static void idac_di_get_shifter_virt(uint8_t *gear)
|
|||||||
static void idac_di_get_analogs(struct idac_io_analog_state *out)
|
static void idac_di_get_analogs(struct idac_io_analog_state *out)
|
||||||
{
|
{
|
||||||
union idac_di_state state;
|
union idac_di_state state;
|
||||||
|
union idac_di_state pedals_state;
|
||||||
const LONG *brake;
|
const LONG *brake;
|
||||||
const LONG *accel;
|
const LONG *accel;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -530,8 +606,19 @@ static void idac_di_get_analogs(struct idac_io_analog_state *out)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
brake = (LONG *) &state.bytes[idac_di_off_brake];
|
if (idac_di_use_pedals) {
|
||||||
accel = (LONG *) &state.bytes[idac_di_off_accel];
|
hr = idac_di_dev_poll(idac_di_pedals, idac_di_wnd, &pedals_state);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
brake = (LONG *) &pedals_state.bytes[idac_di_off_brake];
|
||||||
|
accel = (LONG *) &pedals_state.bytes[idac_di_off_accel];
|
||||||
|
} else {
|
||||||
|
brake = (LONG *) &state.bytes[idac_di_off_brake];
|
||||||
|
accel = (LONG *) &state.bytes[idac_di_off_accel];
|
||||||
|
}
|
||||||
|
|
||||||
out->wheel = state.st.lX - 32768;
|
out->wheel = state.st.lX - 32768;
|
||||||
|
|
||||||
|
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_left_stick_deadzone;
|
||||||
static uint16_t idac_xi_right_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 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);
|
||||||
@ -143,29 +148,39 @@ static void idac_xi_get_shifter(uint8_t *gear) {
|
|||||||
*gear = idac_shifter_current_gear();
|
*gear = idac_shifter_current_gear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_non_linear_transform(int value, int deadzone_center) {
|
static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) {
|
||||||
const int max_input = 32767;
|
// determine how far the controller is pushed
|
||||||
const double power_factor = 3.0;
|
float magnitude = sqrt(axis*axis);
|
||||||
|
|
||||||
// Apply deadzone only after passing the center threshold
|
// determine the direction the controller is pushed
|
||||||
if (abs(value) < deadzone_center) {
|
float norm_axis = axis / magnitude;
|
||||||
return 0;
|
|
||||||
|
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]
|
// apply non-linear transform to the axis
|
||||||
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
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
|
return norm_axis * norm_magnitude * max_wheel_value;
|
||||||
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) {
|
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;
|
left = xi.Gamepad.sThumbLX;
|
||||||
right = xi.Gamepad.sThumbRX;
|
right = xi.Gamepad.sThumbRX;
|
||||||
|
|
||||||
if (!idac_xi_linear_steering) {
|
// normalize the steering axis
|
||||||
// Apply non-linear transform for both sticks
|
left = calculate_norm_steering(left, idac_xi_left_stick_deadzone, idac_xi_linear_steering);
|
||||||
left = apply_non_linear_transform(left, idac_xi_left_stick_deadzone);
|
right = calculate_norm_steering(right, idac_xi_right_stick_deadzone, idac_xi_linear_steering);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idac_xi_single_stick_steering) {
|
if (idac_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
|
@ -24,6 +24,14 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename)
|
|||||||
_countof(cfg->device_name),
|
_countof(cfg->device_name),
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"dinput",
|
||||||
|
L"pedalsName",
|
||||||
|
L"",
|
||||||
|
cfg->pedals_name,
|
||||||
|
_countof(cfg->pedals_name),
|
||||||
|
filename);
|
||||||
|
|
||||||
GetPrivateProfileStringW(
|
GetPrivateProfileStringW(
|
||||||
L"dinput",
|
L"dinput",
|
||||||
L"shifterName",
|
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(
|
cfg->single_stick_steering = GetPrivateProfileIntW(
|
||||||
L"xinput",
|
L"xinput",
|
||||||
L"singleStickSteering",
|
L"singleStickSteering",
|
||||||
0,
|
1,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
cfg->linear_steering = GetPrivateProfileIntW(
|
cfg->linear_steering = GetPrivateProfileIntW(
|
||||||
|
@ -11,6 +11,7 @@ struct idz_shifter_config {
|
|||||||
struct idz_di_config {
|
struct idz_di_config {
|
||||||
wchar_t device_name[64];
|
wchar_t device_name[64];
|
||||||
wchar_t shifter_name[64];
|
wchar_t shifter_name[64];
|
||||||
|
wchar_t pedals_name[64];
|
||||||
wchar_t brake_axis[16];
|
wchar_t brake_axis[16];
|
||||||
wchar_t accel_axis[16];
|
wchar_t accel_axis[16];
|
||||||
uint8_t start;
|
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(
|
static BOOL CALLBACK idz_di_enum_callback(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
|
static BOOL CALLBACK idz_di_enum_callback_pedals(
|
||||||
|
const DIDEVICEINSTANCEW *dev,
|
||||||
|
void *ctx);
|
||||||
static BOOL CALLBACK idz_di_enum_callback_shifter(
|
static BOOL CALLBACK idz_di_enum_callback_shifter(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
@ -57,6 +60,7 @@ static const struct idz_io_backend idz_di_backend = {
|
|||||||
static HWND idz_di_wnd;
|
static HWND idz_di_wnd;
|
||||||
static IDirectInput8W *idz_di_api;
|
static IDirectInput8W *idz_di_api;
|
||||||
static IDirectInputDevice8W *idz_di_dev;
|
static IDirectInputDevice8W *idz_di_dev;
|
||||||
|
static IDirectInputDevice8W *idz_di_pedals;
|
||||||
static IDirectInputDevice8W *idz_di_shifter;
|
static IDirectInputDevice8W *idz_di_shifter;
|
||||||
static IDirectInputEffect *idz_di_fx;
|
static IDirectInputEffect *idz_di_fx;
|
||||||
static size_t idz_di_off_brake;
|
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_view_chg;
|
||||||
static uint8_t idz_di_start;
|
static uint8_t idz_di_start;
|
||||||
static uint8_t idz_di_gear[6];
|
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_brake_axis;
|
||||||
static bool idz_di_reverse_accel_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);
|
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') {
|
if (cfg->shifter_name[0] != L'\0') {
|
||||||
hr = IDirectInput8_EnumDevices(
|
hr = IDirectInput8_EnumDevices(
|
||||||
idz_di_api,
|
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: --- 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", brake_axis->name);
|
if (cfg->pedals_name[0] == L'\0') {
|
||||||
dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name);
|
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: 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);
|
||||||
@ -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: Reverse Accel Axis : %i\n", cfg->reverse_accel_axis);
|
||||||
dprintf("Wheel: --- End configuration ---\n");
|
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') {
|
if (cfg->shifter_name[0] != L'\0') {
|
||||||
dprintf("Shifter: --- Begin configuration ---\n");
|
dprintf("Shifter: --- Begin configuration ---\n");
|
||||||
dprintf("Shifter: Device name . . . : Contains \"%S\"\n",
|
dprintf("Shifter: Device name . . . : Contains \"%S\"\n",
|
||||||
@ -346,6 +393,34 @@ static BOOL CALLBACK idz_di_enum_callback(
|
|||||||
return DIENUM_STOP;
|
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(
|
static BOOL CALLBACK idz_di_enum_callback_shifter(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx)
|
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)
|
static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out)
|
||||||
{
|
{
|
||||||
union idz_di_state state;
|
union idz_di_state state;
|
||||||
|
union idz_di_state pedals_state;
|
||||||
const LONG *brake;
|
const LONG *brake;
|
||||||
const LONG *accel;
|
const LONG *accel;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -504,8 +580,19 @@ static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
brake = (LONG *) &state.bytes[idz_di_off_brake];
|
if (idz_di_use_pedals) {
|
||||||
accel = (LONG *) &state.bytes[idz_di_off_accel];
|
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;
|
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_left_stick_deadzone;
|
||||||
static uint16_t idz_xi_right_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 idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -143,29 +148,39 @@ 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) {
|
static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) {
|
||||||
const int max_input = 32767;
|
// determine how far the controller is pushed
|
||||||
const double power_factor = 3.0;
|
float magnitude = sqrt(axis*axis);
|
||||||
|
|
||||||
// Apply deadzone only after passing the center threshold
|
// determine the direction the controller is pushed
|
||||||
if (abs(value) < deadzone_center) {
|
float norm_axis = axis / magnitude;
|
||||||
return 0;
|
|
||||||
|
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]
|
// apply non-linear transform to the axis
|
||||||
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
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
|
return norm_axis * norm_magnitude * max_wheel_value;
|
||||||
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)
|
||||||
@ -182,27 +197,9 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out)
|
|||||||
left = xi.Gamepad.sThumbLX;
|
left = xi.Gamepad.sThumbLX;
|
||||||
right = xi.Gamepad.sThumbRX;
|
right = xi.Gamepad.sThumbRX;
|
||||||
|
|
||||||
if (!idz_xi_linear_steering) {
|
// normalize the steering axis
|
||||||
// Apply non-linear transform for both sticks
|
left = calculate_norm_steering(left, idz_xi_left_stick_deadzone, idz_xi_linear_steering);
|
||||||
left = apply_non_linear_transform(left, idz_xi_left_stick_deadzone);
|
right = calculate_norm_steering(right, idz_xi_right_stick_deadzone, idz_xi_linear_steering);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(idz_xi_single_stick_steering) {
|
if(idz_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
|
@ -24,6 +24,14 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename)
|
|||||||
_countof(cfg->device_name),
|
_countof(cfg->device_name),
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"dinput",
|
||||||
|
L"pedalsName",
|
||||||
|
L"",
|
||||||
|
cfg->pedals_name,
|
||||||
|
_countof(cfg->pedals_name),
|
||||||
|
filename);
|
||||||
|
|
||||||
GetPrivateProfileStringW(
|
GetPrivateProfileStringW(
|
||||||
L"dinput",
|
L"dinput",
|
||||||
L"brakeAxis",
|
L"brakeAxis",
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
struct swdc_di_config {
|
struct swdc_di_config {
|
||||||
wchar_t device_name[64];
|
wchar_t device_name[64];
|
||||||
|
wchar_t pedals_name[64];
|
||||||
wchar_t brake_axis[16];
|
wchar_t brake_axis[16];
|
||||||
wchar_t accel_axis[16];
|
wchar_t accel_axis[16];
|
||||||
uint8_t start;
|
uint8_t start;
|
||||||
|
95
swdcio/di.c
95
swdcio/di.c
@ -25,6 +25,9 @@ static const struct swdc_di_axis *swdc_di_get_axis(const wchar_t *name);
|
|||||||
static BOOL CALLBACK swdc_di_enum_callback(
|
static BOOL CALLBACK swdc_di_enum_callback(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
|
static BOOL CALLBACK swdc_di_enum_callback_pedals(
|
||||||
|
const DIDEVICEINSTANCEW *dev,
|
||||||
|
void *ctx);
|
||||||
static BOOL CALLBACK swdc_di_enum_callback_shifter(
|
static BOOL CALLBACK swdc_di_enum_callback_shifter(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
@ -52,6 +55,7 @@ static const struct swdc_io_backend swdc_di_backend = {
|
|||||||
static HWND swdc_di_wnd;
|
static HWND swdc_di_wnd;
|
||||||
static IDirectInput8W *swdc_di_api;
|
static IDirectInput8W *swdc_di_api;
|
||||||
static IDirectInputDevice8W *swdc_di_dev;
|
static IDirectInputDevice8W *swdc_di_dev;
|
||||||
|
static IDirectInputDevice8W *swdc_di_pedals;
|
||||||
static IDirectInputEffect *swdc_di_fx;
|
static IDirectInputEffect *swdc_di_fx;
|
||||||
static size_t swdc_di_off_brake;
|
static size_t swdc_di_off_brake;
|
||||||
static size_t swdc_di_off_accel;
|
static size_t swdc_di_off_accel;
|
||||||
@ -63,6 +67,7 @@ static uint8_t swdc_di_wheel_green;
|
|||||||
static uint8_t swdc_di_wheel_red;
|
static uint8_t swdc_di_wheel_red;
|
||||||
static uint8_t swdc_di_wheel_blue;
|
static uint8_t swdc_di_wheel_blue;
|
||||||
static uint8_t swdc_di_wheel_yellow;
|
static uint8_t swdc_di_wheel_yellow;
|
||||||
|
static bool swdc_di_use_pedals;
|
||||||
static bool swdc_di_reverse_brake_axis;
|
static bool swdc_di_reverse_brake_axis;
|
||||||
static bool swdc_di_reverse_accel_axis;
|
static bool swdc_di_reverse_accel_axis;
|
||||||
|
|
||||||
@ -165,6 +170,37 @@ HRESULT swdc_di_init(
|
|||||||
|
|
||||||
swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx);
|
swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx);
|
||||||
|
|
||||||
|
if (cfg->pedals_name[0] != L'\0') {
|
||||||
|
hr = IDirectInput8_EnumDevices(
|
||||||
|
swdc_di_api,
|
||||||
|
DI8DEVCLASS_GAMECTRL,
|
||||||
|
swdc_di_enum_callback_pedals,
|
||||||
|
(void *) cfg,
|
||||||
|
DIEDFL_ATTACHEDONLY);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swdc_di_dev == NULL) {
|
||||||
|
dprintf("Pedals: Controller not found\n");
|
||||||
|
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = swdc_di_dev_start(swdc_di_pedals, swdc_di_wnd);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
swdc_di_use_pedals = true;
|
||||||
|
} else {
|
||||||
|
swdc_di_use_pedals = false;
|
||||||
|
}
|
||||||
|
|
||||||
dprintf("DirectInput: Controller initialized\n");
|
dprintf("DirectInput: Controller initialized\n");
|
||||||
|
|
||||||
*backend = &swdc_di_backend;
|
*backend = &swdc_di_backend;
|
||||||
@ -246,8 +282,10 @@ 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", brake_axis->name);
|
if (cfg->pedals_name[0] == L'\0') {
|
||||||
dprintf("Wheel: Accel axis . . . . . . : %S\n", accel_axis->name);
|
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: 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: Paddle Left button . . : %i\n", cfg->paddle_left);
|
dprintf("Wheel: Paddle Left button . . : %i\n", cfg->paddle_left);
|
||||||
@ -260,6 +298,15 @@ 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");
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
swdc_di_off_brake = brake_axis->off;
|
swdc_di_off_brake = brake_axis->off;
|
||||||
swdc_di_off_accel = accel_axis->off;
|
swdc_di_off_accel = accel_axis->off;
|
||||||
swdc_di_start = cfg->start;
|
swdc_di_start = cfg->start;
|
||||||
@ -320,6 +367,34 @@ static BOOL CALLBACK swdc_di_enum_callback(
|
|||||||
return DIENUM_STOP;
|
return DIENUM_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK swdc_di_enum_callback_pedals(
|
||||||
|
const DIDEVICEINSTANCEW *dev,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
const struct swdc_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(
|
||||||
|
swdc_di_api,
|
||||||
|
&dev->guidInstance,
|
||||||
|
&swdc_di_pedals,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DIENUM_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
static void swdc_di_get_buttons(uint16_t *gamebtn_out)
|
static void swdc_di_get_buttons(uint16_t *gamebtn_out)
|
||||||
{
|
{
|
||||||
union swdc_di_state state;
|
union swdc_di_state state;
|
||||||
@ -389,6 +464,7 @@ static uint8_t swdc_di_decode_pov(DWORD pov)
|
|||||||
static void swdc_di_get_analogs(struct swdc_io_analog_state *out)
|
static void swdc_di_get_analogs(struct swdc_io_analog_state *out)
|
||||||
{
|
{
|
||||||
union swdc_di_state state;
|
union swdc_di_state state;
|
||||||
|
union swdc_di_state pedals_state;
|
||||||
const LONG *brake;
|
const LONG *brake;
|
||||||
const LONG *accel;
|
const LONG *accel;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -401,8 +477,19 @@ static void swdc_di_get_analogs(struct swdc_io_analog_state *out)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
brake = (LONG *) &state.bytes[swdc_di_off_brake];
|
if (swdc_di_use_pedals) {
|
||||||
accel = (LONG *) &state.bytes[swdc_di_off_accel];
|
hr = swdc_di_dev_poll(swdc_di_pedals, swdc_di_wnd, &pedals_state);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
brake = (LONG *) &pedals_state.bytes[swdc_di_off_brake];
|
||||||
|
accel = (LONG *) &pedals_state.bytes[swdc_di_off_accel];
|
||||||
|
} else {
|
||||||
|
brake = (LONG *) &state.bytes[swdc_di_off_brake];
|
||||||
|
accel = (LONG *) &state.bytes[swdc_di_off_accel];
|
||||||
|
}
|
||||||
|
|
||||||
out->wheel = state.st.lX - 32768;
|
out->wheel = state.st.lX - 32768;
|
||||||
|
|
||||||
|
79
swdcio/xi.c
79
swdcio/xi.c
@ -28,6 +28,11 @@ static bool swdc_xi_linear_steering;
|
|||||||
static uint16_t swdc_xi_left_stick_deadzone;
|
static uint16_t swdc_xi_left_stick_deadzone;
|
||||||
static uint16_t swdc_xi_right_stick_deadzone;
|
static uint16_t swdc_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 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)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -143,29 +148,39 @@ 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) {
|
static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) {
|
||||||
const int max_input = 32767;
|
// determine how far the controller is pushed
|
||||||
const double power_factor = 3.0;
|
float magnitude = sqrt(axis*axis);
|
||||||
|
|
||||||
// Apply deadzone only after passing the center threshold
|
// determine the direction the controller is pushed
|
||||||
if (abs(value) < deadzone_center) {
|
float norm_axis = axis / magnitude;
|
||||||
return 0;
|
|
||||||
|
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]
|
// apply non-linear transform to the axis
|
||||||
double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center);
|
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
|
return norm_axis * norm_magnitude * max_wheel_value;
|
||||||
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)
|
||||||
@ -182,28 +197,10 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out)
|
|||||||
left = xi.Gamepad.sThumbLX;
|
left = xi.Gamepad.sThumbLX;
|
||||||
right = xi.Gamepad.sThumbRX;
|
right = xi.Gamepad.sThumbRX;
|
||||||
|
|
||||||
if (!swdc_xi_linear_steering) {
|
// normalize the steering axis
|
||||||
// Apply non-linear transform for both sticks
|
left = calculate_norm_steering(left, swdc_xi_left_stick_deadzone, swdc_xi_linear_steering);
|
||||||
left = apply_non_linear_transform(left, swdc_xi_left_stick_deadzone);
|
right = calculate_norm_steering(right, swdc_xi_right_stick_deadzone, swdc_xi_linear_steering);
|
||||||
right = apply_non_linear_transform(right, swdc_xi_right_stick_deadzone);
|
|
||||||
} else {
|
|
||||||
if (left < -swdc_xi_left_stick_deadzone) {
|
|
||||||
left += swdc_xi_left_stick_deadzone;
|
|
||||||
} else if (left > swdc_xi_left_stick_deadzone) {
|
|
||||||
left -= swdc_xi_left_stick_deadzone;
|
|
||||||
} else {
|
|
||||||
left = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right < -swdc_xi_right_stick_deadzone) {
|
|
||||||
right += swdc_xi_right_stick_deadzone;
|
|
||||||
} else if (right > swdc_xi_right_stick_deadzone) {
|
|
||||||
right -= swdc_xi_right_stick_deadzone;
|
|
||||||
} else {
|
|
||||||
right = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swdc_xi_single_stick_steering) {
|
if (swdc_xi_single_stick_steering) {
|
||||||
out->wheel = left;
|
out->wheel = left;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user