idac: first segatools support

This commit is contained in:
2023-06-29 11:24:34 +02:00
parent ee6675dd73
commit da97d23b51
25 changed files with 351 additions and 441 deletions

View File

@ -5,7 +5,8 @@
#include "idacio/idacio.h"
struct idac_io_backend {
void (*jvs_read_buttons)(uint8_t *gamebtn);
void (*jvs_read_shifter)(uint8_t *gear);
void (*jvs_read_analogs)(struct idac_io_analog_state *state);
void (*get_opbtns)(uint8_t *opbtn);
void (*get_gamebtns)(uint8_t *gamebtn);
void (*get_shifter)(uint8_t *gear);
void (*get_analogs)(struct idac_io_analog_state *state);
};

View File

@ -77,7 +77,7 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename)
assert(filename != NULL);
cfg->single_stick_steering = GetPrivateProfileIntW(
L"io3",
L"io4",
L"singleStickSteering",
0,
filename);
@ -88,13 +88,13 @@ void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename)
assert(cfg != NULL);
assert(filename != NULL);
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename);
cfg->restrict_ = GetPrivateProfileIntW(L"io3", L"restrict", 97, filename);
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 97, filename);
GetPrivateProfileStringW(
L"io3",
L"io4",
L"mode",
L"xinput",
cfg->mode,
@ -114,7 +114,7 @@ void idac_shifter_config_load(
assert(filename != NULL);
cfg->auto_neutral = GetPrivateProfileIntW(
L"io3",
L"io4",
L"autoNeutral",
0,
filename);

View File

@ -29,12 +29,12 @@ static BOOL CALLBACK idac_di_enum_callback(
static BOOL CALLBACK idac_di_enum_callback_shifter(
const DIDEVICEINSTANCEW *dev,
void *ctx);
static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out);
static void idac_di_get_buttons(uint8_t *gamebtn_out);
static uint8_t idac_di_decode_pov(DWORD pov);
static void idac_di_jvs_read_shifter(uint8_t *gear);
static void idac_di_jvs_read_shifter_pos(uint8_t *gear);
static void idac_di_jvs_read_shifter_virt(uint8_t *gear);
static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out);
static void idac_di_get_shifter(uint8_t *gear);
static void idac_di_get_shifter_pos(uint8_t *gear);
static void idac_di_get_shifter_virt(uint8_t *gear);
static void idac_di_get_analogs(struct idac_io_analog_state *out);
static const struct idac_di_axis idac_di_axes[] = {
/* Just map DIJOYSTATE for now, we can map DIJOYSTATE2 later if needed */
@ -49,9 +49,9 @@ static const struct idac_di_axis idac_di_axes[] = {
};
static const struct idac_io_backend idac_di_backend = {
.jvs_read_buttons = idac_di_jvs_read_buttons,
.jvs_read_shifter = idac_di_jvs_read_shifter,
.jvs_read_analogs = idac_di_jvs_read_analogs,
.get_gamebtns = idac_di_get_buttons,
.get_shifter = idac_di_get_shifter,
.get_analogs = idac_di_get_analogs,
};
static HWND idac_di_wnd;
@ -98,8 +98,8 @@ HRESULT idac_di_init(
}
/* Initial D Zero has some built-in DirectInput support that is not
particularly useful. idzhook shorts this out by redirecting dinput8.dll
to a no-op implementation of DirectInput. However, idzio does need to
particularly useful. idachook shorts this out by redirecting dinput8.dll
to a no-op implementation of DirectInput. However, idacio does need to
talk to the real operating system implementation of DirectInput without
the stub DLL interfering, so build a path to
C:\Windows\System32\dinput.dll here. */
@ -374,7 +374,7 @@ static BOOL CALLBACK idac_di_enum_callback_shifter(
return DIENUM_STOP;
}
static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out)
static void idac_di_get_buttons(uint8_t *gamebtn_out)
{
union idac_di_state state;
uint8_t gamebtn;
@ -416,18 +416,18 @@ static uint8_t idac_di_decode_pov(DWORD pov)
}
}
static void idac_di_jvs_read_shifter(uint8_t *gear)
static void idac_di_get_shifter(uint8_t *gear)
{
assert(gear != NULL);
if (idac_di_shifter != NULL) {
idac_di_jvs_read_shifter_pos(gear);
idac_di_get_shifter_pos(gear);
} else {
idac_di_jvs_read_shifter_virt(gear);
idac_di_get_shifter_virt(gear);
}
}
static void idac_di_jvs_read_shifter_pos(uint8_t *out)
static void idac_di_get_shifter_pos(uint8_t *out)
{
union idac_di_state state;
uint8_t btn_no;
@ -457,7 +457,7 @@ static void idac_di_jvs_read_shifter_pos(uint8_t *out)
*out = gear;
}
static void idac_di_jvs_read_shifter_virt(uint8_t *gear)
static void idac_di_get_shifter_virt(uint8_t *gear)
{
union idac_di_state state;
bool shift_dn;
@ -489,7 +489,7 @@ static void idac_di_jvs_read_shifter_virt(uint8_t *gear)
*gear = idac_shifter_current_gear();
}
static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out)
static void idac_di_get_analogs(struct idac_io_analog_state *out)
{
union idac_di_state state;
const LONG *brake;

View File

@ -16,14 +16,13 @@
static struct idac_io_config idac_io_cfg;
static const struct idac_io_backend *idac_io_backend;
static bool idac_io_coin;
static uint16_t idac_io_coins;
uint16_t idac_io_get_api_version(void)
{
return 0x0100;
}
HRESULT idac_io_jvs_init(void)
HRESULT idac_io_init(void)
{
HINSTANCE inst;
HRESULT hr;
@ -47,20 +46,19 @@ HRESULT idac_io_jvs_init(void)
hr = idac_xi_init(&idac_io_cfg.xi, &idac_io_backend);
} else {
hr = E_INVALIDARG;
dprintf("IDZ IO: Invalid IO mode \"%S\", use dinput or xinput\n",
dprintf("IDAC IO: Invalid IO mode \"%S\", use dinput or xinput\n",
idac_io_cfg.mode);
}
return hr;
}
void idac_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out)
void idac_io_get_opbtns(uint8_t *opbtn_out)
{
uint8_t opbtn;
assert(idac_io_backend != NULL);
assert(opbtn_out != NULL);
assert(gamebtn_out != NULL);
opbtn = 0;
@ -72,27 +70,43 @@ void idac_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out)
opbtn |= IDAC_IO_OPBTN_SERVICE;
}
*opbtn_out = opbtn;
if (GetAsyncKeyState(idac_io_cfg.vk_coin) & 0x8000) {
if (!idac_io_coin) {
idac_io_coin = true;
opbtn |= IDAC_IO_OPBTN_COIN;
}
} else {
idac_io_coin = false;
}
idac_io_backend->jvs_read_buttons(gamebtn_out);
*opbtn_out = opbtn;
}
void idac_io_jvs_read_shifter(uint8_t *gear)
void idac_io_get_gamebtns(uint8_t *gamebtn_out)
{
assert(idac_io_backend != NULL);
assert(gamebtn_out != NULL);
idac_io_backend->get_gamebtns(gamebtn_out);
}
void idac_io_get_shifter(uint8_t *gear)
{
assert(gear != NULL);
assert(idac_io_backend != NULL);
idac_io_backend->jvs_read_shifter(gear);
idac_io_backend->get_shifter(gear);
}
void idac_io_jvs_read_analogs(struct idac_io_analog_state *out)
void idac_io_get_analogs(struct idac_io_analog_state *out)
{
struct idac_io_analog_state tmp;
assert(out != NULL);
assert(idac_io_backend != NULL);
idac_io_backend->jvs_read_analogs(&tmp);
idac_io_backend->get_analogs(&tmp);
/* Apply steering wheel restriction. Real cabs only report about 77% of
the IO-3's max ADC output value when the wheel is turned to either of
@ -104,22 +118,3 @@ void idac_io_jvs_read_analogs(struct idac_io_analog_state *out)
out->accel = tmp.accel;
out->brake = tmp.brake;
}
void idac_io_jvs_read_coin_counter(uint16_t *out)
{
assert(out != NULL);
/* Coin counter is not backend-specific */
if (idac_io_cfg.vk_coin &&
(GetAsyncKeyState(idac_io_cfg.vk_coin) & 0x8000)) {
if (!idac_io_coin) {
idac_io_coin = true;
idac_io_coins++;
}
} else {
idac_io_coin = false;
}
*out = idac_io_coins;
}

