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",
|
"platform.h": "c",
|
||||||
"stdbool.h": "c",
|
"stdbool.h": "c",
|
||||||
"dprintf.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)echo ... $@
|
||||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/chuni
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/siva
|
||||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/chuni/DEVICE
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/siva/DEVICE
|
||||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_32)/chunihook/chunihook.dll \
|
$(BUILD_DIR_32)/sivahook/sivahook.dll \
|
||||||
$(DIST_DIR)/chuni/taitools.ini \
|
$(BUILD_DIR_ZIP)/siva
|
||||||
$(DIST_DIR)/chuni/start.bat \
|
$(V)mv $(BUILD_DIR_ZIP)/siva/inject.exe \
|
||||||
$(BUILD_DIR_ZIP)/chuni
|
$(BUILD_DIR_ZIP)/siva/inject_32.exe
|
||||||
$(V)cp pki/billing.pub \
|
$(V)mv $(BUILD_DIR_ZIP)/siva/sivahook.dll \
|
||||||
pki/ca.crt \
|
$(BUILD_DIR_ZIP)/siva/sivahook_32.dll
|
||||||
$(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
|
|
||||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
$(BUILD_DIR_64)/divahook/divahook.dll \
|
$(BUILD_DIR_64)/sivahook/sivahook.dll \
|
||||||
$(DIST_DIR)/diva/taitools.ini \
|
$(DIST_DIR)/siva/taitools.ini \
|
||||||
$(DIST_DIR)/diva/start.bat \
|
$(DIST_DIR)/siva/start.bat \
|
||||||
$(BUILD_DIR_ZIP)/diva
|
$(BUILD_DIR_ZIP)/siva
|
||||||
$(V)cp pki/billing.pub \
|
$(V)cp pki/billing.pub \
|
||||||
pki/ca.crt \
|
pki/ca.crt \
|
||||||
$(BUILD_DIR_ZIP)/diva/DEVICE
|
$(BUILD_DIR_ZIP)/siva/DEVICE
|
||||||
$(V)strip $(BUILD_DIR_ZIP)/diva/*.{exe,dll}
|
$(V)strip $(BUILD_DIR_ZIP)/siva/*.{exe,dll}
|
||||||
$(V)cd $(BUILD_DIR_ZIP)/diva ; zip -r ../diva.zip *
|
$(V)cd $(BUILD_DIR_ZIP)/siva ; zip -r ../siva.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)/doc.zip: \
|
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||||
$(DOC_DIR)/config \
|
$(DOC_DIR)/config \
|
||||||
$(DOC_DIR)/chunihook.md \
|
|
||||||
$(DOC_DIR)/idzhook.md \
|
|
||||||
| $(zipdir)/
|
| $(zipdir)/
|
||||||
$(V)echo ... $@
|
$(V)echo ... $@
|
||||||
$(V)zip -r $@ $^
|
$(V)zip -r $@ $^
|
||||||
|
|
||||||
$(BUILD_DIR_ZIP)/taitools.zip: \
|
$(BUILD_DIR_ZIP)/taitools.zip: \
|
||||||
$(BUILD_DIR_ZIP)/chuni.zip \
|
$(BUILD_DIR_ZIP)/siva.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 \
|
|
||||||
CHANGELOG.md \
|
CHANGELOG.md \
|
||||||
README.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 <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "board/aime-dll.h"
|
|
||||||
#include "board/config.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)
|
void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,5 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "board/io4.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);
|
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
|
||||||
|
@ -10,8 +10,6 @@ board_lib = static_library(
|
|||||||
iccard_lib,
|
iccard_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
'aime-dll.c',
|
|
||||||
'aime-dll.h',
|
|
||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
'guid.c',
|
'guid.c',
|
||||||
@ -30,7 +28,5 @@ board_lib = static_library(
|
|||||||
'sg-nfc.c',
|
'sg-nfc.c',
|
||||||
'sg-nfc.h',
|
'sg-nfc.h',
|
||||||
'sg-nfc-cmd.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 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 */
|
/* Link pointers */
|
||||||
|
|
||||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||||
@ -185,6 +196,17 @@ static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
|
|||||||
|
|
||||||
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR 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 */
|
/* Hook table */
|
||||||
|
|
||||||
static const struct hook_symbol path_hook_syms[] = {
|
static const struct hook_symbol path_hook_syms[] = {
|
||||||
@ -260,7 +282,15 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||||||
.name = "PathFileExistsW",
|
.name = "PathFileExistsW",
|
||||||
.patch = hook_PathFileExistsW,
|
.patch = hook_PathFileExistsW,
|
||||||
.link = (void **) &next_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;
|
static bool path_hook_initted;
|
||||||
@ -906,3 +936,46 @@ static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
|
|||||||
|
|
||||||
return ok;
|
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[14] = 'T';
|
||||||
mifare->sectors[0].blocks[0].bytes[15] = 'U';
|
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, (uint8_t *)"T053", 4);
|
||||||
memcpy_s(mifare->sectors[0].blocks[1].bytes[4], 12, card_sn, 12);
|
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[2].bytes, 16, card_sn + 12, 4);
|
||||||
|
|
||||||
return S_OK;
|
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(
|
shared_library(
|
||||||
'mercuryhook',
|
'll3hook',
|
||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'mercuryhook.def',
|
vs_module_defs : 'll3hook.def',
|
||||||
c_pch : '../precompiled.h',
|
c_pch : '../precompiled.h',
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
aimeio_lib,
|
|
||||||
gfxhook_lib,
|
gfxhook_lib,
|
||||||
board_lib,
|
board_lib,
|
||||||
hooklib_lib,
|
hooklib_lib,
|
||||||
mercuryio_lib,
|
ll3io_lib,
|
||||||
platform_lib,
|
platform_lib,
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
@ -22,13 +21,7 @@ shared_library(
|
|||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
'dllmain.c',
|
'dllmain.c',
|
||||||
'io4.c',
|
'll3-dll.c',
|
||||||
'io4.h',
|
'll3-dll.h',
|
||||||
'mercury-dll.c',
|
|
||||||
'mercury-dll.h',
|
|
||||||
'elisabeth.h',
|
|
||||||
'elisabeth.c',
|
|
||||||
'touch.h',
|
|
||||||
'touch.c'
|
|
||||||
],
|
],
|
||||||
)
|
)
|
@ -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('gfxhook')
|
||||||
|
|
||||||
subdir('mu3io')
|
subdir('sivaio')
|
||||||
subdir('mercuryio')
|
|
||||||
|
|
||||||
subdir('minihook')
|
subdir('minihook')
|
||||||
subdir('mu3hook')
|
subdir('sivahook')
|
||||||
subdir('mercuryhook')
|
|
||||||
|
@ -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(
|
HRESULT platform_hook_init(
|
||||||
const struct platform_config *cfg,
|
const struct platform_config *cfg,
|
||||||
const char *game_id,
|
const uint32_t game_id,
|
||||||
const char *platform_id,
|
|
||||||
HMODULE redir_mod);
|
HMODULE redir_mod);
|
||||||
|
@ -71,6 +71,8 @@ HRESULT syscfg_hook_init(const struct syscfg_config *cfg, const uint32_t gid)
|
|||||||
L"SOFTWARE\\taito\\typex",
|
L"SOFTWARE\\taito\\typex",
|
||||||
fake_com_keys,
|
fake_com_keys,
|
||||||
_countof(fake_com_keys));
|
_countof(fake_com_keys));
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT syscfg_game_kind(void *bytes, uint32_t *nbytes)
|
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)
|
HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||||
{
|
{
|
||||||
wchar_t temp[MAX_PATH];
|
|
||||||
size_t nthome_len;
|
size_t nthome_len;
|
||||||
DWORD home_ok;
|
DWORD home_ok;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@ -52,14 +51,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config)
|
|||||||
(int) hr);
|
(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 */
|
/* Not auto-creating option directory as it is normally a read-only mount */
|
||||||
|
|
||||||
hr = path_hook_push(vfs_path_hook);
|
hr = path_hook_push(vfs_path_hook);
|
||||||
|
@ -1,26 +1,19 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "board/config.h"
|
#include "sivahook/config.h"
|
||||||
|
|
||||||
#include "gfxhook/config.h"
|
|
||||||
|
|
||||||
#include "hooklib/config.h"
|
|
||||||
#include "hooklib/dvd.h"
|
|
||||||
|
|
||||||
#include "mu3hook/config.h"
|
|
||||||
|
|
||||||
#include "platform/config.h"
|
#include "platform/config.h"
|
||||||
|
|
||||||
void mu3_dll_config_load(
|
void siva_dll_config_load(
|
||||||
struct mu3_dll_config *cfg,
|
struct siva_dll_config *cfg,
|
||||||
const wchar_t *filename)
|
const wchar_t *filename)
|
||||||
{
|
{
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(filename != NULL);
|
assert(filename != NULL);
|
||||||
|
|
||||||
GetPrivateProfileStringW(
|
GetPrivateProfileStringW(
|
||||||
L"mu3io",
|
L"sivaio",
|
||||||
L"path",
|
L"path",
|
||||||
L"",
|
L"",
|
||||||
cfg->path,
|
cfg->path,
|
||||||
@ -28,17 +21,14 @@ void mu3_dll_config_load(
|
|||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mu3_hook_config_load(
|
void siva_hook_config_load(
|
||||||
struct mu3_hook_config *cfg,
|
struct siva_hook_config *cfg,
|
||||||
const wchar_t *filename)
|
const wchar_t *filename)
|
||||||
{
|
{
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(filename != NULL);
|
assert(filename != NULL);
|
||||||
|
|
||||||
platform_config_load(&cfg->platform, filename);
|
platform_config_load(&cfg->platform, filename);
|
||||||
aime_config_load(&cfg->aime, filename);
|
siva_dll_config_load(&cfg->dll, filename);
|
||||||
dvd_config_load(&cfg->dvd, filename);
|
|
||||||
io4_config_load(&cfg->io4, filename);
|
|
||||||
gfx_config_load(&cfg->gfx, 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(
|
shared_library(
|
||||||
'mu3hook',
|
'sivahook',
|
||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'mu3hook.def',
|
vs_module_defs : 'sivahook.def',
|
||||||
c_pch : '../precompiled.h',
|
c_pch : '../precompiled.h',
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
xinput_lib,
|
|
||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
aimeio_lib,
|
|
||||||
board_lib,
|
|
||||||
gfxhook_lib,
|
gfxhook_lib,
|
||||||
|
board_lib,
|
||||||
hooklib_lib,
|
hooklib_lib,
|
||||||
mu3io_lib,
|
sivaio_lib,
|
||||||
platform_lib,
|
platform_lib,
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
@ -23,11 +21,9 @@ shared_library(
|
|||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
'dllmain.c',
|
'dllmain.c',
|
||||||
'io4.c',
|
'siva-dll.c',
|
||||||
'io4.h',
|
'siva-dll.h',
|
||||||
'mu3-dll.c',
|
|
||||||
'mu3-dll.h',
|
|
||||||
'unity.h',
|
|
||||||
'unity.c',
|
'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 <windows.h>
|
||||||
|
|
||||||
#include "hook/table.h"
|
#include "hook/table.h"
|
||||||
|
#include "hook/iohook.h"
|
||||||
|
|
||||||
#include "hooklib/dll.h"
|
#include "hooklib/dll.h"
|
||||||
#include "hooklib/path.h"
|
#include "hooklib/path.h"
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
#include "hooklib/reg.h"
|
||||||
|
#include "hook/procaddr.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
@ -25,8 +29,15 @@ static const struct hook_symbol unity_kernel32_syms[] = {
|
|||||||
static const wchar_t *target_modules[] = {
|
static const wchar_t *target_modules[] = {
|
||||||
L"mono.dll",
|
L"mono.dll",
|
||||||
L"cri_ware_unity.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 target_modules_len = _countof(target_modules);
|
||||||
|
static const size_t dep_hooks_len = _countof(dep_hooks);
|
||||||
|
|
||||||
void unity_hook_init(void)
|
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 *name_end;
|
||||||
const wchar_t *target_module;
|
const wchar_t *target_module;
|
||||||
|
const wchar_t *target_dep;
|
||||||
bool already_loaded;
|
bool already_loaded;
|
||||||
HMODULE result;
|
HMODULE result;
|
||||||
|
HMODULE dep_mod;
|
||||||
size_t name_len;
|
size_t name_len;
|
||||||
size_t target_module_len;
|
size_t target_module_len;
|
||||||
|
size_t dep_len;
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
@ -88,6 +102,20 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
|||||||
|
|
||||||
dll_hook_insert_hooks(result);
|
dll_hook_insert_hooks(result);
|
||||||
path_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(
|
sivaio_lib = static_library(
|
||||||
'mu3io',
|
'sivaio',
|
||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
@ -8,7 +8,9 @@ mu3io_lib = static_library(
|
|||||||
xinput_lib,
|
xinput_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
'mu3io.c',
|
'sivaio.c',
|
||||||
'mu3io.h',
|
'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