forked from Hay1tsme/segatools
Compare commits
4 Commits
2023-12-03
...
2023-12-17
Author | SHA1 | Date | |
---|---|---|---|
ed042176d7
|
|||
ad154a83e5
|
|||
1cbc33d97d
|
|||
72db08ac93
|
@ -18,6 +18,7 @@ struct aime_dll {
|
|||||||
|
|
||||||
struct aime_dll_config {
|
struct aime_dll_config {
|
||||||
wchar_t path[MAX_PATH];
|
wchar_t path[MAX_PATH];
|
||||||
|
bool path64;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct aime_dll aime_dll;
|
extern struct aime_dll aime_dll;
|
||||||
|
@ -9,18 +9,59 @@
|
|||||||
#include "board/config.h"
|
#include "board/config.h"
|
||||||
#include "board/sg-reader.h"
|
#include "board/sg-reader.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
// Check windows
|
||||||
|
#if _WIN32 || _WIN64
|
||||||
|
#if _WIN64
|
||||||
|
#define ENV64BIT
|
||||||
|
#else
|
||||||
|
#define ENV32BIT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check GCC
|
||||||
|
#if __GNUC__
|
||||||
|
#if __x86_64__ || __ppc64__
|
||||||
|
#define ENV64BIT
|
||||||
|
#else
|
||||||
|
#define ENV32BIT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename)
|
static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename)
|
||||||
{
|
{
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(filename != NULL);
|
assert(filename != NULL);
|
||||||
|
|
||||||
GetPrivateProfileStringW(
|
// Workaround for x64/x86 external IO dlls
|
||||||
|
// path32 for 32bit, path64 for 64bit
|
||||||
|
// for else.. is that possible? idk
|
||||||
|
|
||||||
|
if (cfg->path64) {
|
||||||
|
#if defined(ENV32BIT)
|
||||||
|
// Always empty, due to amdaemon being 64 bit in 32 bit mode
|
||||||
|
memset(cfg->path, 0, sizeof(cfg->path));
|
||||||
|
#elif defined(ENV64BIT)
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"aimeio",
|
||||||
|
L"path",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
|
#else
|
||||||
|
#error "Unknown environment"
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
GetPrivateProfileStringW(
|
||||||
L"aimeio",
|
L"aimeio",
|
||||||
L"path",
|
L"path",
|
||||||
L"",
|
L"",
|
||||||
cfg->path,
|
cfg->path,
|
||||||
_countof(cfg->path),
|
_countof(cfg->path),
|
||||||
filename);
|
filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
|
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
|
||||||
|
@ -38,7 +38,7 @@ void chuni_io_jvs_read_coin_counter(uint16_t *out)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetAsyncKeyState(chuni_io_cfg.vk_coin)) {
|
if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) {
|
||||||
if (!chuni_io_coin) {
|
if (!chuni_io_coin) {
|
||||||
chuni_io_coin = true;
|
chuni_io_coin = true;
|
||||||
chuni_io_coins++;
|
chuni_io_coins++;
|
||||||
@ -62,15 +62,6 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
|
|||||||
*opbtn |= CHUNI_IO_OPBTN_SERVICE;
|
*opbtn |= CHUNI_IO_OPBTN_SERVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) {
|
|
||||||
if (!chuni_io_coin) {
|
|
||||||
chuni_io_coin = true;
|
|
||||||
*opbtn |= CHUNI_IO_OPBTN_COIN;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
chuni_io_coin = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chuni_io_cfg.vk_ir_emu) {
|
if (chuni_io_cfg.vk_ir_emu) {
|
||||||
// Use emulated AIR
|
// Use emulated AIR
|
||||||
if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) {
|
if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) {
|
||||||
|
@ -57,7 +57,7 @@ void chuni_io_config_load(
|
|||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetPrivateProfileStringW(L"slider", L"ledport", L"COM2", port_input, 6, filename);
|
GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename);
|
||||||
wcsncpy(cfg->led_com, L"\\\\.\\", 4);
|
wcsncpy(cfg->led_com, L"\\\\.\\", 4);
|
||||||
wcsncat_s(cfg->led_com, 11, port_input, 6);
|
wcsncat_s(cfg->led_com, 11, port_input, 6);
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,9 @@ void chusan_hook_config_load(
|
|||||||
|
|
||||||
memset(cfg, 0, sizeof(*cfg));
|
memset(cfg, 0, sizeof(*cfg));
|
||||||
|
|
||||||
|
// Force load the 64bit Aime DLL instead of the 32bit one
|
||||||
|
cfg->aime.dll.path64 = true;
|
||||||
|
|
||||||
platform_config_load(&cfg->platform, filename);
|
platform_config_load(&cfg->platform, filename);
|
||||||
aime_config_load(&cfg->aime, filename);
|
aime_config_load(&cfg->aime, filename);
|
||||||
dvd_config_load(&cfg->dvd, filename);
|
dvd_config_load(&cfg->dvd, filename);
|
||||||
|
@ -100,11 +100,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0];
|
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0];
|
||||||
|
bool *is_sp = dipsw + 2;
|
||||||
if (dipsw[1] != dipsw[2]) {
|
|
||||||
dprintf("DipSw: DipSw2 and 3 must be set to the same value!\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
@ -117,13 +113,21 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
dprintf("DipSw: Aime Reader: %s\n", dipsw[2] ? "CVT" : "SP");
|
dprintf("DipSw: Cab Type: %s\n", is_sp ? "SP" : "CVT");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int first_port = dipsw[1] ? 2 : 20;
|
unsigned int first_port = is_sp ? 20 : 2;
|
||||||
|
|
||||||
|
if (is_sp) {
|
||||||
|
hr = vfd_hook_init(2);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1);
|
hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1);
|
||||||
|
|
||||||
@ -131,7 +135,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, dipsw[2] ? 2 : 3, chusan_hook_mod);
|
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_sp ? 3: 2, chusan_hook_mod);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -73,6 +73,7 @@ static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state)
|
|||||||
beams = 0;
|
beams = 0;
|
||||||
|
|
||||||
chuni_dll.jvs_poll(&opbtn, &beams);
|
chuni_dll.jvs_poll(&opbtn, &beams);
|
||||||
|
chuni_dll.jvs_read_coin_counter(&coins);
|
||||||
|
|
||||||
if (chuni_dll.api_version >= 0x0101) {
|
if (chuni_dll.api_version >= 0x0101) {
|
||||||
// Use correct mapping
|
// Use correct mapping
|
||||||
@ -90,9 +91,7 @@ static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state)
|
|||||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opbtn & CHUNI_IO_OPBTN_COIN) {
|
// Update the coin counter with the value from jvs_read_coin_counter
|
||||||
coins++;
|
|
||||||
}
|
|
||||||
state->chutes[0] = coins << 8;
|
state->chutes[0] = coins << 8;
|
||||||
|
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
|
4
dist/chuni/segatools.ini
vendored
4
dist/chuni/segatools.ini
vendored
@ -82,3 +82,7 @@ coin=0x33
|
|||||||
;cell31=0x53
|
;cell31=0x53
|
||||||
;cell30=0x53
|
;cell30=0x53
|
||||||
; ... etc ...
|
; ... etc ...
|
||||||
|
|
||||||
|
; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol.
|
||||||
|
; eg. COM5
|
||||||
|
;ledport=
|
||||||
|
14
dist/chusan/segatools.ini
vendored
14
dist/chusan/segatools.ini
vendored
@ -16,9 +16,9 @@ aimePath=DEVICE\aime.txt
|
|||||||
;highbaud=1
|
;highbaud=1
|
||||||
|
|
||||||
[aimeio]
|
[aimeio]
|
||||||
; x64 aimeio dll path.
|
; Uncomment this if you have custom (x64) aime implementation.
|
||||||
; Uncomment this if you have custom aime implementation.
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
;path64=
|
;path=
|
||||||
|
|
||||||
[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.
|
||||||
@ -35,7 +35,7 @@ enable=1
|
|||||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||||
; that subnet must start with 192.168.
|
; that subnet must start with 192.168.
|
||||||
subnet=192.168.100.0
|
subnet=192.168.139.0
|
||||||
|
|
||||||
[gpio]
|
[gpio]
|
||||||
; ALLS DIP switches.
|
; ALLS DIP switches.
|
||||||
@ -49,10 +49,10 @@ freeplay=0
|
|||||||
; LAN Install: If multiple machines are present on the same LAN then set
|
; LAN Install: If multiple machines are present on the same LAN then set
|
||||||
; this to 1 on exactly one machine and set this to 0 on all others.
|
; this to 1 on exactly one machine and set this to 0 on all others.
|
||||||
dipsw1=1
|
dipsw1=1
|
||||||
; Monitor type: 0 = 120FPS (SP), 1 = 60FPS (CVT)
|
; Monitor type: 0 = 120FPS, 1 = 60FPS
|
||||||
dipsw2=1
|
dipsw2=1
|
||||||
; Aime reader hardware type: 0 = SP, 1 = CVT. Both dipsw2 and dipsw3 must be
|
; Cab type: 0 = SP, 1 = CVT. SP will enable VFD and eMoney. This setting will switch
|
||||||
; the same value.
|
; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well.
|
||||||
dipsw3=1
|
dipsw3=1
|
||||||
|
|
||||||
[gfx]
|
[gfx]
|
||||||
|
7
dist/idac/segatools.ini
vendored
7
dist/idac/segatools.ini
vendored
@ -29,7 +29,7 @@ enable=1
|
|||||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||||
; that subnet must start with 192.168. Set it to your LAN's subnet if you
|
; that subnet must start with 192.168. Set it to your LAN's subnet if you
|
||||||
; want to play head-to-head using netenv=1.
|
; want to play head-to-head using netenv=1.
|
||||||
subnet=192.168.100.0
|
subnet=192.168.158.0
|
||||||
|
|
||||||
; Override the keychip's region code. Most games seem to pay attention to the
|
; Override the keychip's region code. Most games seem to pay attention to the
|
||||||
; DS EEPROM region code and not the keychip region code, and this seems to be
|
; DS EEPROM region code and not the keychip region code, and this seems to be
|
||||||
@ -174,3 +174,8 @@ gear6=18
|
|||||||
; (Needed when using DirectInput for the Dualshock 4 for example)
|
; (Needed when using DirectInput for the Dualshock 4 for example)
|
||||||
reverseAccelAxis=0
|
reverseAccelAxis=0
|
||||||
reverseBrakeAxis=0
|
reverseBrakeAxis=0
|
||||||
|
|
||||||
|
; Force feedback settings.
|
||||||
|
; Strength of the force feedback spring effect in percent. Possible values
|
||||||
|
; are 0-100.
|
||||||
|
centerSpringStrength=30
|
||||||
|
5
dist/idz/segatools.ini
vendored
5
dist/idz/segatools.ini
vendored
@ -173,3 +173,8 @@ gear6=18
|
|||||||
; (Needed when using DirectInput for the Dualshock 4 for example)
|
; (Needed when using DirectInput for the Dualshock 4 for example)
|
||||||
reverseAccelAxis=0
|
reverseAccelAxis=0
|
||||||
reverseBrakeAxis=0
|
reverseBrakeAxis=0
|
||||||
|
|
||||||
|
; Force feedback settings.
|
||||||
|
; Strength of the force feedback spring effect in percent. Possible values
|
||||||
|
; are 0-100.
|
||||||
|
centerSpringStrength=30
|
||||||
|
5
dist/swdc/segatools.ini
vendored
5
dist/swdc/segatools.ini
vendored
@ -133,3 +133,8 @@ wheelGreen=10
|
|||||||
; (Needed when using DirectInput for the Dualshock 4 for example)
|
; (Needed when using DirectInput for the Dualshock 4 for example)
|
||||||
reverseAccelAxis=0
|
reverseAccelAxis=0
|
||||||
reverseBrakeAxis=0
|
reverseBrakeAxis=0
|
||||||
|
|
||||||
|
; Force feedback settings.
|
||||||
|
; Strength of the force feedback spring effect in percent. Possible values
|
||||||
|
; are 0-100.
|
||||||
|
centerSpringStrength=30
|
||||||
|
@ -79,6 +79,14 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename)
|
|||||||
cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename);
|
cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
cfg->center_spring_strength = GetPrivateProfileIntW(
|
||||||
|
L"dinput",
|
||||||
|
L"centerSpringStrength",
|
||||||
|
30,
|
||||||
|
filename);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename)
|
void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename)
|
||||||
|
@ -23,6 +23,9 @@ struct idac_di_config {
|
|||||||
uint8_t gear[6];
|
uint8_t gear[6];
|
||||||
bool reverse_brake_axis;
|
bool reverse_brake_axis;
|
||||||
bool reverse_accel_axis;
|
bool reverse_accel_axis;
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
uint16_t center_spring_strength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct idac_xi_config {
|
struct idac_xi_config {
|
||||||
|
@ -44,7 +44,8 @@ HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
void idac_di_dev_start_fx(
|
||||||
|
IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength)
|
||||||
{
|
{
|
||||||
/* Set up force-feedback on devices that support it. This is just a stub
|
/* Set up force-feedback on devices that support it. This is just a stub
|
||||||
for the time being, since we don't yet know how the serial port force
|
for the time being, since we don't yet know how the serial port force
|
||||||
@ -67,7 +68,7 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
DWORD axis;
|
DWORD axis;
|
||||||
LONG direction;
|
LONG direction;
|
||||||
DIEFFECT fx;
|
DIEFFECT fx;
|
||||||
DICONSTANTFORCE cf;
|
DICONDITION cond;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
assert(dev != NULL);
|
assert(dev != NULL);
|
||||||
@ -77,11 +78,17 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
||||||
|
|
||||||
|
// Auto-centering effect
|
||||||
axis = DIJOFS_X;
|
axis = DIJOFS_X;
|
||||||
direction = 0;
|
direction = 0;
|
||||||
|
|
||||||
memset(&cf, 0, sizeof(cf));
|
memset(&cond, 0, sizeof(cond));
|
||||||
cf.lMagnitude = 0;
|
cond.lOffset = 0;
|
||||||
|
cond.lPositiveCoefficient = strength;
|
||||||
|
cond.lNegativeCoefficient = strength;
|
||||||
|
cond.dwPositiveSaturation = strength; // For FG920?
|
||||||
|
cond.dwNegativeSaturation = strength; // For FG920?
|
||||||
|
cond.lDeadBand = 0;
|
||||||
|
|
||||||
memset(&fx, 0, sizeof(fx));
|
memset(&fx, 0, sizeof(fx));
|
||||||
fx.dwSize = sizeof(fx);
|
fx.dwSize = sizeof(fx);
|
||||||
@ -93,20 +100,19 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
fx.cAxes = 1;
|
fx.cAxes = 1;
|
||||||
fx.rgdwAxes = &axis;
|
fx.rgdwAxes = &axis;
|
||||||
fx.rglDirection = &direction;
|
fx.rglDirection = &direction;
|
||||||
fx.cbTypeSpecificParams = sizeof(cf);
|
fx.cbTypeSpecificParams = sizeof(cond);
|
||||||
fx.lpvTypeSpecificParams = &cf;
|
fx.lpvTypeSpecificParams = &cond;
|
||||||
|
|
||||||
hr = IDirectInputDevice8_CreateEffect(
|
hr = IDirectInputDevice8_CreateEffect(
|
||||||
dev,
|
dev,
|
||||||
&GUID_ConstantForce,
|
&GUID_Spring,
|
||||||
&fx,
|
&fx,
|
||||||
&obj,
|
&obj,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +120,15 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
IDirectInputEffect_Release(obj);
|
IDirectInputEffect_Release(obj);
|
||||||
dprintf("DirectInput: DirectInput force feedback start failed: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback start failed: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = obj;
|
*out = obj;
|
||||||
|
|
||||||
dprintf("DirectInput: Force feedback initialized and set to zero\n");
|
dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n",
|
||||||
|
strength / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT idac_di_dev_poll(
|
HRESULT idac_di_dev_poll(
|
||||||
|
@ -11,7 +11,7 @@ union idac_di_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
||||||
void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out);
|
void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength);
|
||||||
HRESULT idac_di_dev_poll(
|
HRESULT idac_di_dev_poll(
|
||||||
IDirectInputDevice8W *dev,
|
IDirectInputDevice8W *dev,
|
||||||
HWND wnd,
|
HWND wnd,
|
||||||
|
15
idacio/di.c
15
idacio/di.c
@ -75,6 +75,7 @@ static uint8_t idac_di_gear[6];
|
|||||||
static bool idac_di_use_pedals;
|
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;
|
||||||
|
static uint16_t idac_di_center_spring_strength;
|
||||||
|
|
||||||
HRESULT idac_di_init(
|
HRESULT idac_di_init(
|
||||||
const struct idac_di_config *cfg,
|
const struct idac_di_config *cfg,
|
||||||
@ -173,7 +174,9 @@ HRESULT idac_di_init(
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
idac_di_dev_start_fx(idac_di_dev, &idac_di_fx);
|
// Convert the strength from 0-100 to 0-10000 for DirectInput
|
||||||
|
idac_di_dev_start_fx(idac_di_dev, &idac_di_fx,
|
||||||
|
idac_di_center_spring_strength * 100);
|
||||||
|
|
||||||
if (cfg->pedals_name[0] != L'\0') {
|
if (cfg->pedals_name[0] != L'\0') {
|
||||||
hr = IDirectInput8_EnumDevices(
|
hr = IDirectInput8_EnumDevices(
|
||||||
@ -364,6 +367,16 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
|||||||
idac_di_gear[i] = cfg->gear[i];
|
idac_di_gear[i] = cfg->gear[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) {
|
||||||
|
dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength);
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
idac_di_center_spring_strength = cfg->center_spring_strength;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,14 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename)
|
|||||||
swprintf_s(key, _countof(key), L"gear%i", i + 1);
|
swprintf_s(key, _countof(key), L"gear%i", i + 1);
|
||||||
cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename);
|
cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
cfg->center_spring_strength = GetPrivateProfileIntW(
|
||||||
|
L"dinput",
|
||||||
|
L"centerSpringStrength",
|
||||||
|
30,
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename)
|
void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename)
|
||||||
|
@ -21,6 +21,9 @@ struct idz_di_config {
|
|||||||
uint8_t gear[6];
|
uint8_t gear[6];
|
||||||
bool reverse_brake_axis;
|
bool reverse_brake_axis;
|
||||||
bool reverse_accel_axis;
|
bool reverse_accel_axis;
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
uint16_t center_spring_strength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct idz_xi_config {
|
struct idz_xi_config {
|
||||||
|
@ -44,7 +44,8 @@ HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
void idz_di_dev_start_fx(
|
||||||
|
IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength)
|
||||||
{
|
{
|
||||||
/* Set up force-feedback on devices that support it. This is just a stub
|
/* Set up force-feedback on devices that support it. This is just a stub
|
||||||
for the time being, since we don't yet know how the serial port force
|
for the time being, since we don't yet know how the serial port force
|
||||||
@ -67,7 +68,7 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
DWORD axis;
|
DWORD axis;
|
||||||
LONG direction;
|
LONG direction;
|
||||||
DIEFFECT fx;
|
DIEFFECT fx;
|
||||||
DICONSTANTFORCE cf;
|
DICONDITION cond;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
assert(dev != NULL);
|
assert(dev != NULL);
|
||||||
@ -77,11 +78,17 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
||||||
|
|
||||||
|
// Auto-centering effect
|
||||||
axis = DIJOFS_X;
|
axis = DIJOFS_X;
|
||||||
direction = 0;
|
direction = 0;
|
||||||
|
|
||||||
memset(&cf, 0, sizeof(cf));
|
memset(&cond, 0, sizeof(cond));
|
||||||
cf.lMagnitude = 0;
|
cond.lOffset = 0;
|
||||||
|
cond.lPositiveCoefficient = strength;
|
||||||
|
cond.lNegativeCoefficient = strength;
|
||||||
|
cond.dwPositiveSaturation = strength; // For FG920?
|
||||||
|
cond.dwNegativeSaturation = strength; // For FG920?
|
||||||
|
cond.lDeadBand = 0;
|
||||||
|
|
||||||
memset(&fx, 0, sizeof(fx));
|
memset(&fx, 0, sizeof(fx));
|
||||||
fx.dwSize = sizeof(fx);
|
fx.dwSize = sizeof(fx);
|
||||||
@ -93,20 +100,19 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
fx.cAxes = 1;
|
fx.cAxes = 1;
|
||||||
fx.rgdwAxes = &axis;
|
fx.rgdwAxes = &axis;
|
||||||
fx.rglDirection = &direction;
|
fx.rglDirection = &direction;
|
||||||
fx.cbTypeSpecificParams = sizeof(cf);
|
fx.cbTypeSpecificParams = sizeof(cond);
|
||||||
fx.lpvTypeSpecificParams = &cf;
|
fx.lpvTypeSpecificParams = &cond;
|
||||||
|
|
||||||
hr = IDirectInputDevice8_CreateEffect(
|
hr = IDirectInputDevice8_CreateEffect(
|
||||||
dev,
|
dev,
|
||||||
&GUID_ConstantForce,
|
&GUID_Spring,
|
||||||
&fx,
|
&fx,
|
||||||
&obj,
|
&obj,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +120,15 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
IDirectInputEffect_Release(obj);
|
IDirectInputEffect_Release(obj);
|
||||||
dprintf("DirectInput: DirectInput force feedback start failed: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback start failed: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = obj;
|
*out = obj;
|
||||||
|
|
||||||
dprintf("DirectInput: Force feedback initialized and set to zero\n");
|
dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n",
|
||||||
|
strength / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT idz_di_dev_poll(
|
HRESULT idz_di_dev_poll(
|
||||||
|
@ -11,7 +11,7 @@ union idz_di_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
||||||
void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out);
|
void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength);
|
||||||
HRESULT idz_di_dev_poll(
|
HRESULT idz_di_dev_poll(
|
||||||
IDirectInputDevice8W *dev,
|
IDirectInputDevice8W *dev,
|
||||||
HWND wnd,
|
HWND wnd,
|
||||||
|
15
idzio/di.c
15
idzio/di.c
@ -73,6 +73,7 @@ static uint8_t idz_di_gear[6];
|
|||||||
static bool idz_di_use_pedals;
|
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;
|
||||||
|
static uint16_t idz_di_center_spring_strength;
|
||||||
|
|
||||||
HRESULT idz_di_init(
|
HRESULT idz_di_init(
|
||||||
const struct idz_di_config *cfg,
|
const struct idz_di_config *cfg,
|
||||||
@ -171,7 +172,9 @@ HRESULT idz_di_init(
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
idz_di_dev_start_fx(idz_di_dev, &idz_di_fx);
|
// Convert the strength from 0-100 to 0-10000 for DirectInput
|
||||||
|
idz_di_dev_start_fx(idz_di_dev, &idz_di_fx,
|
||||||
|
idz_di_center_spring_strength * 100);
|
||||||
|
|
||||||
if (cfg->pedals_name[0] != L'\0') {
|
if (cfg->pedals_name[0] != L'\0') {
|
||||||
hr = IDirectInput8_EnumDevices(
|
hr = IDirectInput8_EnumDevices(
|
||||||
@ -346,6 +349,16 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg)
|
|||||||
idz_di_gear[i] = cfg->gear[i];
|
idz_di_gear[i] = cfg->gear[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) {
|
||||||
|
dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength);
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
idz_di_center_spring_strength = cfg->center_spring_strength;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,14 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename)
|
|||||||
L"reverseAccelAxis",
|
L"reverseAccelAxis",
|
||||||
0,
|
0,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
cfg->center_spring_strength = GetPrivateProfileIntW(
|
||||||
|
L"dinput",
|
||||||
|
L"centerSpringStrength",
|
||||||
|
30,
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename)
|
void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename)
|
||||||
|
@ -19,6 +19,9 @@ struct swdc_di_config {
|
|||||||
uint8_t wheel_yellow;
|
uint8_t wheel_yellow;
|
||||||
bool reverse_brake_axis;
|
bool reverse_brake_axis;
|
||||||
bool reverse_accel_axis;
|
bool reverse_accel_axis;
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
uint16_t center_spring_strength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct swdc_xi_config {
|
struct swdc_xi_config {
|
||||||
|
@ -44,7 +44,8 @@ HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
void swdc_di_dev_start_fx(
|
||||||
|
IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength)
|
||||||
{
|
{
|
||||||
/* Set up force-feedback on devices that support it. This is just a stub
|
/* Set up force-feedback on devices that support it. This is just a stub
|
||||||
for the time being, since we don't yet know how the serial port force
|
for the time being, since we don't yet know how the serial port force
|
||||||
@ -67,7 +68,7 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
DWORD axis;
|
DWORD axis;
|
||||||
LONG direction;
|
LONG direction;
|
||||||
DIEFFECT fx;
|
DIEFFECT fx;
|
||||||
DICONSTANTFORCE cf;
|
DICONDITION cond;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
assert(dev != NULL);
|
assert(dev != NULL);
|
||||||
@ -77,11 +78,17 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
dprintf("DirectInput: Starting force feedback (may take a sec)\n");
|
||||||
|
|
||||||
|
// Auto-centering effect
|
||||||
axis = DIJOFS_X;
|
axis = DIJOFS_X;
|
||||||
direction = 0;
|
direction = 0;
|
||||||
|
|
||||||
memset(&cf, 0, sizeof(cf));
|
memset(&cond, 0, sizeof(cond));
|
||||||
cf.lMagnitude = 0;
|
cond.lOffset = 0;
|
||||||
|
cond.lPositiveCoefficient = strength;
|
||||||
|
cond.lNegativeCoefficient = strength;
|
||||||
|
cond.dwPositiveSaturation = strength; // For FG920?
|
||||||
|
cond.dwNegativeSaturation = strength; // For FG920?
|
||||||
|
cond.lDeadBand = 0;
|
||||||
|
|
||||||
memset(&fx, 0, sizeof(fx));
|
memset(&fx, 0, sizeof(fx));
|
||||||
fx.dwSize = sizeof(fx);
|
fx.dwSize = sizeof(fx);
|
||||||
@ -93,20 +100,19 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
fx.cAxes = 1;
|
fx.cAxes = 1;
|
||||||
fx.rgdwAxes = &axis;
|
fx.rgdwAxes = &axis;
|
||||||
fx.rglDirection = &direction;
|
fx.rglDirection = &direction;
|
||||||
fx.cbTypeSpecificParams = sizeof(cf);
|
fx.cbTypeSpecificParams = sizeof(cond);
|
||||||
fx.lpvTypeSpecificParams = &cf;
|
fx.lpvTypeSpecificParams = &cond;
|
||||||
|
|
||||||
hr = IDirectInputDevice8_CreateEffect(
|
hr = IDirectInputDevice8_CreateEffect(
|
||||||
dev,
|
dev,
|
||||||
&GUID_ConstantForce,
|
&GUID_Spring,
|
||||||
&fx,
|
&fx,
|
||||||
&obj,
|
&obj,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +120,15 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out)
|
|||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
IDirectInputEffect_Release(obj);
|
IDirectInputEffect_Release(obj);
|
||||||
dprintf("DirectInput: DirectInput force feedback start failed: %08x\n",
|
dprintf("DirectInput: Centering spring force feedback start failed: %08x\n",
|
||||||
(int) hr);
|
(int) hr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = obj;
|
*out = obj;
|
||||||
|
|
||||||
dprintf("DirectInput: Force feedback initialized and set to zero\n");
|
dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n",
|
||||||
|
strength / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT swdc_di_dev_poll(
|
HRESULT swdc_di_dev_poll(
|
||||||
|
@ -11,7 +11,7 @@ union swdc_di_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd);
|
||||||
void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out);
|
void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength);
|
||||||
HRESULT swdc_di_dev_poll(
|
HRESULT swdc_di_dev_poll(
|
||||||
IDirectInputDevice8W *dev,
|
IDirectInputDevice8W *dev,
|
||||||
HWND wnd,
|
HWND wnd,
|
||||||
|
15
swdcio/di.c
15
swdcio/di.c
@ -70,6 +70,7 @@ static uint8_t swdc_di_wheel_yellow;
|
|||||||
static bool swdc_di_use_pedals;
|
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;
|
||||||
|
static uint16_t swdc_di_center_spring_strength;
|
||||||
|
|
||||||
HRESULT swdc_di_init(
|
HRESULT swdc_di_init(
|
||||||
const struct swdc_di_config *cfg,
|
const struct swdc_di_config *cfg,
|
||||||
@ -168,7 +169,9 @@ HRESULT swdc_di_init(
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx);
|
// Convert the strength from 0-100 to 0-10000 for DirectInput
|
||||||
|
swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx,
|
||||||
|
swdc_di_center_spring_strength * 100);
|
||||||
|
|
||||||
if (cfg->pedals_name[0] != L'\0') {
|
if (cfg->pedals_name[0] != L'\0') {
|
||||||
hr = IDirectInput8_EnumDevices(
|
hr = IDirectInput8_EnumDevices(
|
||||||
@ -320,6 +323,16 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg)
|
|||||||
swdc_di_reverse_brake_axis = cfg->reverse_brake_axis;
|
swdc_di_reverse_brake_axis = cfg->reverse_brake_axis;
|
||||||
swdc_di_reverse_accel_axis = cfg->reverse_accel_axis;
|
swdc_di_reverse_accel_axis = cfg->reverse_accel_axis;
|
||||||
|
|
||||||
|
// FFB configuration
|
||||||
|
|
||||||
|
if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) {
|
||||||
|
dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength);
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
swdc_di_center_spring_strength = cfg->center_spring_strength;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user