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 \
|
||||
$(BUILD_DIR_64)/swdchook/swdchook.dll \
|
||||
$(DIST_DIR)/swdc/segatools.ini \
|
||||
$(DIST_DIR)/swdc/config_hook.json \
|
||||
$(DIST_DIR)/swdc/start.bat \
|
||||
$(BUILD_DIR_ZIP)/swdc
|
||||
$(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.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=
|
||||
appdata=appdata
|
||||
|
||||
[aime]
|
||||
; 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
|
||||
|
||||
rem Matching Server
|
||||
start /min ..\..\..\Tools\tdrserver.exe
|
||||
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 Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet
|
||||
inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
||||
REM Root directory
|
||||
set ROOT_DIR=WindowsNoEditor
|
||||
|
||||
rem Matching Server paths
|
||||
set MATCHING_SERVER_FILE_NAME=tdrserver.exe
|
||||
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 tdrserver.exe > nul 2>&1
|
||||
|
@ -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);
|
||||
|
@ -28,9 +28,6 @@ static BOOL CALLBACK swdc_di_enum_callback(
|
||||
static BOOL CALLBACK swdc_di_enum_callback_pedals(
|
||||
const DIDEVICEINSTANCEW *dev,
|
||||
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 uint8_t swdc_di_decode_pov(DWORD pov);
|
||||
static void swdc_di_get_analogs(struct swdc_io_analog_state *out);
|
||||
|
@ -2,7 +2,6 @@ LIBRARY swdcio
|
||||
|
||||
EXPORTS
|
||||
swdc_io_init
|
||||
swdc_io_poll
|
||||
swdc_io_get_opbtns
|
||||
swdc_io_get_gamebtns
|
||||
swdc_io_get_analogs
|
||||
|
@ -55,7 +55,7 @@ struct swdc_io_analog_state {
|
||||
uint16_t swdc_io_get_api_version(void);
|
||||
|
||||
/* 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.
|
||||
|
||||
@ -63,15 +63,8 @@ uint16_t swdc_io_get_api_version(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
|
||||
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.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
@ -79,7 +72,7 @@ HRESULT swdc_io_poll(void);
|
||||
void swdc_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
|
||||
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
|
||||
mappings are the same in both cases.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user