9
idacio/idacio.def Normal file
View File

@ -0,0 +1,9 @@
LIBRARY idacio
EXPORTS
idac_io_init
idac_io_poll
idac_io_get_opbtns
idac_io_get_gamebtns
idac_io_get_shifter
idac_io_get_analogs

View File

@ -1,17 +1,5 @@
#pragma once
/* INITIAL D THE ARCADE CUSTOM IO API
This API definition allows custom driver DLLs to be defined for the
emulation of Initial D The Arcade cabinets. To be honest, there is very
little reason to want to do this, since driving game controllers are a
mostly-standardized PC peripheral which can be adequately controlled by the
built-in DirectInput and XInput support in idzhook. However, previous
versions of Segatools broke this functionality out into a separate DLL just
like all of the other supported games, so in the interests of maintaining
backwards compatibility we provide the option to load custom IDZIO
implementations as well. */
#include <windows.h>
#include <stdint.h>
@ -19,6 +7,7 @@
enum {
IDAC_IO_OPBTN_TEST = 0x01,
IDAC_IO_OPBTN_SERVICE = 0x02,
IDAC_IO_OPBTN_COIN = 0x04,
};
enum {
@ -49,7 +38,7 @@ struct idac_io_analog_state {
uint16_t brake;
};
/* Get the version of the IDZ IO API that this DLL supports. This
/* Get the version of the IDAC IO API that this DLL supports. This
function should return a positive 16-bit integer, where the high byte is
the major version and the low byte is the minor version (as defined by the
Semantic Versioning standard).
@ -58,33 +47,48 @@ struct idac_io_analog_state {
uint16_t idac_io_get_api_version(void);
/* Initialize JVS-based input. This function will be called before any other
idac_io_jvs_*() function calls. Errors returned from this function will
manifest as a disconnected JVS bus.
/* Initialize the IO DLL. This is the second function that will be called on
your DLL, after mu3_io_get_api_version.
All subsequent calls may originate from arbitrary threads and some may
overlap with each other. Ensuring synchronization inside your IO DLL is
your responsibility.
All subsequent calls to this API may originate from arbitrary threads.
Minimum API version: 0x0100 */
HRESULT idac_io_jvs_init(void);
HRESULT idac_io_init(void);
/* Send any queued outputs (of which there are currently none, though this may
change in subsequent API versions) and retrieve any new inputs.
Minimum API version: 0x0100 */
HRESULT idac_io_poll(void);
/* Get the state of the cabinet's operator buttons as of the last poll. See
MU3_IO_OPBTN enum above: this contains bit mask definitions for button
states returned in *opbtn. All buttons are active-high.
Minimum API version: 0x0100 */
void idac_io_get_opbtns(uint8_t *opbtn);
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
MU3_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into
a left hand side set of inputs and a right hand side set of inputs: the bit
mappings are the same in both cases.
All buttons are active-high, even though some buttons' electrical signals
on a real cabinet are active-low.
Minimum API version: 0x0100 */
void idac_io_get_gamebtns(uint8_t *gamebtn);
/* Poll the current state of the cabinet's JVS analog inputs. See structure
definition above for details.
Minimum API version: 0x0100 */
void idac_io_jvs_read_analogs(struct idac_io_analog_state *out);
/* Poll the current state of the cabinet's JVS input buttons and return them
through the opbtn and gamebtn out parameters. See enum definitions at the
top of this file for a list of bit masks to be used with these out
parameters.
Minimum API version: 0x0100 */
void idac_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn);
void idac_io_get_analogs(struct idac_io_analog_state *out);
/* Poll the current position of the six-speed shifter and return it via the
gear out parameter. Valid values are 0 for neutral and 1-6 for gears 1-6.
@ -95,12 +99,4 @@ void idac_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn);
Minimum API version: 0x0100 */
void idac_io_jvs_read_shifter(uint8_t *gear);
/* Read the current state of the coin counter. This value should be incremented
for every coin detected by the coin acceptor mechanism. This count does not
need to persist beyond the lifetime of the process.
Minimum API version: 0x0100 */
void idac_io_jvs_read_coin_counter(uint16_t *total);
void idac_io_get_shifter(uint8_t *gear);

