create theatrhythm dll
This commit is contained in:
parent
ae23b1f174
commit
0263157f1a
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -10,6 +10,9 @@
|
||||
"platform.h": "c",
|
||||
"stdbool.h": "c",
|
||||
"dprintf.h": "c",
|
||||
"slider-frame.h": "c"
|
||||
"slider-frame.h": "c",
|
||||
"aime-dll.h": "c",
|
||||
"sg-reader.h": "c",
|
||||
"reg.h": "c"
|
||||
}
|
||||
}
|
143
Package.mk
143
Package.mk
@ -1,142 +1,33 @@
|
||||
$(BUILD_DIR_ZIP)/chuni.zip:
|
||||
$(BUILD_DIR_ZIP)/siva.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/chuni
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/chuni/DEVICE
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/siva
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/siva/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_32)/chunihook/chunihook.dll \
|
||||
$(DIST_DIR)/chuni/taitools.ini \
|
||||
$(DIST_DIR)/chuni/start.bat \
|
||||
$(BUILD_DIR_ZIP)/chuni
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/chuni/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/chuni/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/chuni ; zip -r ../chuni.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/cxb.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/cxb
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/cxb/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_32)/cxbhook/cxbhook.dll \
|
||||
$(DIST_DIR)/cxb/taitools.ini \
|
||||
$(DIST_DIR)/cxb/start.bat \
|
||||
$(BUILD_DIR_ZIP)/cxb
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/cxb/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/cxb/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/cxb ; zip -r ../cxb.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/diva.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/diva
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/diva/DEVICE
|
||||
$(BUILD_DIR_32)/sivahook/sivahook.dll \
|
||||
$(BUILD_DIR_ZIP)/siva
|
||||
$(V)mv $(BUILD_DIR_ZIP)/siva/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/siva/inject_32.exe
|
||||
$(V)mv $(BUILD_DIR_ZIP)/siva/sivahook.dll \
|
||||
$(BUILD_DIR_ZIP)/siva/sivahook_32.dll
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/divahook/divahook.dll \
|
||||
$(DIST_DIR)/diva/taitools.ini \
|
||||
$(DIST_DIR)/diva/start.bat \
|
||||
$(BUILD_DIR_ZIP)/diva
|
||||
$(BUILD_DIR_64)/sivahook/sivahook.dll \
|
||||
$(DIST_DIR)/siva/taitools.ini \
|
||||
$(DIST_DIR)/siva/start.bat \
|
||||
$(BUILD_DIR_ZIP)/siva
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/diva/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/diva/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/diva ; zip -r ../diva.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/carol.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/carol
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/carol/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_32)/carolhook/carolhook.dll \
|
||||
$(DIST_DIR)/carol/taitools.ini \
|
||||
$(DIST_DIR)/carol/start.bat \
|
||||
$(BUILD_DIR_ZIP)/carol
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/carol/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/carol/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/carol ; zip -r ../carol.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/idz.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/idz
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/idz/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/idzhook/idzhook.dll \
|
||||
$(DIST_DIR)/idz/taitools.ini \
|
||||
$(DIST_DIR)/idz/start.bat \
|
||||
$(BUILD_DIR_ZIP)/idz
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/idz/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/idz/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/idz ; zip -r ../idz.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/mercury.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mercury
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mercury/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/mercuryhook/mercuryhook.dll \
|
||||
$(DIST_DIR)/mercury/taitools.ini \
|
||||
$(DIST_DIR)/mercury/start.bat \
|
||||
$(BUILD_DIR_ZIP)/mercury
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/mercury/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/mercury/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/mercury ; zip -r ../mercury.zip *
|
||||
|
||||
|
||||
$(BUILD_DIR_ZIP)/mu3.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mu3
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/mu3hook/mu3hook.dll \
|
||||
$(DIST_DIR)/mu3/taitools.ini \
|
||||
$(DIST_DIR)/mu3/start.bat \
|
||||
$(BUILD_DIR_ZIP)/mu3
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/mu3/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/mai2.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
|
||||
$(DIST_DIR)/mai2/taitools.ini \
|
||||
$(DIST_DIR)/mai2/start.bat \
|
||||
$(BUILD_DIR_ZIP)/mai2
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/mai2/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/mai2 ; zip -r ../mai2.zip *
|
||||
$(BUILD_DIR_ZIP)/siva/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/siva/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/siva ; zip -r ../siva.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||
$(DOC_DIR)/config \
|
||||
$(DOC_DIR)/chunihook.md \
|
||||
$(DOC_DIR)/idzhook.md \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -r $@ $^
|
||||
|
||||
$(BUILD_DIR_ZIP)/taitools.zip: \
|
||||
$(BUILD_DIR_ZIP)/chuni.zip \
|
||||
$(BUILD_DIR_ZIP)/cxb.zip \
|
||||
$(BUILD_DIR_ZIP)/carol.zip \
|
||||
$(BUILD_DIR_ZIP)/diva.zip \
|
||||
$(BUILD_DIR_ZIP)/doc.zip \
|
||||
$(BUILD_DIR_ZIP)/idz.zip \
|
||||
$(BUILD_DIR_ZIP)/mercury.zip \
|
||||
$(BUILD_DIR_ZIP)/mu3.zip \
|
||||
$(BUILD_DIR_ZIP)/mai2.zip \
|
||||
$(BUILD_DIR_ZIP)/siva.zip \
|
||||
CHANGELOG.md \
|
||||
README.md \
|
||||
|
||||
|
112
board/aime-dll.c
112
board/aime-dll.c
@ -1,112 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym aime_dll_syms[] = {
|
||||
{
|
||||
.sym = "aime_io_init",
|
||||
.off = offsetof(struct aime_dll, init),
|
||||
}, {
|
||||
.sym = "aime_io_nfc_poll",
|
||||
.off = offsetof(struct aime_dll, nfc_poll),
|
||||
}, {
|
||||
.sym = "aime_io_nfc_get_aime_id",
|
||||
.off = offsetof(struct aime_dll, nfc_get_aime_id),
|
||||
}, {
|
||||
.sym = "aime_io_nfc_get_felica_id",
|
||||
.off = offsetof(struct aime_dll, nfc_get_felica_id),
|
||||
}, {
|
||||
.sym = "aime_io_led_set_color",
|
||||
.off = offsetof(struct aime_dll, led_set_color),
|
||||
}
|
||||
};
|
||||
|
||||
struct aime_dll aime_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
// Not much of this lends itself to being easily factored out. Also there
|
||||
// will be a lot of API-specific branching code here eventually as new API
|
||||
// versions get defined, so even though these functions all look the same
|
||||
// now this won't remain the case forever.
|
||||
|
||||
HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("NFC Assembly: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("NFC Assembly: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "aime_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
aime_dll.api_version = get_api_version();
|
||||
} else {
|
||||
aime_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose aime_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (aime_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("NFC Assembly: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Taitools.\n",
|
||||
aime_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = aime_dll_syms;
|
||||
hr = dll_bind(&aime_dll, src, &sym, _countof(aime_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("NFC Assembly: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "aimeio/aimeio.h"
|
||||
|
||||
struct aime_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*nfc_poll)(uint8_t unit_no);
|
||||
HRESULT (*nfc_get_aime_id)(
|
||||
uint8_t unit_no,
|
||||
uint8_t *luid,
|
||||
size_t luid_size);
|
||||
HRESULT (*nfc_get_felica_id)(uint8_t unit_no, uint64_t *IDm);
|
||||
void (*led_set_color)(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);
|
||||
};
|
||||
|
||||
struct aime_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct aime_dll aime_dll;
|
||||
|
||||
HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self);
|
@ -5,32 +5,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
#include "board/config.h"
|
||||
#include "board/sg-reader.h"
|
||||
|
||||
static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"aimeio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
aime_dll_config_load(&cfg->dll, filename);
|
||||
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
|
@ -4,7 +4,5 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
#include "board/sg-reader.h"
|
||||
|
||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename);
|
||||
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
|
||||
|
@ -10,8 +10,6 @@ board_lib = static_library(
|
||||
iccard_lib,
|
||||
],
|
||||
sources : [
|
||||
'aime-dll.c',
|
||||
'aime-dll.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'guid.c',
|
||||
@ -30,7 +28,5 @@ board_lib = static_library(
|
||||
'sg-nfc.c',
|
||||
'sg-nfc.h',
|
||||
'sg-nfc-cmd.h',
|
||||
'sg-reader.c',
|
||||
'sg-reader.h',
|
||||
],
|
||||
)
|
||||
|
@ -1,186 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
#include "board/sg-led.h"
|
||||
#include "board/sg-nfc.h"
|
||||
#include "board/sg-reader.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
static HRESULT sg_reader_handle_irp(struct irp *irp);
|
||||
static HRESULT sg_reader_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT sg_reader_nfc_poll(void *ctx);
|
||||
static HRESULT sg_reader_nfc_get_aime_id(
|
||||
void *ctx,
|
||||
uint8_t *luid,
|
||||
size_t luid_size);
|
||||
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm);
|
||||
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
static const struct sg_nfc_ops sg_reader_nfc_ops = {
|
||||
.poll = sg_reader_nfc_poll,
|
||||
.get_aime_id = sg_reader_nfc_get_aime_id,
|
||||
.get_felica_id = sg_reader_nfc_get_felica_id,
|
||||
};
|
||||
|
||||
static const struct sg_led_ops sg_reader_led_ops = {
|
||||
.set_color = sg_reader_led_set_color,
|
||||
};
|
||||
|
||||
static CRITICAL_SECTION sg_reader_lock;
|
||||
static bool sg_reader_started;
|
||||
static HRESULT sg_reader_start_hr;
|
||||
static struct uart sg_reader_uart;
|
||||
static uint8_t sg_reader_written_bytes[520];
|
||||
static uint8_t sg_reader_readable_bytes[520];
|
||||
static struct sg_nfc sg_reader_nfc;
|
||||
static struct sg_led sg_reader_led;
|
||||
|
||||
HRESULT sg_reader_hook_init(
|
||||
const struct aime_config *cfg,
|
||||
unsigned int port_no,
|
||||
HINSTANCE self)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
hr = aime_dll_init(&cfg->dll, self);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL);
|
||||
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL);
|
||||
|
||||
InitializeCriticalSection(&sg_reader_lock);
|
||||
|
||||
uart_init(&sg_reader_uart, port_no);
|
||||
sg_reader_uart.written.bytes = sg_reader_written_bytes;
|
||||
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);
|
||||
sg_reader_uart.readable.bytes = sg_reader_readable_bytes;
|
||||
sg_reader_uart.readable.nbytes = sizeof(sg_reader_readable_bytes);
|
||||
|
||||
return iohook_push_handler(sg_reader_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (!uart_match_irp(&sg_reader_uart, irp)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&sg_reader_lock);
|
||||
hr = sg_reader_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&sg_reader_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
#if 0
|
||||
if (irp->op == IRP_OP_WRITE) {
|
||||
dprintf("WRITE:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (irp->op == IRP_OP_READ) {
|
||||
dprintf("READ:\n");
|
||||
dump_iobuf(&sg_reader_uart.readable);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
/* Unfortunately the card reader UART gets opened and closed
|
||||
repeatedly */
|
||||
|
||||
if (!sg_reader_started) {
|
||||
dprintf("NFC Assembly: Starting backend DLL\n");
|
||||
hr = aime_dll.init();
|
||||
|
||||
sg_reader_started = true;
|
||||
sg_reader_start_hr = hr;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("NFC Assembly: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
} else {
|
||||
hr = sg_reader_start_hr;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&sg_reader_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
sg_nfc_transact(
|
||||
&sg_reader_nfc,
|
||||
&sg_reader_uart.readable,
|
||||
sg_reader_uart.written.bytes,
|
||||
sg_reader_uart.written.pos);
|
||||
|
||||
sg_led_transact(
|
||||
&sg_reader_led,
|
||||
&sg_reader_uart.readable,
|
||||
sg_reader_uart.written.bytes,
|
||||
sg_reader_uart.written.pos);
|
||||
|
||||
sg_reader_uart.written.pos = 0;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_poll(void *ctx)
|
||||
{
|
||||
return aime_dll.nfc_poll(0);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_get_aime_id(
|
||||
void *ctx,
|
||||
uint8_t *luid,
|
||||
size_t luid_size)
|
||||
{
|
||||
return aime_dll.nfc_get_aime_id(0, luid, luid_size);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm)
|
||||
{
|
||||
return aime_dll.nfc_get_felica_id(0, IDm);
|
||||
}
|
||||
|
||||
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
aime_dll.led_set_color(0, r, g, b);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
|
||||
struct aime_config {
|
||||
struct aime_dll_config dll;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
HRESULT sg_reader_hook_init(
|
||||
const struct aime_config *cfg,
|
||||
unsigned int port_no,
|
||||
HINSTANCE self);
|
48
dist/carol/segatools.ini
vendored
48
dist/carol/segatools.ini
vendored
@ -1,48 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
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=
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment.
|
||||
enable=1
|
||||
|
||||
[gpio]
|
||||
dipsw1=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.126.0
|
||||
|
||||
[gfx]
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=1
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Taitools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[io3]
|
||||
; Test button virtual-key code. Default is the 1 key.
|
||||
test=0x31
|
||||
; Service button virtual-key code. Default is the 2 key.
|
||||
service=0x32
|
||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||
coin=0x33
|
13
dist/carol/start.bat
vendored
13
dist/carol/start.bat
vendored
@ -1,13 +0,0 @@
|
||||
@echo off
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
taskkill /f /im aimeReaderHost.exe > nul 2>&1
|
||||
|
||||
start /min inject -d -k carolhook.dll aimeReaderHost.exe -p 10
|
||||
inject -d -k carolhook.dll carol_nu.exe
|
||||
taskkill /f /im aimeReaderHost.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
80
dist/chuni/segatools.ini
vendored
80
dist/chuni/segatools.ini
vendored
@ -1,80 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
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=
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; Chunithm is extremely picky about its LAN environment, so leaving this
|
||||
; setting enabled is strongly recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.139.0
|
||||
|
||||
[gfx]
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=1
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Taitools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[chuniio]
|
||||
; To use a custom Chunithm IO DLL enter its path here.
|
||||
; Leave empty if you want to use Taitools built-in keyboard input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io3]
|
||||
; Test button virtual-key code. Default is the 1 key.
|
||||
test=0x31
|
||||
; Service button virtual-key code. Default is the 2 key.
|
||||
service=0x32
|
||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||
coin=0x33
|
||||
|
||||
; Key bindings for each of the 32 touch cells. The default key map, depicted
|
||||
; in left-to-right order, is as follows:
|
||||
;
|
||||
; SSSSDDDDFFFFGGGGHHHHJJJJKKKKLLLL
|
||||
;
|
||||
; Touch cells are numbered FROM RIGHT TO LEFT! starting from 1. This is in
|
||||
; order to match the numbering used in the operator menu and service manual.
|
||||
;
|
||||
; Uncomment and complete the following sequence of settings to configure a
|
||||
; custom high-precision touch strip controller if you have one.
|
||||
[slider]
|
||||
;cell32=0x53
|
||||
;cell31=0x53
|
||||
;cell30=0x53
|
||||
; ... etc ...
|
11
dist/chuni/start.bat
vendored
11
dist/chuni/start.bat
vendored
@ -1,11 +0,0 @@
|
||||
@echo off
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start /min inject -d -k chunihook.dll aimeReaderHost.exe -p 12
|
||||
inject -d -k chunihook.dll chuniApp.exe
|
||||
taskkill /f /im aimeReaderHost.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
4
dist/cxb/resource/segatools.ini
vendored
4
dist/cxb/resource/segatools.ini
vendored
@ -1,4 +0,0 @@
|
||||
[aime]
|
||||
; CXB is stupid, so we have to make the paths go back one
|
||||
aimePath=../DEVICE/aime.txt
|
||||
felicaPath=../DEVICE/felica.txt
|
75
dist/cxb/segatools.ini
vendored
75
dist/cxb/segatools.ini
vendored
@ -1,75 +0,0 @@
|
||||
[vfs]
|
||||
; Make sure theses are full paths and not relative or you will have a bad time
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
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=
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; Crossbeats is extremely picky about its LAN environment, so leaving this
|
||||
; setting enabled is strongly recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.100.0
|
||||
billingCa=../DEVICE/ca.crt
|
||||
billingPub=../DEVICE/billing.pub
|
||||
billingType=2
|
||||
|
||||
[gfx]
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=1
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
[aime]
|
||||
; Aime reader emulation
|
||||
; CXB is stupid, so we have to make the paths go back one
|
||||
enable=1
|
||||
aimePath=../DEVICE/aime.txt
|
||||
felicaPath=../DEVICE/felica.txt
|
||||
|
||||
[eeprom]
|
||||
; See above
|
||||
path=../DEVICE/eeprom.bin
|
||||
|
||||
[sram]
|
||||
; See above
|
||||
path=../DEVICE/sram.bin
|
||||
|
||||
[led]
|
||||
; Emulation for the LED board. Currently it's just dummy responses,
|
||||
; but if somebody wants to make their keyboard or whatever light
|
||||
; up with the game they can
|
||||
enable=1
|
||||
|
||||
[revio]
|
||||
; Enable emulation of the rev IO board
|
||||
enabe=1
|
||||
; Test button virtual-key code. Default is the 1 key.
|
||||
test=0x31
|
||||
; Service button virtual-key code. Default is the 2 key.
|
||||
service=0x32
|
||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||
coin=0x33
|
||||
; Menu up key. Default is up arrow.
|
||||
up=0x26
|
||||
; Menu down key. Default is down arrow.
|
||||
down=0x28
|
||||
; Menu cancel key. Default is the 4 key.
|
||||
cancel=0x34
|
9
dist/cxb/start.bat
vendored
9
dist/cxb/start.bat
vendored
@ -1,9 +0,0 @@
|
||||
@echo off
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
inject -d -k cxbhook.dll Rev_v11.exe
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
54
dist/diva/segatools.ini
vendored
54
dist/diva/segatools.ini
vendored
@ -1,54 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
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=
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; Chunithm is extremely picky about its LAN environment, so leaving this
|
||||
; setting enabled is strongly recommended.
|
||||
enable=1
|
||||
|
||||
[gpio]
|
||||
dipsw1=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.150.0
|
||||
|
||||
[slider]
|
||||
cell1=0x51
|
||||
cell2=0x57
|
||||
cell3=0x45
|
||||
cell4=0x52
|
||||
cell5=0x55
|
||||
cell6=0x49
|
||||
cell7=0x4F
|
||||
cell8=0x50
|
||||
|
||||
[buttons]
|
||||
key1=0x27
|
||||
key2=0x28
|
||||
key3=0x25
|
||||
key4=0x26
|
||||
key5=0x20
|
||||
|
||||
; Sliders : <- QWER UIOP ->
|
||||
; Triangle : Up arrow
|
||||
; Square : Left Arrow
|
||||
; Cross : Down Arrow
|
||||
; Circle : Right arrow
|
||||
; Enter : Space
|
||||
|
9
dist/diva/start.bat
vendored
9
dist/diva/start.bat
vendored
@ -1,9 +0,0 @@
|
||||
@echo off
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
inject -d -k divahook.dll diva.exe
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
116
dist/idz/segatools.ini
vendored
116
dist/idz/segatools.ini
vendored
@ -1,116 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains OPxx directories)
|
||||
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=
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[ds]
|
||||
; Region code on the emulated AMEX board DS EEPROM.
|
||||
; 1: Japan
|
||||
; 4: Export (some UI elements in English)
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset.
|
||||
region=1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.100.0
|
||||
|
||||
[gpio]
|
||||
; Emulated Nu DIP switch for Distribution Server setting.
|
||||
;
|
||||
; If multiple machines are present on the same LAN then set this to 1 on
|
||||
; exactly one machine and set this to 0 on all others.
|
||||
dipsw1=1
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Taitools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[idzio]
|
||||
; To use a custom Initial D Zero IO DLL enter its path here.
|
||||
; Leave empty if you want to use Taitools built-in gamepad/wheel input.
|
||||
path=
|
||||
|
||||
[io3]
|
||||
; Input API selection for JVS input emulator.
|
||||
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
|
||||
mode=xinput
|
||||
; Automatically reset the simulated shifter to Neutral when XInput Start is
|
||||
; pressed (e.g. when navigating menus between races).
|
||||
autoNeutral=1
|
||||
; Use the left thumbstick for steering instead of both on XInput Controllers.
|
||||
; Not recommended as it will not give you the precision needed for this game
|
||||
singleStickSteering=0
|
||||
; Adjust scaling for steering wheel input.
|
||||
;
|
||||
; This setting scales the steering wheel input so that the maximum positive
|
||||
; and minimum negative steering inputs reported in the operator menu's input
|
||||
; test screen do not exceed the value below. The maximum possible value is 128,
|
||||
; and the value that matches the input range of a real cabinet is 97.
|
||||
;
|
||||
; NOTE: This is not the same thing as DirectInput steering wheel movement
|
||||
; range! Taitools cannot control the maximum angle of your physical steering
|
||||
; wheel controller, this setting is vendor-specific and can only be adjusted
|
||||
; in the Control Panel.
|
||||
restrict=97
|
||||
|
||||
[dinput]
|
||||
; Name of the DirectInput wheel to use (or any text that occurs in its name)
|
||||
; Example: TMX
|
||||
;
|
||||
; If this is left blank then the first DirectInput device will be used.
|
||||
deviceName=
|
||||
; Name of the positional shifter to use (or any subset thereof).
|
||||
; Leave blank if you do not have a positional shifter; a positional shifter
|
||||
; will be simulated using the configured Shift Down and Shift Up buttons
|
||||
; in this case.
|
||||
;
|
||||
; Can be the same device as the wheel.
|
||||
;
|
||||
; Example: T500
|
||||
shifterName=
|
||||
; Pedal mappings. Valid axis names are:
|
||||
;
|
||||
; X, Y, Z, RX, RY, RZ, U, V
|
||||
;
|
||||
; (U and V are old names for Slider 1 and Slider 2).
|
||||
; The examples below are valid for a Thrustmaster TMX.
|
||||
brakeAxis=RZ
|
||||
accelAxis=Y
|
||||
; DirectInput button numbers to map to menu inputs. Note that buttons are
|
||||
; numbered from 1; some software numbers buttons from 0.
|
||||
start=3
|
||||
viewChg=10
|
||||
; Button mappings for the simulated six-speed shifter.
|
||||
shiftDn=1
|
||||
shiftUp=2
|
||||
; Button mappings for the positional shifter, if present.
|
||||
gear1=1
|
||||
gear2=2
|
||||
gear3=3
|
||||
gear4=4
|
||||
gear5=5
|
||||
gear6=6
|
||||
; Invert the accelerator and or brake axis
|
||||
; (Needed when using DirectInput for the Dualshock 4 for example)
|
||||
reverseAccelAxis=0
|
||||
reverseBrakeAxis=0
|
10
dist/idz/start.bat
vendored
10
dist/idz/start.bat
vendored
@ -1,10 +0,0 @@
|
||||
@echo off
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
.\inject.exe -k .\idzhook.dll .\InitialD0_DX11_Nu.exe
|
||||
.\inject.exe -d -k .\idzhook.dll .\amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
44
dist/mai2/segatools.ini
vendored
44
dist/mai2/segatools.ini
vendored
@ -1,44 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs
|
||||
; 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
|
||||
option=option
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[ds]
|
||||
; Region code on the emulated AMEX board DS EEPROM.
|
||||
; 1: Japan
|
||||
; 4: Export (some UI elements in English)
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset.
|
||||
region=1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.172.0
|
||||
|
||||
[gfx]
|
||||
enable=1
|
||||
|
||||
[io4]
|
||||
; Delete
|
||||
test=0x2E
|
||||
; End
|
||||
service=0x23
|
||||
; Insert
|
||||
coin=0x2D
|
11
dist/mai2/start.bat
vendored
11
dist/mai2/start.bat
vendored
@ -1,11 +0,0 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
start inject -d -k mai2hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||
inject.exe -d -k mai2hook.dll Sinmai.exe -screen-fullscreen 0 -screen-width 2160 -screen-height 1920
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo Game processes have terminated
|
56
dist/mercury/segatools.ini
vendored
56
dist/mercury/segatools.ini
vendored
@ -1,56 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs
|
||||
; 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
|
||||
option=option
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[ds]
|
||||
; Region code on the emulated AMEX board DS EEPROM.
|
||||
; 1: Japan
|
||||
; 4: Export (some UI elements in English)
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset.
|
||||
region=1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.174.0
|
||||
|
||||
[gfx]
|
||||
enable=1
|
||||
|
||||
[io4]
|
||||
; Input API selection for JVS input emulator.
|
||||
test=0x2D
|
||||
service=0x2E
|
||||
coin=0x24
|
||||
volup=0x26
|
||||
voldown=0x28
|
||||
|
||||
; Hooks related to the touch boards
|
||||
[touch]
|
||||
enable=1
|
||||
|
||||
; Hooks related to the LED board (codenamed Elisabeth)
|
||||
[elisabeth]
|
||||
enable=1
|
||||
|
||||
;[mercuryio]
|
||||
; Use mercuryio.dll
|
||||
;path=mercuryio.dll
|
15
dist/mercury/start.bat
vendored
15
dist/mercury/start.bat
vendored
@ -1,15 +0,0 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
REM USA
|
||||
REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
|
||||
REM JP
|
||||
start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo Game processes have terminated
|
60
dist/mu3/segatools.ini
vendored
60
dist/mu3/segatools.ini
vendored
@ -1,60 +0,0 @@
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs
|
||||
; 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
|
||||
option=option
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[ds]
|
||||
; Region code on the emulated AMEX board DS EEPROM.
|
||||
; 1: Japan
|
||||
; 4: Export (some UI elements in English)
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset.
|
||||
region=1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.162.0
|
||||
|
||||
[gfx]
|
||||
enable=1
|
||||
|
||||
[io4]
|
||||
; Input API selection for JVS input emulator.
|
||||
; Set "1" to use a xinput gamepad and set "2" to use keyboard.
|
||||
mode=2
|
||||
|
||||
test=0x31
|
||||
service=0x32
|
||||
|
||||
[dinput]
|
||||
LEFT_A=0x53
|
||||
LEFT_B=0x44
|
||||
LEFT_C=0x46
|
||||
LEFT_MENU=0x51
|
||||
LEFT_SIDE=0x52
|
||||
RIGHT_A=0x4A
|
||||
RIGHT_B=0x4B
|
||||
RIGHT_C=0x4C
|
||||
RIGHT_MENU=0x50
|
||||
RIGHT_SIDE=0x55
|
||||
SLIDER_LEFT=0x54
|
||||
SLIDER_RIGHT=0x59
|
||||
;Change move speed of slider when use dinput
|
||||
SLIDER_SPEED=1000
|
11
dist/mu3/start.bat
vendored
11
dist/mu3/start.bat
vendored
@ -1,11 +0,0 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
start inject -d -k mu3hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||
inject -d -k mu3hook.dll mu3.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo Game processes have terminated
|
0
dist/siva/start.bat
vendored
Normal file
0
dist/siva/start.bat
vendored
Normal file
0
dist/siva/taitools.ini
vendored
Normal file
0
dist/siva/taitools.ini
vendored
Normal file
@ -101,6 +101,17 @@ static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath);
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
|
||||
|
||||
static UINT WINAPI hook_GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName);
|
||||
|
||||
static DWORD WINAPI hook_GetPrivateProfileStringW(
|
||||
LPCWSTR lpAppName,
|
||||
LPCWSTR lpKeyName,
|
||||
LPCWSTR lpDefault,
|
||||
LPWSTR lpReturnedString,
|
||||
DWORD nSize,
|
||||
LPCWSTR lpFileName
|
||||
);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||
@ -185,6 +196,17 @@ static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
|
||||
|
||||
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
|
||||
|
||||
static UINT (WINAPI *next_GetPrivateProfileIntW)(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName);
|
||||
|
||||
static DWORD (WINAPI *next_GetPrivateProfileStringW)(
|
||||
LPCWSTR lpAppName,
|
||||
LPCWSTR lpKeyName,
|
||||
LPCWSTR lpDefault,
|
||||
LPWSTR lpReturnedString,
|
||||
DWORD nSize,
|
||||
LPCWSTR lpFileName
|
||||
);
|
||||
|
||||
/* Hook table */
|
||||
|
||||
static const struct hook_symbol path_hook_syms[] = {
|
||||
@ -260,7 +282,15 @@ static const struct hook_symbol path_hook_syms[] = {
|
||||
.name = "PathFileExistsW",
|
||||
.patch = hook_PathFileExistsW,
|
||||
.link = (void **) &next_PathFileExistsW,
|
||||
}
|
||||
}, {
|
||||
.name = "GetPrivateProfileIntW",
|
||||
.patch = hook_GetPrivateProfileIntW,
|
||||
.link = (void **) &next_GetPrivateProfileIntW,
|
||||
}, {
|
||||
.name = "GetPrivateProfileStringW",
|
||||
.patch = hook_GetPrivateProfileStringW,
|
||||
.link = (void **) &next_GetPrivateProfileStringW,
|
||||
},
|
||||
};
|
||||
|
||||
static bool path_hook_initted;
|
||||
@ -906,3 +936,46 @@ static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static UINT WINAPI hook_GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName)
|
||||
{
|
||||
wchar_t *trans;
|
||||
UINT ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, trans ? trans : lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static DWORD WINAPI hook_GetPrivateProfileStringW(
|
||||
LPCWSTR lpAppName,
|
||||
LPCWSTR lpKeyName,
|
||||
LPCWSTR lpDefault,
|
||||
LPWSTR lpReturnedString,
|
||||
DWORD nSize,
|
||||
LPCWSTR lpFileName
|
||||
)
|
||||
{
|
||||
wchar_t *trans;
|
||||
DWORD ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, trans ? trans : lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
@ -36,9 +36,9 @@ HRESULT aime_card_populate(
|
||||
mifare->sectors[0].blocks[0].bytes[14] = 'T';
|
||||
mifare->sectors[0].blocks[0].bytes[15] = 'U';
|
||||
|
||||
memcpy_s(mifare->sectors[0].blocks[1].bytes, 4, 'T053', 4);
|
||||
memcpy_s(mifare->sectors[0].blocks[1].bytes[4], 12, card_sn, 12);
|
||||
memcpy_s(mifare->sectors[0].blocks[2].bytes, 16, card_sn[12], 4);
|
||||
memcpy_s(mifare->sectors[0].blocks[1].bytes, 4, (uint8_t *)"T053", 4);
|
||||
memcpy_s(mifare->sectors[0].blocks[1].bytes + 4, 12, card_sn, 12);
|
||||
memcpy_s(mifare->sectors[0].blocks[2].bytes, 16, card_sn + 12, 4);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
113
ll3hook/dllmain.c
Normal file
113
ll3hook/dllmain.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
#include "gfxhook/d3d11.h"
|
||||
|
||||
#include "ll3hook/config.h"
|
||||
#include "ll3hook/ll3-dll.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE ll3_hook_mod;
|
||||
static process_entry_t ll3_startup;
|
||||
static struct ll3_hook_config ll3_hook_cfg;
|
||||
|
||||
/* This hook is based on mu3hook, with leaked ll3hook i/o codes. */
|
||||
|
||||
static DWORD CALLBACK ll3_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin ll3_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
ll3_hook_config_load(&ll3_hook_cfg, L".\\taitools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
serial_hook_init();
|
||||
|
||||
gfx_hook_init(&ll3_hook_cfg.gfx);
|
||||
gfx_d3d11_hook_init(&ll3_hook_cfg.gfx, ll3_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&ll3_hook_cfg.platform,
|
||||
3800,
|
||||
ll3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&ll3_hook_cfg.aime, 1, ll3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = vfd_hook_init(2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = ll3_dll_init(&ll3_hook_cfg.dll, ll3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = ll3_io4_hook_init(&ll3_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start elisabeth Hooks for the LED and IO Board DLLs */
|
||||
elisabeth_hook_init(&ll3_hook_cfg.elisabeth);
|
||||
|
||||
touch_hook_init(&ll3_hook_cfg.touch);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\taitools.ini");
|
||||
|
||||
dprintf("--- End ll3_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return ll3_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ll3_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(ll3_pre_startup, &ll3_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
shared_library(
|
||||
'mercuryhook',
|
||||
'll3hook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'mercuryhook.def',
|
||||
vs_module_defs : 'll3hook.def',
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
gfxhook_lib,
|
||||
board_lib,
|
||||
hooklib_lib,
|
||||
mercuryio_lib,
|
||||
ll3io_lib,
|
||||
platform_lib,
|
||||
util_lib,
|
||||
],
|
||||
@ -22,13 +21,7 @@ shared_library(
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'io4.c',
|
||||
'io4.h',
|
||||
'mercury-dll.c',
|
||||
'mercury-dll.h',
|
||||
'elisabeth.h',
|
||||
'elisabeth.c',
|
||||
'touch.h',
|
||||
'touch.c'
|
||||
'll3-dll.c',
|
||||
'll3-dll.h',
|
||||
],
|
||||
)
|
@ -1,74 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
#include "mercuryhook/config.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
void mercury_dll_config_load(
|
||||
struct mercury_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"mercuryio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void touch_config_load(
|
||||
struct touch_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(
|
||||
L"touch",
|
||||
L"enable",
|
||||
1,
|
||||
filename);
|
||||
}
|
||||
|
||||
void elisabeth_config_load(
|
||||
struct elisabeth_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(
|
||||
L"elisabeth",
|
||||
L"enable",
|
||||
1,
|
||||
filename);
|
||||
}
|
||||
|
||||
|
||||
void mercury_hook_config_load(
|
||||
struct mercury_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
platform_config_load(&cfg->platform, filename);
|
||||
aime_config_load(&cfg->aime, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
mercury_dll_config_load(&cfg->dll, filename);
|
||||
touch_config_load(&cfg->touch, filename);
|
||||
elisabeth_config_load(&cfg->elisabeth, filename);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
#include "mercuryhook/touch.h"
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
struct mercury_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct gfx_config gfx;
|
||||
struct mercury_dll_config dll;
|
||||
struct touch_config touch;
|
||||
struct elisabeth_config elisabeth;
|
||||
};
|
||||
|
||||
void mercury_dll_config_load(
|
||||
struct mercury_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void mercury_hook_config_load(
|
||||
struct mercury_hook_config *cfg,
|
||||
const wchar_t *filename);
|
@ -1,121 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/vfd.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
#include "gfxhook/d3d11.h"
|
||||
|
||||
#include "mercuryhook/config.h"
|
||||
#include "mercuryhook/io4.h"
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
#include "mercuryhook/touch.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE mercury_hook_mod;
|
||||
static process_entry_t mercury_startup;
|
||||
static struct mercury_hook_config mercury_hook_cfg;
|
||||
|
||||
/* This hook is based on mu3hook, with leaked mercuryhook i/o codes. */
|
||||
|
||||
static DWORD CALLBACK mercury_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin mercury_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
mercury_hook_config_load(&mercury_hook_cfg, L".\\taitools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&mercury_hook_cfg.dvd, mercury_hook_mod);
|
||||
serial_hook_init();
|
||||
|
||||
gfx_hook_init(&mercury_hook_cfg.gfx);
|
||||
gfx_d3d11_hook_init(&mercury_hook_cfg.gfx, mercury_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&mercury_hook_cfg.platform,
|
||||
"SDFE",
|
||||
"ACA1",
|
||||
mercury_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&mercury_hook_cfg.aime, 1, mercury_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = vfd_hook_init(2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mercury_dll_init(&mercury_hook_cfg.dll, mercury_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mercury_io4_hook_init(&mercury_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start elisabeth Hooks for the LED and IO Board DLLs */
|
||||
elisabeth_hook_init(&mercury_hook_cfg.elisabeth);
|
||||
|
||||
touch_hook_init(&mercury_hook_cfg.touch);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\taitools.ini");
|
||||
|
||||
dprintf("--- End mercury_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return mercury_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mercury_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(mercury_pre_startup, &mercury_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
#include <initguid.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
/* Hooks targeted DLLs dynamically loaded by elisabeth. */
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
static FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name);
|
||||
static FARPROC (WINAPI *next_GetProcAddress)(HMODULE hModule, const char *name);
|
||||
static int my_USBIntLED_Init();
|
||||
static int my_USBIntLED_set();
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "GetProcAddress",
|
||||
.patch = my_GetProcAddress,
|
||||
.link = (void **) &next_GetProcAddress
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT elisabeth_hook_init(struct elisabeth_config *cfg)
|
||||
{
|
||||
if (!cfg->enable) {
|
||||
return S_OK;
|
||||
}
|
||||
dll_hook_insert_hooks(NULL);
|
||||
dprintf("Elisabeth: Init\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
}
|
||||
|
||||
FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name)
|
||||
{
|
||||
uintptr_t ordinal = (uintptr_t) name;
|
||||
|
||||
FARPROC result = next_GetProcAddress(hModule, name);
|
||||
|
||||
if (ordinal > 0xFFFF) {
|
||||
/* Import by name */
|
||||
if (strcmp(name, "USBIntLED_Init") == 0) {
|
||||
result = (FARPROC) my_USBIntLED_Init;
|
||||
}
|
||||
|
||||
if (strcmp(name, "USBIntLED_set") == 0) {
|
||||
result = (FARPROC) my_USBIntLED_set;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Intercept the call to initialize the LED board. */
|
||||
static int my_USBIntLED_Init()
|
||||
{
|
||||
dprintf("Elisabeth: my_USBIntLED_Init hit!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int my_USBIntLED_set(int data1, struct led_data data2)
|
||||
{
|
||||
assert(mercury_dll.set_leds != NULL);
|
||||
mercury_dll.set_leds(data2);
|
||||
return 1;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
struct led_data {
|
||||
DWORD unitCount;
|
||||
uint8_t rgba[480 * 4];
|
||||
};
|
||||
|
||||
struct elisabeth_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
HRESULT elisabeth_hook_init(struct elisabeth_config *cfg);
|
@ -1,91 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
bool mercury_io_coin = false;
|
||||
uint16_t mercury_io_coins = 0;
|
||||
|
||||
static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state);
|
||||
|
||||
static const struct io4_ops mercury_io4_ops = {
|
||||
.poll = mercury_io4_poll,
|
||||
};
|
||||
|
||||
HRESULT mercury_io4_hook_init(const struct io4_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(mercury_dll.init != NULL);
|
||||
|
||||
hr = io4_hook_init(cfg, &mercury_io4_ops, NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mercury_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
uint8_t opbtn;
|
||||
uint8_t gamebtn;
|
||||
HRESULT hr;
|
||||
|
||||
assert(mercury_dll.poll != NULL);
|
||||
assert(mercury_dll.get_opbtns != NULL);
|
||||
assert(mercury_dll.get_gamebtns != NULL);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
hr = mercury_dll.poll();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
opbtn = 0;
|
||||
gamebtn = 0;
|
||||
|
||||
mercury_dll.get_opbtns(&opbtn);
|
||||
mercury_dll.get_gamebtns(&gamebtn);
|
||||
|
||||
if (opbtn & MERCURY_IO_OPBTN_TEST) {
|
||||
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||
}
|
||||
|
||||
if (opbtn & MERCURY_IO_OPBTN_SERVICE) {
|
||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||
}
|
||||
|
||||
if (opbtn & MERCURY_IO_OPBTN_COIN) {
|
||||
if (!mercury_io_coin) {
|
||||
mercury_io_coin = true;
|
||||
mercury_io_coins++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mercury_io_coin = false;
|
||||
}
|
||||
|
||||
state->chutes[0] = 128 + 256 * mercury_io_coins;
|
||||
|
||||
if (gamebtn & MERCURY_IO_GAMEBTN_VOL_UP) {
|
||||
state->buttons[0] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (gamebtn & MERCURY_IO_GAMEBTN_VOL_DOWN) {
|
||||
state->buttons[0] |= 1 << 0;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
HRESULT mercury_io4_hook_init(const struct io4_config *cfg);
|
@ -1,118 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym mercury_dll_syms[] = {
|
||||
{
|
||||
.sym = "mercury_io_init",
|
||||
.off = offsetof(struct mercury_dll, init),
|
||||
}, {
|
||||
.sym = "mercury_io_poll",
|
||||
.off = offsetof(struct mercury_dll, poll),
|
||||
}, {
|
||||
.sym = "mercury_io_get_opbtns",
|
||||
.off = offsetof(struct mercury_dll, get_opbtns),
|
||||
}, {
|
||||
.sym = "mercury_io_get_gamebtns",
|
||||
.off = offsetof(struct mercury_dll, get_gamebtns),
|
||||
}, {
|
||||
.sym = "mercury_io_touch_init",
|
||||
.off = offsetof(struct mercury_dll, touch_init),
|
||||
}, {
|
||||
.sym = "mercury_io_touch_start",
|
||||
.off = offsetof(struct mercury_dll, touch_start),
|
||||
}, {
|
||||
.sym = "mercury_io_touch_set_leds",
|
||||
.off = offsetof(struct mercury_dll, set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
struct mercury_dll mercury_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
// Not much of this lends itself to being easily factored out. Also there
|
||||
// will be a lot of API-specific branching code here eventually as new API
|
||||
// versions get defined, so even though these functions all look the same
|
||||
// now this won't remain the case forever.
|
||||
|
||||
HRESULT mercury_dll_init(const struct mercury_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("Wacca IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Wacca IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "mercury_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
mercury_dll.api_version = get_api_version();
|
||||
} else {
|
||||
mercury_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose mercury_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (mercury_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Wacca IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Taitools.\n",
|
||||
mercury_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = mercury_dll_syms;
|
||||
hr = dll_bind(&mercury_dll, src, &sym, _countof(mercury_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Wacca IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mercuryio/mercuryio.h"
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
|
||||
struct mercury_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
HRESULT (*touch_init)(void);
|
||||
void (*touch_start)(mercury_io_touch_callback_t callback);
|
||||
void (*set_leds)(struct led_data data);
|
||||
};
|
||||
|
||||
struct mercury_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct mercury_dll mercury_dll;
|
||||
|
||||
HRESULT mercury_dll_init(const struct mercury_dll_config *cfg, HINSTANCE self);
|
@ -1,21 +0,0 @@
|
||||
LIBRARY mercuryhook
|
||||
|
||||
EXPORTS
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
amDllVideoClose @2
|
||||
amDllVideoGetVBiosVersion @4
|
||||
amDllVideoOpen @1
|
||||
amDllVideoSetResolution @3
|
||||
mercury_io_get_api_version
|
||||
mercury_io_get_gamebtns
|
||||
mercury_io_get_opbtns
|
||||
mercury_io_touch_init
|
||||
mercury_io_touch_start
|
||||
mercury_io_touch_set_leds
|
||||
mercury_io_init
|
||||
mercury_io_poll
|
@ -1,518 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board/slider-cmd.h"
|
||||
#include "board/slider-frame.h"
|
||||
|
||||
#include "mercuryhook/mercury-dll.h"
|
||||
#include "mercuryhook/touch.h"
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
#include "hooklib/fdshark.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
const char SYNC_BOARD_VER[6] = "190523";
|
||||
const char UNIT_BOARD_VER[6] = "190514";
|
||||
|
||||
static HRESULT touch_handle_irp(struct irp *irp);
|
||||
static HRESULT touch0_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT touch1_handle_irp_locked(struct irp *irp);
|
||||
|
||||
static HRESULT touch_req_dispatch(const struct touch_req *req);
|
||||
|
||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf, int side);
|
||||
static uint8_t calc_checksum(const void *ptr, size_t nbytes);
|
||||
|
||||
static HRESULT touch_handle_get_sync_board_ver(const struct touch_req *req);
|
||||
static HRESULT touch_handle_next_read(const struct touch_req *req);
|
||||
static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req);
|
||||
static HRESULT touch_handle_mystery1(const struct touch_req *req);
|
||||
static HRESULT touch_handle_mystery2(const struct touch_req *req);
|
||||
static HRESULT touch_handle_start_auto_scan(const struct touch_req *req);
|
||||
static void touch_res_auto_scan(const bool *state);
|
||||
|
||||
uint8_t input_frame_count_0 = 0x7b;
|
||||
uint8_t input_frame_count_1 = 0x7b;
|
||||
bool touch0_auto = false;
|
||||
bool touch1_auto = false;
|
||||
|
||||
static CRITICAL_SECTION touch0_lock;
|
||||
static struct uart touch0_uart;
|
||||
static uint8_t touch0_written_bytes[520];
|
||||
static uint8_t touch0_readable_bytes[520];
|
||||
|
||||
static CRITICAL_SECTION touch1_lock;
|
||||
static struct uart touch1_uart;
|
||||
static uint8_t touch1_written_bytes[520];
|
||||
static uint8_t touch1_readable_bytes[520];
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(mercury_dll.touch_init != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&touch0_lock);
|
||||
InitializeCriticalSection(&touch1_lock);
|
||||
dprintf("Wacca touch: Init\n");
|
||||
|
||||
uart_init(&touch0_uart, 3);
|
||||
touch0_uart.written.bytes = touch0_written_bytes;
|
||||
touch0_uart.written.nbytes = sizeof(touch0_written_bytes);
|
||||
touch0_uart.readable.bytes = touch0_readable_bytes;
|
||||
touch0_uart.readable.nbytes = sizeof(touch0_readable_bytes);
|
||||
|
||||
uart_init(&touch1_uart, 4);
|
||||
touch1_uart.written.bytes = touch1_written_bytes;
|
||||
touch1_uart.written.nbytes = sizeof(touch1_written_bytes);
|
||||
touch1_uart.readable.bytes = touch1_readable_bytes;
|
||||
touch1_uart.readable.nbytes = sizeof(touch1_readable_bytes);
|
||||
|
||||
return iohook_push_handler(touch_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (uart_match_irp(&touch0_uart, irp)) {
|
||||
EnterCriticalSection(&touch0_lock);
|
||||
hr = touch0_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&touch0_lock);
|
||||
}
|
||||
else if (uart_match_irp(&touch1_uart, irp)) {
|
||||
EnterCriticalSection(&touch1_lock);
|
||||
hr = touch1_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&touch1_lock);
|
||||
}
|
||||
else {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch0_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
struct touch_req req;
|
||||
HRESULT hr;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Wacca touch0: Starting backend\n");
|
||||
hr = mercury_dll.touch_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&touch0_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("TX0 Buffer:\n");
|
||||
dump_iobuf(&touch0_uart.written);
|
||||
#endif
|
||||
hr = touch_frame_decode(&req, &touch0_uart.written, 0);
|
||||
|
||||
if (hr != S_OK) {
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Deframe error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = touch_req_dispatch(&req);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Processing error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT touch1_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
struct touch_req req;
|
||||
HRESULT hr;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Wacca touch1: Starting backend\n");
|
||||
hr = mercury_dll.touch_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&touch1_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("TX1 Buffer:\n");
|
||||
dump_iobuf(&touch1_uart.written);
|
||||
#endif
|
||||
|
||||
hr = touch_frame_decode(&req, &touch1_uart.written, 1);
|
||||
|
||||
if (hr != S_OK) {
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Deframe error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = touch_req_dispatch(&req);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Wacca touch: Processing error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT touch_req_dispatch(const struct touch_req *req)
|
||||
{
|
||||
switch (req->cmd) {
|
||||
case CMD_GET_SYNC_BOARD_VER:
|
||||
return touch_handle_get_sync_board_ver(req);
|
||||
case CMD_NEXT_READ:
|
||||
return touch_handle_next_read(req);
|
||||
case CMD_GET_UNIT_BOARD_VER:
|
||||
return touch_handle_get_unit_board_ver(req);
|
||||
case CMD_MYSTERY1:
|
||||
return touch_handle_mystery1(req);
|
||||
case CMD_MYSTERY2:
|
||||
return touch_handle_mystery2(req);
|
||||
case CMD_START_AUTO_SCAN:
|
||||
return touch_handle_start_auto_scan(req);
|
||||
case CMD_BEGIN_WRITE:
|
||||
dprintf("Wacca touch: Begin write for side %d\n", req->side);
|
||||
return S_OK;
|
||||
case CMD_NEXT_WRITE:
|
||||
dprintf("Wacca touch: continue write for side %d\n", req->side);
|
||||
return S_OK;
|
||||
default:
|
||||
dprintf("Wacca touch: Unhandled command %02x\n", req->cmd);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_get_sync_board_ver(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_get_sync_board_ver resp;
|
||||
HRESULT hr;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Wacca Touch%d: Get sync board version\n", req->side);
|
||||
|
||||
resp.cmd = 0xa0;
|
||||
memcpy(resp.version, SYNC_BOARD_VER, sizeof(SYNC_BOARD_VER));
|
||||
resp.checksum = 0;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_next_read(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_startup resp;
|
||||
HRESULT hr;
|
||||
char *rev;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Wacca Touch%d: Read section %2hx\n", req->side, req->data[2]);
|
||||
|
||||
|
||||
switch (req->data[2]) {
|
||||
// These can be found in the config file
|
||||
case 0x30:
|
||||
rev = " 0 0 1 2 3 4 5 15 15 15 15 15 15 11 11 11";
|
||||
break;
|
||||
case 0x31:
|
||||
rev = " 11 11 11 128 103 103 115 138 127 103 105 111 126 113 95 100";
|
||||
break;
|
||||
case 0x33:
|
||||
rev = " 101 115 98 86 76 67 68 48 117 0 82 154 0 6 35 4";
|
||||
break;
|
||||
default:
|
||||
dprintf("Wacca touch: BAD READ REQUEST %2hx\n", req->data[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(resp.data, rev, 80 * sizeof(char));
|
||||
resp.checksum = 0;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_get_unit_board_ver resp;
|
||||
HRESULT hr;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Wacca Touch%d: get unit board version\n", req->side);
|
||||
|
||||
memset(resp.version, 0, sizeof(resp.version));
|
||||
memcpy(resp.version, SYNC_BOARD_VER, sizeof(SYNC_BOARD_VER));
|
||||
|
||||
for (int i = 0; i < 6; i++ )
|
||||
memcpy(&resp.version[7 + (6 * i)], UNIT_BOARD_VER, sizeof(UNIT_BOARD_VER));
|
||||
|
||||
resp.cmd = 0xa8;
|
||||
resp.checksum = 0;
|
||||
|
||||
if (req->side == 0) {
|
||||
resp.version[6] = 'R';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
dprintf("\n");
|
||||
#endif
|
||||
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
else {
|
||||
resp.version[6] = 'L';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
dprintf("\n");
|
||||
#endif
|
||||
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_mystery1(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_mystery1 resp;
|
||||
HRESULT hr;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Wacca Touch%d: Command A2\n", req->side);
|
||||
|
||||
resp.cmd = 0xa2;
|
||||
resp.data = 0x3f;
|
||||
resp.checksum = 0;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_mystery2(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_mystery2 resp;
|
||||
HRESULT hr;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Wacca Touch%d: Command 94\n", req->side);
|
||||
|
||||
resp.cmd = 0x94;
|
||||
resp.data = 0;
|
||||
resp.checksum = 0;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_start_auto_scan(const struct touch_req *req)
|
||||
{
|
||||
struct touch_resp_start_auto resp;
|
||||
HRESULT hr;
|
||||
uint8_t data1[24] = { 0 };
|
||||
// Unsure what this does. It seems to change every request on a real board,
|
||||
// but the game doesn't seem to mind that it's the same
|
||||
uint8_t data2[9] = { 0x0d, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 };
|
||||
|
||||
dprintf("Wacca Touch%d: Start Auto", req->side);
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < req->data_length; i++)
|
||||
dprintf("0x%02x ", req->data[i]);
|
||||
#endif
|
||||
dprintf("\n");
|
||||
|
||||
resp.cmd = 0x9c;
|
||||
resp.data = 0;
|
||||
resp.checksum = 0x49;
|
||||
|
||||
resp.frame.cmd= 0x81;
|
||||
memcpy(resp.frame.data1, data1, sizeof(data1));
|
||||
memcpy(resp.frame.data2, data2, sizeof(data2));
|
||||
resp.frame.checksum = 0;
|
||||
resp.frame.checksum = calc_checksum(&resp.frame, sizeof(resp.frame));
|
||||
|
||||
if (req->side == 0) {
|
||||
resp.frame.count = input_frame_count_0++;
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
touch0_auto = true;
|
||||
}
|
||||
else {
|
||||
resp.frame.count = input_frame_count_1++;
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
touch1_auto = true;
|
||||
}
|
||||
|
||||
mercury_dll.touch_start(touch_res_auto_scan);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void touch_res_auto_scan(const bool *state)
|
||||
{
|
||||
struct touch_input_frame frame0;
|
||||
struct touch_input_frame frame1;
|
||||
memset(&frame0, 0, sizeof(frame0));
|
||||
memset(&frame1, 0, sizeof(frame1));
|
||||
uint8_t dataR[24] = { 0 };
|
||||
uint8_t dataL[24] = { 0 };
|
||||
// this changes every input on a real board but
|
||||
// the game doesn't seem to care about it...
|
||||
uint8_t data2[9] = { 0x0d, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 };
|
||||
uint8_t counter = 0;
|
||||
|
||||
frame0.cmd = 0x81;
|
||||
frame0.count = input_frame_count_0++;
|
||||
input_frame_count_0 %= 0x7f;
|
||||
|
||||
frame1.cmd = 0x81;
|
||||
frame1.count = input_frame_count_1++;
|
||||
input_frame_count_1 %= 0x7f;
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
if (state[counter]) {
|
||||
dataR[i] |= (1 << j);
|
||||
}
|
||||
if (state[counter+120]) {
|
||||
dataL[i] |= (1 << j);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(frame0.data1, dataR, sizeof(dataR));
|
||||
memcpy(frame0.data2, data2, sizeof(data2));
|
||||
|
||||
memcpy(frame1.data1, dataL, sizeof(dataL));
|
||||
memcpy(frame1.data2, data2, sizeof(data2));
|
||||
|
||||
frame0.checksum = 0;
|
||||
frame0.checksum = calc_checksum(&frame0, sizeof(frame0));
|
||||
|
||||
frame1.checksum = 0;
|
||||
frame1.checksum = calc_checksum(&frame1, sizeof(frame1));
|
||||
|
||||
if (touch0_auto) {
|
||||
//dprintf("Wacca touch: Touch0 auto frame #%2hx sent\n", frame0.count);
|
||||
EnterCriticalSection(&touch0_lock);
|
||||
iobuf_write(&touch0_uart.readable, &frame0, sizeof(frame0));
|
||||
LeaveCriticalSection(&touch0_lock);
|
||||
}
|
||||
|
||||
if (touch1_auto) {
|
||||
//dprintf("Wacca touch: Touch1 auto frame #%2hx sent\n", frame0.count);
|
||||
EnterCriticalSection(&touch1_lock);
|
||||
iobuf_write(&touch1_uart.readable, &frame1, sizeof(frame1));
|
||||
LeaveCriticalSection(&touch1_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes the response into a struct that's easier to work with. */
|
||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf, int side)
|
||||
{
|
||||
dest->side = side;
|
||||
dest->cmd = iobuf->bytes[0];
|
||||
iobuf->pos--;
|
||||
dest->data_length = iobuf->pos;
|
||||
|
||||
if (dest->data_length > 0) {
|
||||
for (int i = 1; i < dest->data_length; i++) {
|
||||
dest->data[i-1] = iobuf->bytes[i];
|
||||
}
|
||||
}
|
||||
iobuf->pos -= dest->data_length;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* The last byte of every response is a checksum.
|
||||
* This checksum is calculated by bitwise XORing
|
||||
* every byte in the response, then dropping the MSB.
|
||||
* Thanks the CrazyRedMachine for figuring that out!!
|
||||
*/
|
||||
static uint8_t calc_checksum(const void *ptr, size_t nbytes)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
src = ptr;
|
||||
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
//dprintf("Wacca touch: Calculating %2hx\n", src[i]);
|
||||
checksum = checksum^(src[i]);
|
||||
}
|
||||
//dprintf("Wacca touch: Checksum is %2hx\n", checksum&0x7f);
|
||||
return checksum&0x7f;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct touch_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
enum touch_cmd {
|
||||
CMD_GET_SYNC_BOARD_VER = 0xa0,
|
||||
CMD_NEXT_READ = 0x72,
|
||||
CMD_GET_UNIT_BOARD_VER = 0xa8,
|
||||
CMD_MYSTERY1 = 0xa2,
|
||||
CMD_MYSTERY2 = 0x94,
|
||||
CMD_START_AUTO_SCAN = 0xc9,
|
||||
CMD_BEGIN_WRITE = 0x77,
|
||||
CMD_NEXT_WRITE = 0x20
|
||||
};
|
||||
|
||||
struct touch_req {
|
||||
uint8_t side; // COM3 or COM4
|
||||
uint8_t cmd; // First byte is the command byte
|
||||
uint8_t data[256]; // rest of the data goes here
|
||||
uint8_t data_length; // Size of the data including command byte
|
||||
};
|
||||
|
||||
struct touch_input_frame {
|
||||
uint8_t cmd;
|
||||
uint8_t data1[24];
|
||||
uint8_t data2[9];
|
||||
uint8_t count;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_get_sync_board_ver {
|
||||
uint8_t cmd;
|
||||
char version[6];
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_startup {
|
||||
char data[80];
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_get_unit_board_ver {
|
||||
uint8_t cmd;
|
||||
uint8_t version[43];
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_mystery1 {
|
||||
uint8_t cmd;
|
||||
uint8_t data;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_mystery2 {
|
||||
uint8_t cmd;
|
||||
uint8_t data;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct touch_resp_start_auto {
|
||||
uint8_t cmd;
|
||||
uint8_t data;
|
||||
uint8_t checksum;
|
||||
struct touch_input_frame frame;
|
||||
};
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg);
|
@ -1,44 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mercuryio/config.h"
|
||||
|
||||
static const int mercury_io_default_cells[] = {
|
||||
'1','1','1','2','2','2','3','3','3','4','4','4','5','5','5','6','6','6','7','7','7','8','8','8','9','9','9','0','0','0',
|
||||
'1','1','1','2','2','2','3','3','3','4','4','4','5','5','5','6','6','6','7','7','7','8','8','8','9','9','9','0','0','0',
|
||||
'Q','Q','Q','W','W','W','E','E','E','R','R','R','T','T','T','Y','Y','Y','U','U','U','I','I','I','O','O','O','P','P','P',
|
||||
'Q','Q','Q','W','W','W','E','E','E','R','R','R','T','T','T','Y','Y','Y','U','U','U','I','I','I','O','O','O','P','P','P',
|
||||
'A','A','A','S','S','S','D','D','D','F','F','F','G','G','G','H','H','H','J','J','J','K','K','K','L','L','L',VK_OEM_1,VK_OEM_1,VK_OEM_1,
|
||||
'A','A','A','S','S','S','D','D','D','F','F','F','G','G','G','H','H','H','J','J','J','K','K','K','L','L','L',VK_OEM_1,VK_OEM_1,VK_OEM_1,
|
||||
'Z','Z','Z','X','X','X','C','C','C','V','V','V','B','B','B','N','N','N','M','M','M',VK_OEM_COMMA,VK_OEM_COMMA,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_PERIOD,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_2,VK_OEM_2,
|
||||
'Z','Z','Z','X','X','X','C','C','C','V','V','V','B','B','B','N','N','N','M','M','M',VK_OEM_COMMA,VK_OEM_COMMA,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_PERIOD,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_2,VK_OEM_2,
|
||||
};
|
||||
|
||||
void mercury_io_config_load(
|
||||
struct mercury_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
wchar_t key[240];
|
||||
int i;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", 0x2D, filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", 0x2E, filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", 0x24, filename);
|
||||
cfg->vk_vol_up = GetPrivateProfileIntW(L"io4", L"volup", 0x26, filename);
|
||||
cfg->vk_vol_down = GetPrivateProfileIntW(L"io4", L"voldown", 0x28, filename);
|
||||
|
||||
for (i = 0 ; i < 240 ; i++) {
|
||||
swprintf_s(key, _countof(key), L"cell%i", i + 1);
|
||||
cfg->vk_cell[i] = GetPrivateProfileIntW(
|
||||
L"touch",
|
||||
key,
|
||||
mercury_io_default_cells[i],
|
||||
filename);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mercury_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
uint8_t vk_vol_up;
|
||||
uint8_t vk_vol_down;
|
||||
uint8_t vk_cell[240];
|
||||
};
|
||||
|
||||
void mercury_io_config_load(
|
||||
struct mercury_io_config *cfg,
|
||||
const wchar_t *filename);
|
@ -1,121 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "mercuryio/mercuryio.h"
|
||||
#include "mercuryio/config.h"
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
|
||||
static unsigned int __stdcall mercury_io_touch_thread_proc(void *ctx);
|
||||
|
||||
static uint8_t mercury_opbtn;
|
||||
static uint8_t mercury_gamebtn;
|
||||
static struct mercury_io_config mercury_io_cfg;
|
||||
static bool mercury_io_touch_stop_flag;
|
||||
static HANDLE mercury_io_touch_thread;
|
||||
|
||||
uint16_t mercury_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT mercury_io_init(void)
|
||||
{
|
||||
mercury_io_config_load(&mercury_io_cfg, L".\\taitools.ini");
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT mercury_io_poll(void)
|
||||
{
|
||||
mercury_opbtn = 0;
|
||||
mercury_gamebtn = 0;
|
||||
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_test)) {
|
||||
mercury_opbtn |= MERCURY_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_service)) {
|
||||
mercury_opbtn |= MERCURY_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_coin)) {
|
||||
mercury_opbtn |= MERCURY_IO_OPBTN_COIN;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_vol_up)) {
|
||||
mercury_gamebtn |= MERCURY_IO_GAMEBTN_VOL_UP;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_vol_down)) {
|
||||
mercury_gamebtn |= MERCURY_IO_GAMEBTN_VOL_DOWN;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void mercury_io_get_opbtns(uint8_t *opbtn)
|
||||
{
|
||||
if (opbtn != NULL) {
|
||||
*opbtn = mercury_opbtn;
|
||||
}
|
||||
}
|
||||
|
||||
void mercury_io_get_gamebtns(uint8_t *gamebtn)
|
||||
{
|
||||
if (gamebtn != NULL) {
|
||||
*gamebtn = mercury_gamebtn;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT mercury_io_touch_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void mercury_io_touch_start(mercury_io_touch_callback_t callback)
|
||||
{
|
||||
if (mercury_io_touch_thread != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mercury_io_touch_thread = (HANDLE) _beginthreadex(
|
||||
NULL,
|
||||
0,
|
||||
mercury_io_touch_thread_proc,
|
||||
callback,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
void mercury_io_touch_set_leds(struct led_data data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static unsigned int __stdcall mercury_io_touch_thread_proc(void *ctx)
|
||||
{
|
||||
mercury_io_touch_callback_t callback;
|
||||
bool cellPressed[240];
|
||||
size_t i;
|
||||
|
||||
callback = ctx;
|
||||
|
||||
while (!mercury_io_touch_stop_flag) {
|
||||
for (i = 0 ; i < _countof(cellPressed) ; i++) {
|
||||
if (GetAsyncKeyState(mercury_io_cfg.vk_cell[i])) {
|
||||
cellPressed[i] = true;
|
||||
} else {
|
||||
cellPressed[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
callback(cellPressed);
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
LIBRARY mercuryio
|
||||
|
||||
EXPORTS
|
||||
mercury_io_get_api_version
|
||||
mercury_io_init
|
||||
mercury_io_poll
|
||||
mercury_io_get_opbtns
|
||||
mercury_io_get_gamebtns
|
||||
mercury_io_touch_init
|
||||
mercury_io_touch_start
|
||||
mercury_io_touch_set_leds
|
@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mercuryhook/elisabeth.h"
|
||||
|
||||
enum {
|
||||
MERCURY_IO_OPBTN_TEST = 0x01,
|
||||
MERCURY_IO_OPBTN_SERVICE = 0x02,
|
||||
MERCURY_IO_OPBTN_COIN = 0x04,
|
||||
};
|
||||
|
||||
enum {
|
||||
MERCURY_IO_GAMEBTN_VOL_UP = 0x01,
|
||||
MERCURY_IO_GAMEBTN_VOL_DOWN = 0x02,
|
||||
};
|
||||
|
||||
typedef void (*mercury_io_touch_callback_t)(const bool *state);
|
||||
/* Get the version of the Wacca 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).
|
||||
|
||||
The latest API version as of this writing is 0x0100. */
|
||||
|
||||
uint16_t mercury_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after mercury_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT mercury_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 mercury_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
MERCURY_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 mercury_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
MERCURY_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 mercury_io_get_gamebtns(uint8_t *gamebtn);
|
||||
|
||||
HRESULT mercury_io_touch_init(void);
|
||||
|
||||
void mercury_io_touch_start(mercury_io_touch_callback_t callback);
|
||||
|
||||
void mercury_io_touch_set_leds(struct led_data data);
|
@ -1,13 +0,0 @@
|
||||
mercuryio_lib = static_library(
|
||||
'mercuryio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
c_pch : '../precompiled.h',
|
||||
sources : [
|
||||
'mercuryio.c',
|
||||
'mercuryio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
],
|
||||
)
|
@ -53,9 +53,7 @@ subdir('util')
|
||||
|
||||
subdir('gfxhook')
|
||||
|
||||
subdir('mu3io')
|
||||
subdir('mercuryio')
|
||||
subdir('sivaio')
|
||||
|
||||
subdir('minihook')
|
||||
subdir('mu3hook')
|
||||
subdir('mercuryhook')
|
||||
subdir('sivahook')
|
||||
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "mu3hook/mu3-dll.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
struct mu3_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct gfx_config gfx;
|
||||
struct mu3_dll_config dll;
|
||||
};
|
||||
|
||||
void mu3_dll_config_load(
|
||||
struct mu3_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void mu3_hook_config_load(
|
||||
struct mu3_hook_config *cfg,
|
||||
const wchar_t *filename);
|
@ -1,126 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/vfd.h"
|
||||
|
||||
#include "gfxhook/d3d9.h"
|
||||
#include "gfxhook/d3d11.h"
|
||||
#include "gfxhook/dxgi.h"
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "mu3hook/config.h"
|
||||
#include "mu3hook/io4.h"
|
||||
#include "mu3hook/mu3-dll.h"
|
||||
#include "mu3hook/unity.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE mu3_hook_mod;
|
||||
static process_entry_t mu3_startup;
|
||||
static struct mu3_hook_config mu3_hook_cfg;
|
||||
|
||||
static DWORD CALLBACK mu3_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin mu3_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
mu3_hook_config_load(&mu3_hook_cfg, L".\\taitools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&mu3_hook_cfg.dvd, mu3_hook_mod);
|
||||
gfx_hook_init(&mu3_hook_cfg.gfx);
|
||||
gfx_d3d9_hook_init(&mu3_hook_cfg.gfx, mu3_hook_mod);
|
||||
gfx_d3d11_hook_init(&mu3_hook_cfg.gfx, mu3_hook_mod);
|
||||
gfx_dxgi_hook_init(&mu3_hook_cfg.gfx, mu3_hook_mod);
|
||||
serial_hook_init();
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&mu3_hook_cfg.platform,
|
||||
"SDDT",
|
||||
"ACA1",
|
||||
mu3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, mu3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = vfd_hook_init(2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mu3_io4_hook_init(&mu3_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize Unity native plugin DLL hooks
|
||||
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the `mu3hook` initialization. */
|
||||
|
||||
unity_hook_init();
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\taitools.ini");
|
||||
|
||||
dprintf("--- End mu3_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return mu3_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mu3_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(mu3_pre_startup, &mu3_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
120
mu3hook/io4.c
120
mu3hook/io4.c
@ -1,120 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "mu3hook/mu3-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
|
||||
|
||||
static const struct io4_ops mu3_io4_ops = {
|
||||
.poll = mu3_io4_poll,
|
||||
};
|
||||
|
||||
HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(mu3_dll.init != NULL);
|
||||
|
||||
hr = io4_hook_init(cfg, &mu3_io4_ops, NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mu3_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
uint8_t opbtn;
|
||||
uint8_t left;
|
||||
uint8_t right;
|
||||
int16_t lever;
|
||||
HRESULT hr;
|
||||
|
||||
assert(mu3_dll.poll != NULL);
|
||||
assert(mu3_dll.get_opbtns != NULL);
|
||||
assert(mu3_dll.get_gamebtns != NULL);
|
||||
assert(mu3_dll.get_lever != NULL);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
hr = mu3_dll.poll();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
opbtn = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
lever = 0;
|
||||
|
||||
mu3_dll.get_opbtns(&opbtn);
|
||||
mu3_dll.get_gamebtns(&left, &right);
|
||||
mu3_dll.get_lever(&lever);
|
||||
|
||||
if (opbtn & MU3_IO_OPBTN_TEST) {
|
||||
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||
}
|
||||
|
||||
if (opbtn & MU3_IO_OPBTN_SERVICE) {
|
||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||
}
|
||||
|
||||
if (left & MU3_IO_GAMEBTN_1) {
|
||||
state->buttons[0] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (left & MU3_IO_GAMEBTN_2) {
|
||||
state->buttons[0] |= 1 << 5;
|
||||
}
|
||||
|
||||
if (left & MU3_IO_GAMEBTN_3) {
|
||||
state->buttons[0] |= 1 << 4;
|
||||
}
|
||||
|
||||
if (right & MU3_IO_GAMEBTN_1) {
|
||||
state->buttons[0] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (right & MU3_IO_GAMEBTN_2) {
|
||||
state->buttons[1] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (right & MU3_IO_GAMEBTN_3) {
|
||||
state->buttons[0] |= 1 << 15;
|
||||
}
|
||||
|
||||
if (left & MU3_IO_GAMEBTN_MENU) {
|
||||
state->buttons[1] |= 1 << 14;
|
||||
}
|
||||
|
||||
if (right & MU3_IO_GAMEBTN_MENU) {
|
||||
state->buttons[0] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (!(left & MU3_IO_GAMEBTN_SIDE)) {
|
||||
state->buttons[1] |= 1 << 15; /* L-Side, active-low */
|
||||
}
|
||||
|
||||
if (!(right & MU3_IO_GAMEBTN_SIDE)) {
|
||||
state->buttons[0] |= 1 << 14; /* R-Side, active-low */
|
||||
}
|
||||
|
||||
/* Lever increases right-to-left, not left-to-right.
|
||||
|
||||
Use 0x7FFF as the center point instead of 0x8000; the latter would
|
||||
overflow when the lever pos is INT16_MIN. */
|
||||
|
||||
state->adcs[0] = 0x7FFF - lever;
|
||||
|
||||
return S_OK;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
HRESULT mu3_io4_hook_init(const struct io4_config *cfg);
|
@ -1,112 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mu3hook/mu3-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym mu3_dll_syms[] = {
|
||||
{
|
||||
.sym = "mu3_io_init",
|
||||
.off = offsetof(struct mu3_dll, init),
|
||||
}, {
|
||||
.sym = "mu3_io_poll",
|
||||
.off = offsetof(struct mu3_dll, poll),
|
||||
}, {
|
||||
.sym = "mu3_io_get_opbtns",
|
||||
.off = offsetof(struct mu3_dll, get_opbtns),
|
||||
}, {
|
||||
.sym = "mu3_io_get_gamebtns",
|
||||
.off = offsetof(struct mu3_dll, get_gamebtns),
|
||||
}, {
|
||||
.sym = "mu3_io_get_lever",
|
||||
.off = offsetof(struct mu3_dll, get_lever),
|
||||
}
|
||||
};
|
||||
|
||||
struct mu3_dll mu3_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
// Not much of this lends itself to being easily factored out. Also there
|
||||
// will be a lot of API-specific branching code here eventually as new API
|
||||
// versions get defined, so even though these functions all look the same
|
||||
// now this won't remain the case forever.
|
||||
|
||||
HRESULT mu3_dll_init(const struct mu3_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("Ongeki IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Ongeki IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "mu3_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
mu3_dll.api_version = get_api_version();
|
||||
} else {
|
||||
mu3_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose mu3_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (mu3_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Ongeki IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Taitools.\n",
|
||||
mu3_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = mu3_dll_syms;
|
||||
hr = dll_bind(&mu3_dll, src, &sym, _countof(mu3_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Ongeki IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mu3io/mu3io.h"
|
||||
|
||||
struct mu3_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint8_t *left, uint8_t *right);
|
||||
void (*get_lever)(int16_t *pos);
|
||||
};
|
||||
|
||||
struct mu3_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct mu3_dll mu3_dll;
|
||||
|
||||
HRESULT mu3_dll_init(const struct mu3_dll_config *cfg, HINSTANCE self);
|
@ -1,25 +0,0 @@
|
||||
LIBRARY mu3hook
|
||||
|
||||
EXPORTS
|
||||
CreateDXGIFactory
|
||||
CreateDXGIFactory1
|
||||
CreateDXGIFactory2
|
||||
D3D11CreateDevice
|
||||
D3D11CreateDeviceAndSwapChain
|
||||
Direct3DCreate9
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
amDllVideoClose @2
|
||||
amDllVideoGetVBiosVersion @4
|
||||
amDllVideoOpen @1
|
||||
amDllVideoSetResolution @3
|
||||
mu3_io_get_api_version
|
||||
mu3_io_get_gamebtns
|
||||
mu3_io_get_lever
|
||||
mu3_io_get_opbtns
|
||||
mu3_io_init
|
||||
mu3_io_poll
|
148
mu3io/mu3io.c
148
mu3io/mu3io.c
@ -1,148 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mu3io/mu3io.h"
|
||||
|
||||
static uint8_t mu3_opbtn;
|
||||
static uint8_t mu3_left_btn;
|
||||
static uint8_t mu3_right_btn;
|
||||
static int16_t mu3_lever_pos;
|
||||
static int16_t mu3_lever_xpos;
|
||||
|
||||
uint16_t mu3_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT mu3_io_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT mu3_io_poll(void)
|
||||
{
|
||||
int lever;
|
||||
int xlever;
|
||||
XINPUT_STATE xi;
|
||||
WORD xb;
|
||||
|
||||
mu3_opbtn = 0;
|
||||
mu3_left_btn = 0;
|
||||
mu3_right_btn = 0;
|
||||
|
||||
if (GetAsyncKeyState('1') & 0x8000) {
|
||||
mu3_opbtn |= MU3_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState('2') & 0x8000) {
|
||||
mu3_opbtn |= MU3_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
xb = xi.Gamepad.wButtons;
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_DPAD_LEFT) {
|
||||
mu3_left_btn |= MU3_IO_GAMEBTN_1;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_DPAD_UP) {
|
||||
mu3_left_btn |= MU3_IO_GAMEBTN_2;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) {
|
||||
mu3_left_btn |= MU3_IO_GAMEBTN_3;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_X) {
|
||||
mu3_right_btn |= MU3_IO_GAMEBTN_1;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_Y) {
|
||||
mu3_right_btn |= MU3_IO_GAMEBTN_2;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_B) {
|
||||
mu3_right_btn |= MU3_IO_GAMEBTN_3;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_BACK) {
|
||||
mu3_left_btn |= MU3_IO_GAMEBTN_MENU;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_START) {
|
||||
mu3_right_btn |= MU3_IO_GAMEBTN_MENU;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) {
|
||||
mu3_left_btn |= MU3_IO_GAMEBTN_SIDE;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_RIGHT_SHOULDER) {
|
||||
mu3_right_btn |= MU3_IO_GAMEBTN_SIDE;
|
||||
}
|
||||
|
||||
lever = mu3_lever_pos;
|
||||
|
||||
if (abs(xi.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
|
||||
lever += xi.Gamepad.sThumbLX / 24;
|
||||
}
|
||||
|
||||
if (abs(xi.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
|
||||
lever += xi.Gamepad.sThumbRX / 24;
|
||||
}
|
||||
|
||||
if (lever < INT16_MIN) {
|
||||
lever = INT16_MIN;
|
||||
}
|
||||
|
||||
if (lever > INT16_MAX) {
|
||||
lever = INT16_MAX;
|
||||
}
|
||||
|
||||
mu3_lever_pos = lever;
|
||||
|
||||
xlever = mu3_lever_pos
|
||||
- xi.Gamepad.bLeftTrigger * 64
|
||||
+ xi.Gamepad.bRightTrigger * 64;
|
||||
|
||||
if (xlever < INT16_MIN) {
|
||||
xlever = INT16_MIN;
|
||||
}
|
||||
|
||||
if (xlever > INT16_MAX) {
|
||||
xlever = INT16_MAX;
|
||||
}
|
||||
|
||||
mu3_lever_xpos = xlever;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void mu3_io_get_opbtns(uint8_t *opbtn)
|
||||
{
|
||||
if (opbtn != NULL) {
|
||||
*opbtn = mu3_opbtn;
|
||||
}
|
||||
}
|
||||
|
||||
void mu3_io_get_gamebtns(uint8_t *left, uint8_t *right)
|
||||
{
|
||||
if (left != NULL) {
|
||||
*left = mu3_left_btn;
|
||||
}
|
||||
|
||||
if (right != NULL ){
|
||||
*right = mu3_right_btn;
|
||||
}
|
||||
}
|
||||
|
||||
void mu3_io_get_lever(int16_t *pos)
|
||||
{
|
||||
if (pos != NULL) {
|
||||
*pos = mu3_lever_xpos;
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
MU3_IO_OPBTN_TEST = 0x01,
|
||||
MU3_IO_OPBTN_SERVICE = 0x02,
|
||||
};
|
||||
|
||||
enum {
|
||||
MU3_IO_GAMEBTN_1 = 0x01,
|
||||
MU3_IO_GAMEBTN_2 = 0x02,
|
||||
MU3_IO_GAMEBTN_3 = 0x04,
|
||||
MU3_IO_GAMEBTN_SIDE = 0x08,
|
||||
MU3_IO_GAMEBTN_MENU = 0x10,
|
||||
};
|
||||
|
||||
/* Get the version of the Ongeki 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).
|
||||
|
||||
The latest API version as of this writing is 0x0100. */
|
||||
|
||||
uint16_t mu3_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.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT mu3_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 mu3_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 mu3_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 mu3_io_get_gamebtns(uint8_t *left, uint8_t *right);
|
||||
|
||||
/* Get the position of the cabinet lever as of the last poll. The center
|
||||
position should be equal to or close to zero.
|
||||
|
||||
The operator will be required to calibrate the lever's range of motion on
|
||||
first power-on, so the lever position reported through this API does not
|
||||
need to perfectly centered or cover every single position value possible,
|
||||
but it should be reasonably close in order to make things easier for the
|
||||
operator.
|
||||
|
||||
The calibration screen displays the leftmost and rightmost position signal
|
||||
returned from the cabinet's ADC encoder as a pair of raw two's complement
|
||||
hexadecimal values. On a real cabinet these leftmost and rightmost
|
||||
positions are somewhere around 0xB000 and 0x5000 respectively (remember
|
||||
that negative values i.e. left positions have a high most-significant bit),
|
||||
although these values can easily vary by +/- 0x1000 across different
|
||||
cabinets.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void mu3_io_get_lever(int16_t *pos);
|
0
pki/billing.pub
Normal file
0
pki/billing.pub
Normal file
0
pki/ca.crt
Normal file
0
pki/ca.crt
Normal file
@ -22,6 +22,5 @@ struct platform_config {
|
||||
|
||||
HRESULT platform_hook_init(
|
||||
const struct platform_config *cfg,
|
||||
const char *game_id,
|
||||
const char *platform_id,
|
||||
const uint32_t game_id,
|
||||
HMODULE redir_mod);
|
||||
|
@ -71,6 +71,8 @@ HRESULT syscfg_hook_init(const struct syscfg_config *cfg, const uint32_t gid)
|
||||
L"SOFTWARE\\taito\\typex",
|
||||
fake_com_keys,
|
||||
_countof(fake_com_keys));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT syscfg_game_kind(void *bytes, uint32_t *nbytes)
|
||||
|
@ -23,7 +23,6 @@ static struct vfs_config vfs_config;
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
{
|
||||
wchar_t temp[MAX_PATH];
|
||||
size_t nthome_len;
|
||||
DWORD home_ok;
|
||||
HRESULT hr;
|
||||
@ -52,14 +51,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
(int) hr);
|
||||
}
|
||||
|
||||
/* Need to create the temp subdirectory, not just nthome itself */
|
||||
|
||||
hr = vfs_mkdir_rec(temp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Vfs: Failed to create %S: %x\n", temp, (int) hr);
|
||||
}
|
||||
|
||||
/* Not auto-creating option directory as it is normally a read-only mount */
|
||||
|
||||
hr = path_hook_push(vfs_path_hook);
|
||||
|
@ -1,26 +1,19 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "mu3hook/config.h"
|
||||
#include "sivahook/config.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
void mu3_dll_config_load(
|
||||
struct mu3_dll_config *cfg,
|
||||
void siva_dll_config_load(
|
||||
struct siva_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"mu3io",
|
||||
L"sivaio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
@ -28,17 +21,14 @@ void mu3_dll_config_load(
|
||||
filename);
|
||||
}
|
||||
|
||||
void mu3_hook_config_load(
|
||||
struct mu3_hook_config *cfg,
|
||||
void siva_hook_config_load(
|
||||
struct siva_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
platform_config_load(&cfg->platform, filename);
|
||||
aime_config_load(&cfg->aime, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
siva_dll_config_load(&cfg->dll, filename);
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
mu3_dll_config_load(&cfg->dll, filename);
|
||||
}
|
||||
}
|
19
sivahook/config.h
Normal file
19
sivahook/config.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sivahook/siva-dll.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
#include "gfxhook/config.h"
|
||||
#include "board/config.h"
|
||||
|
||||
struct siva_hook_config {
|
||||
struct platform_config platform;
|
||||
struct siva_dll_config dll;
|
||||
struct gfx_config gfx;
|
||||
};
|
||||
|
||||
void siva_hook_config_load(
|
||||
struct siva_hook_config *cfg,
|
||||
const wchar_t *filename);
|
91
sivahook/dllmain.c
Normal file
91
sivahook/dllmain.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
#include "gfxhook/d3d11.h"
|
||||
|
||||
#include "sivahook/config.h"
|
||||
#include "sivahook/siva-dll.h"
|
||||
#include "sivahook/unity.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE siva_hook_mod;
|
||||
static process_entry_t siva_startup;
|
||||
static struct siva_hook_config siva_hook_cfg;
|
||||
|
||||
/* This hook is based on mu3hook, with leaked sivahook i/o codes. */
|
||||
|
||||
static DWORD CALLBACK siva_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin siva_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
siva_hook_config_load(&siva_hook_cfg, L".\\taitools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
serial_hook_init();
|
||||
|
||||
gfx_hook_init(&siva_hook_cfg.gfx);
|
||||
gfx_d3d11_hook_init(&siva_hook_cfg.gfx, siva_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&siva_hook_cfg.platform,
|
||||
3000,
|
||||
siva_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
hr = siva_dll_init(&siva_hook_cfg.dll, siva_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
unity_hook_init();
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\taitools.ini");
|
||||
|
||||
dprintf("--- End siva_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return siva_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
siva_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(siva_pre_startup, &siva_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
@ -1,21 +1,19 @@
|
||||
shared_library(
|
||||
'mu3hook',
|
||||
'sivahook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'mu3hook.def',
|
||||
vs_module_defs : 'sivahook.def',
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
xinput_lib,
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
board_lib,
|
||||
gfxhook_lib,
|
||||
board_lib,
|
||||
hooklib_lib,
|
||||
mu3io_lib,
|
||||
sivaio_lib,
|
||||
platform_lib,
|
||||
util_lib,
|
||||
],
|
||||
@ -23,11 +21,9 @@ shared_library(
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'io4.c',
|
||||
'io4.h',
|
||||
'mu3-dll.c',
|
||||
'mu3-dll.h',
|
||||
'unity.h',
|
||||
'siva-dll.c',
|
||||
'siva-dll.h',
|
||||
'unity.c',
|
||||
'unity.h',
|
||||
],
|
||||
)
|
100
sivahook/siva-dll.c
Normal file
100
sivahook/siva-dll.c
Normal file
@ -0,0 +1,100 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sivahook/siva-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym siva_dll_syms[] = {
|
||||
{
|
||||
.sym = "siva_io_init",
|
||||
.off = offsetof(struct siva_dll, init),
|
||||
}, {
|
||||
.sym = "siva_io_read_coin_counter",
|
||||
.off = offsetof(struct siva_dll, read_coin_counter),
|
||||
}, {
|
||||
.sym = "siva_io_get_btns",
|
||||
.off = offsetof(struct siva_dll, get_btns),
|
||||
},
|
||||
};
|
||||
|
||||
struct siva_dll siva_dll;
|
||||
|
||||
HRESULT siva_dll_init(const struct siva_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("Siva IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Siva IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "siva_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
siva_dll.api_version = get_api_version();
|
||||
} else {
|
||||
siva_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose siva_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (siva_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Siva IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
siva_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = siva_dll_syms;
|
||||
hr = dll_bind(&siva_dll, src, &sym, _countof(siva_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Siva IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
20
sivahook/siva-dll.h
Normal file
20
sivahook/siva-dll.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "sivaio/sivaio.h"
|
||||
|
||||
struct siva_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
void (*read_coin_counter)(uint16_t *coins, uint16_t *services);
|
||||
void (*get_btns)(uint8_t *btn, uint8_t *stick);
|
||||
};
|
||||
|
||||
struct siva_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct siva_dll siva_dll;
|
||||
|
||||
HRESULT siva_dll_init(const struct siva_dll_config *cfg, HINSTANCE self);
|
7
sivahook/sivahook.def
Normal file
7
sivahook/sivahook.def
Normal file
@ -0,0 +1,7 @@
|
||||
LIBRARY sivahook
|
||||
|
||||
EXPORTS
|
||||
siva_io_get_api_version
|
||||
siva_io_init
|
||||
siva_io_read_coin_counter
|
||||
siva_io_get_btns
|
@ -3,9 +3,13 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
@ -25,8 +29,15 @@ static const struct hook_symbol unity_kernel32_syms[] = {
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"mono.dll",
|
||||
L"cri_ware_unity.dll",
|
||||
L"SimpleNesys.dll",
|
||||
L"ismACIO.dll",
|
||||
L"NESiCAReader.dll",
|
||||
};
|
||||
|
||||
static const wchar_t *dep_hooks[] = {};
|
||||
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
static const size_t dep_hooks_len = _countof(dep_hooks);
|
||||
|
||||
void unity_hook_init(void)
|
||||
{
|
||||
@ -46,10 +57,13 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
||||
{
|
||||
const wchar_t *name_end;
|
||||
const wchar_t *target_module;
|
||||
const wchar_t *target_dep;
|
||||
bool already_loaded;
|
||||
HMODULE result;
|
||||
HMODULE dep_mod;
|
||||
size_t name_len;
|
||||
size_t target_module_len;
|
||||
size_t dep_len;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
@ -88,6 +102,20 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
path_hook_insert_hooks(result);
|
||||
reg_hook_insert_hooks(result);
|
||||
proc_addr_insert_hooks(result);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dep_hooks_len; i++) {
|
||||
target_dep = dep_hooks[i];
|
||||
|
||||
dep_mod = GetModuleHandleW(target_dep);
|
||||
if (dep_mod != NULL) {
|
||||
dprintf("Unity: Hook dependency %ls\n", target_dep);
|
||||
iohook_apply_hooks(dep_mod);
|
||||
serial_hook_apply_hooks(dep_mod);
|
||||
reg_hook_insert_hooks(dep_mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
sivaio/config.c
Normal file
30
sivaio/config.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sivaio/config.h"
|
||||
|
||||
void siva_io_config_load(struct siva_input_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
cfg->test = GetPrivateProfileIntW(L"jvs", L"test", VK_HOME, filename);
|
||||
cfg->service = GetPrivateProfileIntW(L"jvs", L"service", VK_DELETE, filename);
|
||||
cfg->coin = GetPrivateProfileIntW(L"jvs", L"coin", VK_INSERT, filename);
|
||||
|
||||
cfg->is_xinput = GetPrivateProfileIntW(L"deck", L"deck", 0, filename);
|
||||
cfg->xinput_player = GetPrivateProfileIntW(L"deck", L"controller_num", 0, filename);
|
||||
|
||||
cfg->btn_l = GetPrivateProfileIntW(L"deck", L"left_button", 'C', filename);
|
||||
cfg->btn_r = GetPrivateProfileIntW(L"deck", L"right_button", 'N', filename);
|
||||
|
||||
cfg->stick_l_up = GetPrivateProfileIntW(L"deck", L"left_stick_up", 'W', filename);
|
||||
cfg->stick_l_right = GetPrivateProfileIntW(L"deck", L"left_stick_right", 'D', filename);
|
||||
cfg->stick_l_down = GetPrivateProfileIntW(L"deck", L"left_stick_down", 'S', filename);
|
||||
cfg->stick_l_left = GetPrivateProfileIntW(L"deck", L"left_stick_left", 'A', filename);
|
||||
|
||||
cfg->stick_r_up = GetPrivateProfileIntW(L"deck", L"right_stick_up", 'I', filename);
|
||||
cfg->stick_r_right = GetPrivateProfileIntW(L"deck", L"right_stick_right", 'L', filename);
|
||||
cfg->stick_r_down = GetPrivateProfileIntW(L"deck", L"right_stick_down", 'K', filename);
|
||||
cfg->stick_r_left = GetPrivateProfileIntW(L"deck", L"right_stick_left", 'J', filename);
|
||||
}
|
28
sivaio/config.h
Normal file
28
sivaio/config.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct siva_input_config {
|
||||
uint8_t is_xinput;
|
||||
uint8_t xinput_player;
|
||||
|
||||
uint8_t test;
|
||||
uint8_t service;
|
||||
uint8_t coin;
|
||||
uint8_t btn_l;
|
||||
uint8_t btn_r;
|
||||
|
||||
uint8_t stick_l_up;
|
||||
uint8_t stick_l_right;
|
||||
uint8_t stick_l_down;
|
||||
uint8_t stick_l_left;
|
||||
uint8_t stick_r_up;
|
||||
uint8_t stick_r_right;
|
||||
uint8_t stick_r_down;
|
||||
uint8_t stick_r_left;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void siva_io_config_load(struct siva_input_config *cfg, const wchar_t *filename);
|
@ -1,5 +1,5 @@
|
||||
mu3io_lib = static_library(
|
||||
'mu3io',
|
||||
sivaio_lib = static_library(
|
||||
'sivaio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
@ -8,7 +8,9 @@ mu3io_lib = static_library(
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'mu3io.c',
|
||||
'mu3io.h',
|
||||
'sivaio.c',
|
||||
'sivaio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
],
|
||||
)
|
64
sivaio/sivaio.c
Normal file
64
sivaio/sivaio.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sivaio/sivaio.h"
|
||||
#include "sivaio/config.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static bool siva_io_coin = false;
|
||||
static bool siva_io_service = false;
|
||||
static uint16_t siva_coin_ct = 0;
|
||||
static uint16_t siva_service_ct = 0;
|
||||
static struct siva_input_config cfg;
|
||||
|
||||
uint16_t siva_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT siva_io_init(void)
|
||||
{
|
||||
dprintf("Siva IO: Init\n");
|
||||
siva_io_config_load(&cfg, L".\\bananatools.ini");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void siva_io_get_btns(uint8_t *btn, uint8_t *stick)
|
||||
{
|
||||
if (GetAsyncKeyState(cfg.test) & 0x8000) {
|
||||
*btn |= SIVA_BTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(cfg.service) & 0x8000) {
|
||||
*btn |= SIVA_BTN_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
void siva_io_read_coin_counter(uint16_t *coins, uint16_t *services)
|
||||
{
|
||||
if (GetAsyncKeyState(cfg.coin) & 0x8000) {
|
||||
if (!siva_io_coin) {
|
||||
siva_io_coin = true;
|
||||
siva_coin_ct++;
|
||||
}
|
||||
} else {
|
||||
siva_io_coin = false;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(cfg.service) & 0x8000) {
|
||||
if (!siva_io_service) {
|
||||
siva_io_service = true;
|
||||
siva_service_ct++;
|
||||
}
|
||||
} else {
|
||||
siva_io_service = false;
|
||||
}
|
||||
|
||||
*coins = siva_coin_ct;
|
||||
*services = siva_service_ct;
|
||||
}
|
57
sivaio/sivaio.h
Normal file
57
sivaio/sivaio.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
SIVA_BTN_TEST = 0x01,
|
||||
SIVA_BTN_SERVICE = 0x02,
|
||||
SIVA_BTN_COIN = 0x03,
|
||||
SIVA_BTN_LEFT = 0x04,
|
||||
SIVA_BTN_RIGHT = 0x05,
|
||||
};
|
||||
|
||||
enum {
|
||||
SIVA_STICK_L_UP = 0x01,
|
||||
SIVA_STICK_L_RIGHT = 0x02,
|
||||
SIVA_STICK_L_DOWN = 0x03,
|
||||
SIVA_STICK_L_LEFT = 0x04,
|
||||
SIVA_STICK_R_UP = 0x05,
|
||||
SIVA_STICK_R_RIGHT = 0x06,
|
||||
SIVA_STICK_R_DOWN = 0x07,
|
||||
SIVA_STICK_R_LEFT = 0x08,
|
||||
};
|
||||
|
||||
/* Get the version of the Theatrhythm 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).
|
||||
|
||||
The latest API version as of this writing is 0x0100. */
|
||||
|
||||
uint16_t siva_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after siva_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT siva_io_init(void);
|
||||
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
SIVA_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 siva_io_get_btns(uint8_t *btn, uint8_t *stick);
|
||||
|
||||
void siva_io_read_coin_counter(uint16_t *coins, uint16_t *services);
|
Loading…
Reference in New Issue
Block a user