forked from TeamTofuShop/segatools
swdc: fixed steering wheel buttons, improved start.bat
This commit is contained in:
@ -16,7 +16,6 @@
|
||||
#include "swdchook/config.h"
|
||||
#include "swdchook/swdc-dll.h"
|
||||
#include "swdchook/io4.h"
|
||||
#include "swdchook/zinput.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
@ -39,7 +38,6 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
serial_hook_init();
|
||||
zinput_hook_init(&swdc_hook_cfg.zinput, swdc_hook_mod);
|
||||
dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
@ -54,6 +52,12 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = swdc_dll_init(&swdc_hook_cfg.dll, swdc_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, 3, swdc_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
@ -66,18 +70,16 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = swdc_dll_init(&swdc_hook_cfg.dll, swdc_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = swdc_io4_hook_init(&swdc_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
zinput_hook_init(&swdc_hook_cfg.zinput);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
@ -6,9 +6,13 @@
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "swdchook/swdc-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
static HANDLE mmf;
|
||||
static HRESULT init_mmf(void);
|
||||
static void swdc_set_gamebtns(uint16_t value);
|
||||
|
||||
static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state);
|
||||
static uint16_t coins;
|
||||
@ -17,8 +21,7 @@ static const struct io4_ops swdc_io4_ops = {
|
||||
.poll = swdc_io4_poll,
|
||||
};
|
||||
|
||||
HRESULT swdc_io4_hook_init(const struct io4_config *cfg)
|
||||
{
|
||||
HRESULT swdc_io4_hook_init(const struct io4_config *cfg) {
|
||||
HRESULT hr;
|
||||
|
||||
assert(swdc_dll.init != NULL);
|
||||
@ -29,30 +32,54 @@ HRESULT swdc_io4_hook_init(const struct io4_config *cfg)
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = init_mmf();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return swdc_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
// Function to initialize the memory-mapped file
|
||||
static HRESULT init_mmf(void) {
|
||||
mmf = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, "SWDCButton");
|
||||
if (mmf == NULL) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
swdc_set_gamebtns(0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void swdc_set_gamebtns(uint16_t value) {
|
||||
// WaitForSingleObject(mutex, INFINITE);
|
||||
|
||||
// Update the memory-mapped file
|
||||
LPVOID mmf_view = MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, 2);
|
||||
if (mmf_view != NULL) {
|
||||
uint16_t* ptr = (uint16_t*)mmf_view;
|
||||
*ptr = value;
|
||||
|
||||
UnmapViewOfFile(mmf_view);
|
||||
}
|
||||
|
||||
// ReleaseMutex(mutex);
|
||||
}
|
||||
|
||||
static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) {
|
||||
uint8_t opbtn;
|
||||
uint16_t gamebtn;
|
||||
struct swdc_io_analog_state analog_state;
|
||||
HRESULT hr;
|
||||
|
||||
assert(swdc_dll.poll != NULL);
|
||||
assert(swdc_dll.get_opbtns != NULL);
|
||||
assert(swdc_dll.get_gamebtns != NULL);
|
||||
assert(swdc_dll.get_analogs != NULL);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
memset(&analog_state, 0, sizeof(analog_state));
|
||||
|
||||
hr = swdc_dll.poll();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
opbtn = 0;
|
||||
gamebtn = 0;
|
||||
|
||||
@ -99,7 +126,17 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state)
|
||||
state->buttons[0] |= 1 << 2;
|
||||
}
|
||||
|
||||
/* Update steering wheel buttons */
|
||||
/*
|
||||
Update steering wheel buttons
|
||||
|
||||
Those are connected to the SEGA838-15415 INDICATOR BD MAIN
|
||||
USB board which is not emulated for now. So those buttons
|
||||
are hooked to the built-in XInput support.
|
||||
*/
|
||||
|
||||
/* Instead update gamebtns for the file mapping */
|
||||
|
||||
swdc_set_gamebtns(gamebtn);
|
||||
|
||||
if (gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) {
|
||||
state->buttons[1] |= 1 << 15;
|
||||
|
@ -12,9 +12,6 @@ const struct dll_bind_sym swdc_dll_syms[] = {
|
||||
{
|
||||
.sym = "swdc_io_init",
|
||||
.off = offsetof(struct swdc_dll, init),
|
||||
}, {
|
||||
.sym = "swdc_io_poll",
|
||||
.off = offsetof(struct swdc_dll, poll),
|
||||
}, {
|
||||
.sym = "swdc_io_get_opbtns",
|
||||
.off = offsetof(struct swdc_dll, get_opbtns),
|
||||
|
@ -7,7 +7,6 @@
|
||||
struct swdc_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint16_t *gamebtn);
|
||||
void (*get_analogs)(struct swdc_io_analog_state *out);
|
||||
|
@ -13,7 +13,6 @@ EXPORTS
|
||||
amDllVideoSetResolution @3
|
||||
swdc_io_get_api_version
|
||||
swdc_io_init
|
||||
swdc_io_poll
|
||||
swdc_io_get_opbtns
|
||||
swdc_io_get_gamebtns
|
||||
swdc_io_get_analogs
|
||||
|
@ -1,31 +1,61 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xinput.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/lib.h"
|
||||
|
||||
#include "swdchook/config.h"
|
||||
#include "swdchook/zinput.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
static struct zinput_config zinput_config;
|
||||
static bool zinput_hook_initted;
|
||||
static bool zinput_controller_init = false;
|
||||
|
||||
#include "util/dprintf.h"
|
||||
static HRESULT init_mmf(void);
|
||||
|
||||
static HANDLE mmf;
|
||||
static uint16_t* swdc_gamebtn;
|
||||
|
||||
/* Hooked functions */
|
||||
DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState);
|
||||
DWORD WINAPI hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
|
||||
// Not needed for now?
|
||||
DWORD WINAPI hook_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities);
|
||||
|
||||
static const struct hook_symbol zinput_hook_syms[] = {
|
||||
// Yup SEGA imports XInput functions via ordinal. FUN!
|
||||
static struct hook_symbol zinput_hook_syms[] = {
|
||||
{
|
||||
.name = "XInputGetState",
|
||||
.patch = hook_XInputGetState,
|
||||
.link = NULL
|
||||
.name = "XInputGetState",
|
||||
.ordinal = 0x0002,
|
||||
.patch = hook_XInputGetState,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "XInputSetState",
|
||||
.ordinal = 0x0003,
|
||||
.patch = hook_XInputSetState,
|
||||
.link = NULL
|
||||
}, {
|
||||
// Not needed for now?
|
||||
.name = "XInputGetCapabilities",
|
||||
.patch = hook_XInputGetCapabilities,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
static struct zinput_config zinput_config;
|
||||
static bool zinput_hook_initted;
|
||||
|
||||
void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self)
|
||||
void zinput_hook_init(struct zinput_config *cfg)
|
||||
{
|
||||
wchar_t *module_path;
|
||||
wchar_t *file_name;
|
||||
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
@ -36,45 +66,149 @@ void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self)
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&zinput_config, cfg, sizeof(*cfg));
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"XINPUT9_1_0.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
module_path = module_file_name(NULL);
|
||||
|
||||
if (module_path != NULL) {
|
||||
file_name = PathFindFileNameW(module_path);
|
||||
|
||||
free(module_path);
|
||||
module_path = NULL;
|
||||
|
||||
_wcslwr(file_name);
|
||||
|
||||
if (wcsstr(file_name, L"amdaemon") != NULL) {
|
||||
// dprintf("Executable filename contains 'amdaemon', disabling zinput\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"XINPUT1_1.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"XINPUT1_2.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"XINPUT1_3.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"XINPUT1_4.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
NULL,
|
||||
"XINPUT1_3.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
|
||||
if (FAILED(init_mmf())) {
|
||||
return;
|
||||
}
|
||||
|
||||
zinput_hook_initted = true;
|
||||
|
||||
dprintf("ZInput: Blocking built-in XInput support\n");
|
||||
dprintf("ZInput: Hooking built-in XInput support\n");
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState)
|
||||
{
|
||||
bool zinput_connect_controller(bool enable) {
|
||||
zinput_controller_init = enable;
|
||||
dprintf("zinput_connect_controller\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static HRESULT init_mmf(void) {
|
||||
// Create or open memory-mapped file
|
||||
mmf = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, "SWDCButton");
|
||||
if (mmf == NULL) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Map the memory-mapped file
|
||||
swdc_gamebtn = (uint16_t*)MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, 2);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities) {
|
||||
// dprintf("ZInput: XInputGetCapabilities hook hit\n");
|
||||
|
||||
if (!zinput_controller_init) {
|
||||
zinput_connect_controller(true);
|
||||
}
|
||||
|
||||
if (dwFlags > XINPUT_FLAG_GAMEPAD) {
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (zinput_controller_init && dwUserIndex == 0) {
|
||||
pCapabilities->Flags = XINPUT_CAPS_VOICE_SUPPORTED;
|
||||
pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD;
|
||||
pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD;
|
||||
|
||||
pCapabilities->Gamepad.wButtons = 0xF3FF;
|
||||
|
||||
pCapabilities->Gamepad.bLeftTrigger = 0xFF;
|
||||
pCapabilities->Gamepad.bRightTrigger = 0xFF;
|
||||
|
||||
pCapabilities->Gamepad.sThumbLX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbLY = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRY = (SHORT)0xFFC0;
|
||||
|
||||
pCapabilities->Vibration.wLeftMotorSpeed = 0xFF;
|
||||
pCapabilities->Vibration.wRightMotorSpeed = 0xFF;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) {
|
||||
// dprintf("ZInput: XInputGetState hook hit\n");
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
if (!zinput_controller_init) {
|
||||
zinput_connect_controller(true);
|
||||
}
|
||||
|
||||
if (zinput_controller_init && dwUserIndex == 0) {
|
||||
XINPUT_GAMEPAD gamepad_state = {0};
|
||||
gamepad_state.wButtons = 0;
|
||||
|
||||
/* Read filemapping for for the gamebtns */
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER;
|
||||
}
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER;
|
||||
}
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_X;
|
||||
}
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_RED) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_B;
|
||||
}
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_GREEN) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_A;
|
||||
}
|
||||
|
||||
if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_YELLOW) {
|
||||
gamepad_state.wButtons |= XINPUT_GAMEPAD_Y;
|
||||
}
|
||||
if (pState->dwPacketNumber == UINT_MAX)
|
||||
pState->dwPacketNumber = 0;
|
||||
else
|
||||
pState->dwPacketNumber++;
|
||||
|
||||
pState->Gamepad = gamepad_state;
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration) {
|
||||
// dprintf("ZInput: XInputSetState hook hit\n");
|
||||
|
||||
if (!zinput_controller_init) {
|
||||
zinput_connect_controller(true);
|
||||
}
|
||||
|
||||
if (zinput_controller_init && dwUserIndex == 0) {
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
@ -8,4 +8,4 @@ struct zinput_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self);
|
||||
void zinput_hook_init(struct zinput_config *cfg);
|
||||
|
Reference in New Issue
Block a user