View File

@ -1,8 +0,0 @@
LIBRARY idacio
EXPORTS
idac_io_jvs_init
idac_io_jvs_read_analogs
idac_io_jvs_read_buttons
idac_io_jvs_read_coin_counter
idac_io_jvs_read_shifter

View File

@ -1,14 +1,14 @@
#include <stdbool.h>
#include <stdint.h>
#include "idzio/shifter.h"
#include "idacio/shifter.h"
static bool idac_shifter_shifting;
static uint8_t idac_shifter_gear;
void idac_shifter_reset(void)
void idac_shifter_set(uint8_t gear)
{
idac_shifter_gear = 0;
idac_shifter_gear = gear;
}
void idac_shifter_update(bool shift_dn, bool shift_up)

View File

@ -3,6 +3,6 @@
#include <stdbool.h>
#include <stdint.h>
void idac_shifter_reset(void);
void idac_shifter_set(uint8_t gear);
void idac_shifter_update(bool shift_dn, bool shift_up);
uint8_t idac_shifter_current_gear(void);

View File

@ -31,13 +31,13 @@ HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out)
wcx.cbSize = sizeof(wcx);
wcx.lpfnWndProc = idac_io_wnd_proc;
wcx.hInstance = inst;
wcx.lpszClassName = L"IDZIO";
wcx.lpszClassName = L"IDACIO";
atom = RegisterClassExW(&wcx);
if (atom == 0) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("IDZIO: RegisterClassExW failed: %08x\n", (int) hr);
dprintf("IDACIO: RegisterClassExW failed: %08x\n", (int) hr);
goto fail;
}
@ -58,7 +58,7 @@ HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out)
if (hwnd == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("IDZIO: CreateWindowExW failed: %08x\n", (int) hr);
dprintf("IDACIO: CreateWindowExW failed: %08x\n", (int) hr);
goto fail;
}

