diff --git a/idzhook/jvs.c b/idzhook/jvs.c index 9d278c2..f43e092 100644 --- a/idzhook/jvs.c +++ b/idzhook/jvs.c @@ -1,11 +1,7 @@ #include -#include -#include #include -#include #include -#include #include "amex/jvs.h" @@ -13,6 +9,8 @@ #include "idzhook/jvs.h" +#include "idzio/idzio.h" + #include "jvs/jvs-bus.h" #include "util/dprintf.h" @@ -30,12 +28,6 @@ static const struct io3_ops idz_jvs_io3_ops = { .read_coin_counter = idz_jvs_read_coin_counter, }; -static struct io3 idz_jvs_io3; -static bool idz_jvs_coin; -static uint16_t idz_jvs_coins; -static bool idz_jvs_shifting; -static uint8_t idz_jvs_gear; - static const uint16_t idz_jvs_gear_signals[] = { /* Neutral */ 0x0000, @@ -53,79 +45,82 @@ static const uint16_t idz_jvs_gear_signals[] = { 0x1400, }; -void idz_jvs_init(void) +static struct io3 idz_jvs_io3; + +HRESULT idz_jvs_init(void) { + HRESULT hr; + + hr = idz_io_init(); + + if (FAILED(hr)) { + return hr; + } + io3_init(&idz_jvs_io3, NULL, &idz_jvs_io3_ops, NULL); jvs_attach(&idz_jvs_io3.jvs); + + return S_OK; } static void idz_jvs_read_switches(void *ctx, struct io3_switch_state *out) { - bool shift_inc; - bool shift_dec; - XINPUT_STATE xi; - WORD xb; + uint8_t opbtn; + uint8_t gamebtn; + uint8_t gear; assert(out != NULL); - memset(&xi, 0, sizeof(xi)); - XInputGetState(0, &xi); - xb = xi.Gamepad.wButtons; + opbtn = 0; + gamebtn = 0; + gear = 0; + + idz_io_jvs_read_buttons(&opbtn, &gamebtn); + idz_io_jvs_read_shifter(&gear); /* Update gameplay buttons */ - if (xb & XINPUT_GAMEPAD_START) { - out->p1 |= 1 << 15; - idz_jvs_gear = 0; /* Reset to Neutral when start is pressed */ - } - - if (xb & XINPUT_GAMEPAD_DPAD_UP) { + if (gamebtn & IDZ_IO_GAMEBTN_UP) { out->p1 |= 1 << 13; } - if (xb & XINPUT_GAMEPAD_DPAD_DOWN) { + if (gamebtn & IDZ_IO_GAMEBTN_DOWN) { out->p1 |= 1 << 12; } - if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + if (gamebtn & IDZ_IO_GAMEBTN_LEFT) { out->p1 |= 1 << 11; } - if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + if (gamebtn & IDZ_IO_GAMEBTN_RIGHT) { out->p1 |= 1 << 10; } - if (xb & XINPUT_GAMEPAD_BACK) { + if (gamebtn & IDZ_IO_GAMEBTN_START) { + out->p1 |= 1 << 15; + } + + if (gamebtn & IDZ_IO_GAMEBTN_VIEW_CHANGE) { out->p1 |= 1 << 9; } /* Update simulated six-speed shifter */ - shift_inc = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER); - shift_dec = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER); - - if (!idz_jvs_shifting) { - if (shift_inc && idz_jvs_gear < 6) { - idz_jvs_gear++; - } - - if (shift_dec && idz_jvs_gear > 0) { - idz_jvs_gear--; - } + if (gear > 6) { + gear = 6; } - idz_jvs_shifting = shift_inc || shift_dec; - out->p2 = idz_jvs_gear_signals[idz_jvs_gear]; + out->p2 = idz_jvs_gear_signals[gear]; /* Update test/service buttons */ - if (GetAsyncKeyState('1')) { + if (opbtn & IDZ_IO_OPBTN_TEST) { out->system = 0x80; } else { out->system = 0; } - if (GetAsyncKeyState('2')) { + if (opbtn & IDZ_IO_OPBTN_SERVICE) { out->p1 |= 1 << 14; } } @@ -135,51 +130,23 @@ static void idz_jvs_read_analogs( uint16_t *analogs, uint8_t nanalogs) { - XINPUT_STATE xi; - int left; - int right; + struct idz_io_analog_state state; assert(analogs != NULL); - memset(&xi, 0, sizeof(xi)); - XInputGetState(0, &xi); - - /* Wheel */ + memset(&state, 0, sizeof(state)); + idz_io_jvs_read_analogs(&state); if (nanalogs > 0) { - left = xi.Gamepad.sThumbLX; - - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else { - left = 0; - } - - right = xi.Gamepad.sThumbRX; - - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else { - right = 0; - } - - analogs[0] = 0x8000 + (left + right) / 2; + analogs[0] = 0x8000 + state.wheel; } - /* Accel */ - if (nanalogs > 1) { - analogs[1] = xi.Gamepad.bRightTrigger << 8; + analogs[1] = state.accel; } - /* Brake */ - if (nanalogs > 2) { - analogs[2] = xi.Gamepad.bLeftTrigger << 8; + analogs[2] = state.brake; } } @@ -189,15 +156,5 @@ static uint16_t idz_jvs_read_coin_counter(void *ctx, uint8_t slot_no) return 0; } - if (GetAsyncKeyState('3')) { - if (!idz_jvs_coin) { - dprintf("IDZero JVS: Coin drop\n"); - idz_jvs_coin = true; - idz_jvs_coins++; - } - } else { - idz_jvs_coin = false; - } - - return idz_jvs_coins; + return idz_io_jvs_read_coin_counter(); } diff --git a/idzhook/jvs.h b/idzhook/jvs.h index be29753..5320541 100644 --- a/idzhook/jvs.h +++ b/idzhook/jvs.h @@ -1,3 +1,5 @@ #pragma once -void idz_jvs_init(void); +#include + +HRESULT idz_jvs_init(void); diff --git a/idzhook/meson.build b/idzhook/meson.build index 6c54744..e330b9a 100644 --- a/idzhook/meson.build +++ b/idzhook/meson.build @@ -14,6 +14,7 @@ shared_library( aimeio_dll, amex_lib, board_lib, + idzio_dll, jvs_lib, platform_lib, util_lib, diff --git a/idzio/idzio.c b/idzio/idzio.c new file mode 100644 index 0000000..55943ff --- /dev/null +++ b/idzio/idzio.c @@ -0,0 +1,151 @@ +#include +#include + +#include +#include + +#include "idzio/idzio.h" + +static bool idz_io_coin; +static uint16_t idz_io_coins; +static bool idz_io_shifting; +static uint8_t idz_io_gear; + +HRESULT idz_io_init(void) +{ + return S_OK; +} + +void idz_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) +{ + uint8_t opbtn; + uint8_t gamebtn; + XINPUT_STATE xi; + WORD xb; + + opbtn = 0; + gamebtn = 0; + + /* Update test/service buttons */ + + if (GetAsyncKeyState('1')) { + opbtn |= IDZ_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState('2')) { + opbtn |= IDZ_IO_OPBTN_SERVICE; + } + + /* Update gameplay buttons */ + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xb & XINPUT_GAMEPAD_DPAD_UP) { + gamebtn |= IDZ_IO_GAMEBTN_UP; + } + + if (xb & XINPUT_GAMEPAD_DPAD_DOWN) { + gamebtn |= IDZ_IO_GAMEBTN_DOWN; + } + + if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + gamebtn |= IDZ_IO_GAMEBTN_LEFT; + } + + if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + gamebtn |= IDZ_IO_GAMEBTN_RIGHT; + } + + if (xb & XINPUT_GAMEPAD_START) { + gamebtn |= IDZ_IO_GAMEBTN_START; + } + + if (xb & XINPUT_GAMEPAD_BACK) { + gamebtn |= IDZ_IO_GAMEBTN_VIEW_CHANGE; + } + + *opbtn_out = opbtn; + *gamebtn_out = gamebtn; +} + +void idz_io_jvs_read_shifter(uint8_t *gear) +{ + bool shift_inc; + bool shift_dec; + XINPUT_STATE xi; + WORD xb; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xb & XINPUT_GAMEPAD_START) { + idz_io_gear = 0; /* Reset to Neutral when start is pressed */ + } + + shift_inc = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER); + shift_dec = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER); + + if (!idz_io_shifting) { + if (shift_inc && idz_io_gear < 6) { + idz_io_gear++; + } + + if (shift_dec && idz_io_gear > 0) { + idz_io_gear--; + } + } + + idz_io_shifting = shift_inc || shift_dec; + *gear = idz_io_gear; +} + +void idz_io_jvs_read_analogs(struct idz_io_analog_state *out) +{ + XINPUT_STATE xi; + int left; + int right; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + left = xi.Gamepad.sThumbLX; + + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + right = xi.Gamepad.sThumbRX; + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } + + out->wheel = (left + right) / 2; + out->accel = xi.Gamepad.bRightTrigger << 8; + out->brake = xi.Gamepad.bLeftTrigger << 8; +} + +uint16_t idz_io_jvs_read_coin_counter(void) +{ + if (GetAsyncKeyState('3')) { + if (!idz_io_coin) { + idz_io_coin = true; + idz_io_coins++; + } + } else { + idz_io_coin = false; + } + + return idz_io_coins; +} diff --git a/idzio/idzio.def b/idzio/idzio.def new file mode 100644 index 0000000..3a418c9 --- /dev/null +++ b/idzio/idzio.def @@ -0,0 +1,8 @@ +LIBRARY idzio + +EXPORTS + idz_io_init + idz_io_jvs_read_analogs + idz_io_jvs_read_buttons + idz_io_jvs_read_coin_counter + idz_io_jvs_read_shifter diff --git a/idzio/idzio.h b/idzio/idzio.h new file mode 100644 index 0000000..edcdafe --- /dev/null +++ b/idzio/idzio.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include + +enum { + IDZ_IO_OPBTN_TEST = 0x01, + IDZ_IO_OPBTN_SERVICE = 0x02, +}; + +enum { + IDZ_IO_GAMEBTN_UP = 0x01, + IDZ_IO_GAMEBTN_DOWN = 0x02, + IDZ_IO_GAMEBTN_LEFT = 0x04, + IDZ_IO_GAMEBTN_RIGHT = 0x08, + IDZ_IO_GAMEBTN_START = 0x10, + IDZ_IO_GAMEBTN_VIEW_CHANGE = 0x20, +}; + +struct idz_io_analog_state { + int16_t wheel; + uint16_t accel; + uint16_t brake; +}; + +HRESULT idz_io_init(void); + +void idz_io_jvs_read_analogs(struct idz_io_analog_state *out); + +void idz_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn); + +void idz_io_jvs_read_shifter(uint8_t *gear); + +uint16_t idz_io_jvs_read_coin_counter(void); + +// TODO force feedback once that gets reverse engineered diff --git a/idzio/meson.build b/idzio/meson.build new file mode 100644 index 0000000..b6306d9 --- /dev/null +++ b/idzio/meson.build @@ -0,0 +1,15 @@ +idzio_dll = shared_library( + 'idzio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'idzio.def', + c_pch : '../precompiled.h', + dependencies : [ + xinput_lib, + ], + sources : [ + 'idzio.c', + 'idzio.h', + ], +) diff --git a/meson.build b/meson.build index 66b2c0a..66fdb8a 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,7 @@ subdir('util') subdir('aimeio') subdir('chuniio') subdir('divaio') +subdir('idzio') subdir('cardhook') subdir('chunihook')