forked from Dniel97/segatools
swdc: fixed steering wheel buttons, improved start.bat
This commit is contained in:
parent
0affc96e3e
commit
cc0b6b0953
@ -111,6 +111,7 @@ $(BUILD_DIR_ZIP)/swdc.zip:
|
|||||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_64)/swdchook/swdchook.dll \
|
$(BUILD_DIR_64)/swdchook/swdchook.dll \
|
||||||
$(DIST_DIR)/swdc/segatools.ini \
|
$(DIST_DIR)/swdc/segatools.ini \
|
||||||
|
$(DIST_DIR)/swdc/config_hook.json \
|
||||||
$(DIST_DIR)/swdc/start.bat \
|
$(DIST_DIR)/swdc/start.bat \
|
||||||
$(BUILD_DIR_ZIP)/swdc
|
$(BUILD_DIR_ZIP)/swdc
|
||||||
$(V)cp pki/billing.pub \
|
$(V)cp pki/billing.pub \
|
||||||
|
6
dist/swdc/config_hook.json
vendored
Normal file
6
dist/swdc/config_hook.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"emoney" :
|
||||||
|
{
|
||||||
|
"enable" : false
|
||||||
|
}
|
||||||
|
}
|
2
dist/swdc/segatools.ini
vendored
2
dist/swdc/segatools.ini
vendored
@ -6,7 +6,7 @@ option=
|
|||||||
; Create an empty directory somewhere and insert the path here.
|
; Create an empty directory somewhere and insert the path here.
|
||||||
; This directory may be shared between multiple SEGA games.
|
; This directory may be shared between multiple SEGA games.
|
||||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||||
appdata=
|
appdata=appdata
|
||||||
|
|
||||||
[aime]
|
[aime]
|
||||||
; Controls emulation of the Aime card reader assembly.
|
; Controls emulation of the Aime card reader assembly.
|
||||||
|
36
dist/swdc/start.bat
vendored
36
dist/swdc/start.bat
vendored
@ -2,12 +2,36 @@
|
|||||||
|
|
||||||
pushd %~dp0
|
pushd %~dp0
|
||||||
|
|
||||||
rem Matching Server
|
REM Root directory
|
||||||
start /min ..\..\..\Tools\tdrserver.exe
|
set ROOT_DIR=WindowsNoEditor
|
||||||
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
|
rem Matching Server paths
|
||||||
REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet
|
set MATCHING_SERVER_FILE_NAME=tdrserver.exe
|
||||||
inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
set MATCHING_SERVER_PATH=..\Tools\%MATCHING_SERVER_FILE_NAME%
|
||||||
|
|
||||||
|
rem AM Daemon paths
|
||||||
|
set DAEMON_DIR=%ROOT_DIR%\AMDaemon
|
||||||
|
set DAEMON_CONFIG_PATH=%DAEMON_DIR%\config.json
|
||||||
|
rem Make sure to use appdata=appdata in segatools.ini
|
||||||
|
set DAEMON_CHECK_LAN_SERVER_PATH=appdata\SDDS\LanServer.dat
|
||||||
|
|
||||||
|
rem Check if LanServer.dat is present
|
||||||
|
if exist "%DAEMON_CHECK_LAN_SERVER_PATH%" (
|
||||||
|
set DAEMON_LAN_CONFIG_PATH=%DAEMON_DIR%\config_LanServer.json
|
||||||
|
|
||||||
|
start "matching_server" /min %MATCHING_SERVER_PATH%
|
||||||
|
) else (
|
||||||
|
set DAEMON_LAN_CONFIG_PATH=%DAEMON_DIR%\config_LanClient.json
|
||||||
|
)
|
||||||
|
|
||||||
|
start "AM Daemon" /min inject -d -k swdchook.dll "%DAEMON_DIR%\amdaemon.exe" -c %DAEMON_CONFIG_PATH% -c %DAEMON_LAN_CONFIG_PATH% config_hook.json
|
||||||
|
|
||||||
|
REM Launch Todoroki
|
||||||
|
set APP_EXE_DIR=WindowsNoEditor\Todoroki\Binaries\Win64
|
||||||
|
set APP_EXE_PATH=%APP_EXE_DIR%\Todoroki-Win64-Shipping.exe
|
||||||
|
|
||||||
|
REM Valid -launch parameters are "Cabinet" or "MiniCabinet"
|
||||||
|
inject -d -k swdchook.dll "%APP_EXE_PATH%" -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
|
taskkill /f /im tdrserver.exe > nul 2>&1
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "swdchook/config.h"
|
#include "swdchook/config.h"
|
||||||
#include "swdchook/swdc-dll.h"
|
#include "swdchook/swdc-dll.h"
|
||||||
#include "swdchook/io4.h"
|
#include "swdchook/io4.h"
|
||||||
#include "swdchook/zinput.h"
|
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
@ -39,7 +38,6 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
|||||||
/* Hook Win32 APIs */
|
/* Hook Win32 APIs */
|
||||||
|
|
||||||
serial_hook_init();
|
serial_hook_init();
|
||||||
zinput_hook_init(&swdc_hook_cfg.zinput, swdc_hook_mod);
|
|
||||||
dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod);
|
dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod);
|
||||||
|
|
||||||
/* Initialize emulation hooks */
|
/* Initialize emulation hooks */
|
||||||
@ -54,6 +52,12 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
|||||||
goto fail;
|
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);
|
hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, 3, swdc_hook_mod);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
@ -66,18 +70,16 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
|||||||
return hr;
|
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);
|
hr = swdc_io4_hook_init(&swdc_hook_cfg.io4);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hook external DLL APIs */
|
||||||
|
|
||||||
|
zinput_hook_init(&swdc_hook_cfg.zinput);
|
||||||
|
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
spike_hook_init(L".\\segatools.ini");
|
spike_hook_init(L".\\segatools.ini");
|
||||||
|
@ -6,9 +6,13 @@
|
|||||||
|
|
||||||
#include "board/io4.h"
|
#include "board/io4.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
#include "swdchook/swdc-dll.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 HRESULT swdc_io4_poll(void *ctx, struct io4_state *state);
|
||||||
static uint16_t coins;
|
static uint16_t coins;
|
||||||
@ -17,8 +21,7 @@ static const struct io4_ops swdc_io4_ops = {
|
|||||||
.poll = swdc_io4_poll,
|
.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;
|
HRESULT hr;
|
||||||
|
|
||||||
assert(swdc_dll.init != NULL);
|
assert(swdc_dll.init != NULL);
|
||||||
@ -29,30 +32,54 @@ HRESULT swdc_io4_hook_init(const struct io4_config *cfg)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = init_mmf();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
return swdc_dll.init();
|
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;
|
uint8_t opbtn;
|
||||||
uint16_t gamebtn;
|
uint16_t gamebtn;
|
||||||
struct swdc_io_analog_state analog_state;
|
struct swdc_io_analog_state analog_state;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
assert(swdc_dll.poll != NULL);
|
|
||||||
assert(swdc_dll.get_opbtns != NULL);
|
assert(swdc_dll.get_opbtns != NULL);
|
||||||
assert(swdc_dll.get_gamebtns != NULL);
|
assert(swdc_dll.get_gamebtns != NULL);
|
||||||
assert(swdc_dll.get_analogs != NULL);
|
assert(swdc_dll.get_analogs != NULL);
|
||||||
|
|
||||||
memset(state, 0, sizeof(*state));
|
memset(state, 0, sizeof(*state));
|
||||||
memset(&analog_state, 0, sizeof(analog_state));
|
memset(&analog_state, 0, sizeof(analog_state));
|
||||||
|
|
||||||
hr = swdc_dll.poll();
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
opbtn = 0;
|
opbtn = 0;
|
||||||
gamebtn = 0;
|
gamebtn = 0;
|
||||||
|
|
||||||
@ -99,7 +126,17 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state)
|
|||||||
state->buttons[0] |= 1 << 2;
|
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) {
|
if (gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) {
|
||||||
state->buttons[1] |= 1 << 15;
|
state->buttons[1] |= 1 << 15;
|
||||||
|
@ -12,9 +12,6 @@ const struct dll_bind_sym swdc_dll_syms[] = {
|
|||||||
{
|
{
|
||||||
.sym = "swdc_io_init",
|
.sym = "swdc_io_init",
|
||||||
.off = offsetof(struct swdc_dll, init),
|
.off = offsetof(struct swdc_dll, init),
|
||||||
}, {
|
|
||||||
.sym = "swdc_io_poll",
|
|
||||||
.off = offsetof(struct swdc_dll, poll),
|
|
||||||
}, {
|
}, {
|
||||||
.sym = "swdc_io_get_opbtns",
|
.sym = "swdc_io_get_opbtns",
|
||||||
.off = offsetof(struct swdc_dll, get_opbtns),
|
.off = offsetof(struct swdc_dll, get_opbtns),
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
struct swdc_dll {
|
struct swdc_dll {
|
||||||
uint16_t api_version;
|
uint16_t api_version;
|
||||||
HRESULT (*init)(void);
|
HRESULT (*init)(void);
|
||||||
HRESULT (*poll)(void);
|
|
||||||
void (*get_opbtns)(uint8_t *opbtn);
|
void (*get_opbtns)(uint8_t *opbtn);
|
||||||
void (*get_gamebtns)(uint16_t *gamebtn);
|
void (*get_gamebtns)(uint16_t *gamebtn);
|
||||||
void (*get_analogs)(struct swdc_io_analog_state *out);
|
void (*get_analogs)(struct swdc_io_analog_state *out);
|
||||||
|
@ -13,7 +13,6 @@ EXPORTS
|
|||||||
amDllVideoSetResolution @3
|
amDllVideoSetResolution @3
|
||||||
swdc_io_get_api_version
|
swdc_io_get_api_version
|
||||||
swdc_io_init
|
swdc_io_init
|
||||||
swdc_io_poll
|
|
||||||
swdc_io_get_opbtns
|
swdc_io_get_opbtns
|
||||||
swdc_io_get_gamebtns
|
swdc_io_get_gamebtns
|
||||||
swdc_io_get_analogs
|
swdc_io_get_analogs
|
||||||
|
@ -1,31 +1,61 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <xinput.h>
|
#include <shlwapi.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.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/config.h"
|
||||||
#include "swdchook/zinput.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_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",
|
.name = "XInputGetState",
|
||||||
|
.ordinal = 0x0002,
|
||||||
.patch = hook_XInputGetState,
|
.patch = hook_XInputGetState,
|
||||||
.link = NULL
|
.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;
|
void zinput_hook_init(struct zinput_config *cfg)
|
||||||
static bool zinput_hook_initted;
|
|
||||||
|
|
||||||
void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self)
|
|
||||||
{
|
{
|
||||||
|
wchar_t *module_path;
|
||||||
|
wchar_t *file_name;
|
||||||
|
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
|
|
||||||
if (!cfg->enable) {
|
if (!cfg->enable) {
|
||||||
@ -36,24 +66,21 @@ void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&zinput_config, cfg, sizeof(*cfg));
|
module_path = module_file_name(NULL);
|
||||||
hook_table_apply(
|
|
||||||
NULL,
|
|
||||||
"XINPUT9_1_0.dll",
|
|
||||||
zinput_hook_syms,
|
|
||||||
_countof(zinput_hook_syms));
|
|
||||||
|
|
||||||
hook_table_apply(
|
if (module_path != NULL) {
|
||||||
NULL,
|
file_name = PathFindFileNameW(module_path);
|
||||||
"XINPUT1_1.dll",
|
|
||||||
zinput_hook_syms,
|
|
||||||
_countof(zinput_hook_syms));
|
|
||||||
|
|
||||||
hook_table_apply(
|
free(module_path);
|
||||||
NULL,
|
module_path = NULL;
|
||||||
"XINPUT1_2.dll",
|
|
||||||
zinput_hook_syms,
|
_wcslwr(file_name);
|
||||||
_countof(zinput_hook_syms));
|
|
||||||
|
if (wcsstr(file_name, L"amdaemon") != NULL) {
|
||||||
|
// dprintf("Executable filename contains 'amdaemon', disabling zinput\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hook_table_apply(
|
hook_table_apply(
|
||||||
NULL,
|
NULL,
|
||||||
@ -61,20 +88,127 @@ void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self)
|
|||||||
zinput_hook_syms,
|
zinput_hook_syms,
|
||||||
_countof(zinput_hook_syms));
|
_countof(zinput_hook_syms));
|
||||||
|
|
||||||
hook_table_apply(
|
if (FAILED(init_mmf())) {
|
||||||
NULL,
|
return;
|
||||||
"XINPUT1_4.dll",
|
}
|
||||||
zinput_hook_syms,
|
|
||||||
_countof(zinput_hook_syms));
|
|
||||||
|
|
||||||
zinput_hook_initted = true;
|
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: XInputGetState hook hit\n");
|
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;
|
return ERROR_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return ERROR_DEVICE_NOT_CONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) {
|
||||||
|
// dprintf("ZInput: XInputGetState hook hit\n");
|
||||||
|
|
||||||
|
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;
|
bool enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self);
|
void zinput_hook_init(struct zinput_config *cfg);
|
||||||
|
@ -28,9 +28,6 @@ static BOOL CALLBACK swdc_di_enum_callback(
|
|||||||
static BOOL CALLBACK swdc_di_enum_callback_pedals(
|
static BOOL CALLBACK swdc_di_enum_callback_pedals(
|
||||||
const DIDEVICEINSTANCEW *dev,
|
const DIDEVICEINSTANCEW *dev,
|
||||||
void *ctx);
|
void *ctx);
|
||||||
static BOOL CALLBACK swdc_di_enum_callback_shifter(
|
|
||||||
const DIDEVICEINSTANCEW *dev,
|
|
||||||
void *ctx);
|
|
||||||
static void swdc_di_get_buttons(uint16_t *gamebtn_out);
|
static void swdc_di_get_buttons(uint16_t *gamebtn_out);
|
||||||
static uint8_t swdc_di_decode_pov(DWORD pov);
|
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);
|
||||||
|
@ -2,7 +2,6 @@ LIBRARY swdcio
|
|||||||
|
|
||||||
EXPORTS
|
EXPORTS
|
||||||
swdc_io_init
|
swdc_io_init
|
||||||
swdc_io_poll
|
|
||||||
swdc_io_get_opbtns
|
swdc_io_get_opbtns
|
||||||
swdc_io_get_gamebtns
|
swdc_io_get_gamebtns
|
||||||
swdc_io_get_analogs
|
swdc_io_get_analogs
|
||||||
|
@ -55,7 +55,7 @@ struct swdc_io_analog_state {
|
|||||||
uint16_t swdc_io_get_api_version(void);
|
uint16_t swdc_io_get_api_version(void);
|
||||||
|
|
||||||
/* Initialize the IO DLL. This is the second function that will be called on
|
/* Initialize the IO DLL. This is the second function that will be called on
|
||||||
your DLL, after mu3_io_get_api_version.
|
your DLL, after SWDC_io_get_api_version.
|
||||||
|
|
||||||
All subsequent calls to this API may originate from arbitrary threads.
|
All subsequent calls to this API may originate from arbitrary threads.
|
||||||
|
|
||||||
@ -63,15 +63,8 @@ uint16_t swdc_io_get_api_version(void);
|
|||||||
|
|
||||||
HRESULT swdc_io_init(void);
|
HRESULT swdc_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 swdc_io_poll(void);
|
|
||||||
|
|
||||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
/* 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
|
SWDC_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||||
states returned in *opbtn. All buttons are active-high.
|
states returned in *opbtn. All buttons are active-high.
|
||||||
|
|
||||||
Minimum API version: 0x0100 */
|
Minimum API version: 0x0100 */
|
||||||
@ -79,7 +72,7 @@ HRESULT swdc_io_poll(void);
|
|||||||
void swdc_io_get_opbtns(uint8_t *opbtn);
|
void swdc_io_get_opbtns(uint8_t *opbtn);
|
||||||
|
|
||||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
/* 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
|
SWDC_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
|
a left hand side set of inputs and a right hand side set of inputs: the bit
|
||||||
mappings are the same in both cases.
|
mappings are the same in both cases.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user