View File

@ -13,16 +13,16 @@
#include "util/dprintf.h"
static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out);
static void idac_xi_jvs_read_shifter(uint8_t *gear);
static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out);
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out);
static void idac_xi_get_shifter(uint8_t *gear);
static void idac_xi_get_analogs(struct idac_io_analog_state *out);
static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg);
static const struct idac_io_backend idac_xi_backend = {
.jvs_read_buttons = idac_xi_jvs_read_buttons,
.jvs_read_shifter = idac_xi_jvs_read_shifter,
.jvs_read_analogs = idac_xi_jvs_read_analogs,
.get_gamebtns = idac_xi_get_gamebtns,
.get_shifter = idac_xi_get_shifter,
.get_analogs = idac_xi_get_analogs,
};
static bool idac_xi_single_stick_steering;
@ -45,6 +45,11 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back
return S_OK;
}
HRESULT idac_io_poll(void)
{
return S_OK;
}
static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg)
{
dprintf("XInput: --- Begin configuration ---\n");
@ -56,7 +61,7 @@ static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg)
return S_OK;
}
static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out)
static void idac_xi_get_gamebtns(uint8_t *gamebtn_out)
{
uint8_t gamebtn;
XINPUT_STATE xi;
@ -97,7 +102,7 @@ static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out)
*gamebtn_out = gamebtn;
}
static void idac_xi_jvs_read_shifter(uint8_t *gear)
static void idac_xi_get_shifter(uint8_t *gear)
{
bool shift_dn;
bool shift_up;
@ -112,9 +117,25 @@ static void idac_xi_jvs_read_shifter(uint8_t *gear)
if (xb & XINPUT_GAMEPAD_START) {
/* Reset to Neutral when start is pressed */
idac_shifter_reset();
idac_shifter_set(0);
}
/*
// Alternative shifting mode
if (xb & XINPUT_GAMEPAD_X) {
// Set to Gear 2 when X is pressed
idac_shifter_set(2);
}
if (xb & XINPUT_GAMEPAD_Y) {
// Set to Gear 3 when Y is pressed
idac_shifter_set(3);
}
shift_dn = xb & XINPUT_GAMEPAD_LEFT_SHOULDER;
shift_up = xb & XINPUT_GAMEPAD_RIGHT_SHOULDER;
*/
shift_dn = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER);
shift_up = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER);
@ -123,7 +144,7 @@ static void idac_xi_jvs_read_shifter(uint8_t *gear)
*gear = idac_shifter_current_gear();
}
static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out)
static void idac_xi_get_analogs(struct idac_io_analog_state *out)
{
XINPUT_STATE xi;
int left;
@ -154,7 +175,7 @@ static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out)
right = 0;
}
if(idac_xi_single_stick_steering) {
if (idac_xi_single_stick_steering) {
out->wheel = left;
} else {
out->wheel = (left + right) / 2;