forked from Dniel97/segatools
develop #1
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,3 +18,6 @@ build/
|
||||
|
||||
# External dependencies
|
||||
subprojects/capnhook
|
||||
|
||||
# For enabling debug logging on local builds
|
||||
MesonLocalOptions.mk
|
||||
|
9
Makefile
9
Makefile
@ -11,6 +11,11 @@ DOC_DIR := doc
|
||||
|
||||
DIST_DIR := dist
|
||||
|
||||
# Add "-D[option]=[value]" here as necessary
|
||||
MESON_OPTIONS :=
|
||||
# For options that shouldn't be committed
|
||||
-include MesonLocalOptions.mk
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Targets
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -19,9 +24,9 @@ include Package.mk
|
||||
|
||||
.PHONY: build # Build the project
|
||||
build:
|
||||
$(V)meson --cross cross-mingw-32.txt $(BUILD_DIR_32)
|
||||
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-32.txt $(BUILD_DIR_32)
|
||||
$(V)ninja -C $(BUILD_DIR_32)
|
||||
$(V)meson --cross cross-mingw-64.txt $(BUILD_DIR_64)
|
||||
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-64.txt $(BUILD_DIR_64)
|
||||
$(V)ninja -C $(BUILD_DIR_64)
|
||||
|
||||
.PHONY: dist # Build and create a zip distribution package
|
||||
|
17
Package.mk
17
Package.mk
@ -203,6 +203,22 @@ $(BUILD_DIR_ZIP)/cm.zip:
|
||||
$(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/tokyo.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/tokyohook/tokyohook.dll \
|
||||
$(DIST_DIR)/tokyo/config_hook.json \
|
||||
$(DIST_DIR)/tokyo/segatools.ini \
|
||||
$(DIST_DIR)/tokyo/start.bat \
|
||||
$(BUILD_DIR_ZIP)/tokyo
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/tokyo/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/tokyo/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/tokyo ; zip -r ../tokyo.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||
$(DOC_DIR)/config \
|
||||
$(DOC_DIR)/chunihook.md \
|
||||
@ -225,6 +241,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
|
||||
$(BUILD_DIR_ZIP)/mu3.zip \
|
||||
$(BUILD_DIR_ZIP)/mai2.zip \
|
||||
$(BUILD_DIR_ZIP)/cm.zip \
|
||||
$(BUILD_DIR_ZIP)/tokyo.zip \
|
||||
$(BUILD_DIR_ZIP)/fgo.zip \
|
||||
CHANGELOG.md \
|
||||
README.md \
|
||||
|
24
README.md
24
README.md
@ -1,31 +1,33 @@
|
||||
# Segatools
|
||||
|
||||
Version: `2024-03-13`
|
||||
Version: `2024-08-20`
|
||||
|
||||
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
|
||||
|
||||
## List of supported games
|
||||
|
||||
* Card Maker
|
||||
* starting from Card Maker
|
||||
* CHUNITHM
|
||||
* up to [CHUNITHM PARADISE LOST](doc/chunihook.md)
|
||||
* starting from CHUNITHM NEW!!
|
||||
* crossbeats REV.
|
||||
* up to crossbeats REV. SUNRISE
|
||||
* Fate/Grand Order
|
||||
* Fate/Grand Order Arcade
|
||||
* Hatsune Miku: Project DIVA Arcade
|
||||
* up to Future Tone
|
||||
* Initial D
|
||||
* [Initial D Arcade Stage Zero](doc/idzhook.md)
|
||||
* Initial D THE ARCADE
|
||||
* Hatsune Miku: Project DIVA Arcade
|
||||
* up to Future Tone
|
||||
* SEGA World Drivers Championship
|
||||
* SEGA World Drivers Championship 2019
|
||||
* Fate/Grand Order
|
||||
* Fate/Grand Order Arcade
|
||||
* O.N.G.E.K.I.
|
||||
* starting from O.N.G.E.K.I.
|
||||
* maimai DX
|
||||
* starting from maimai DX
|
||||
* Card Maker
|
||||
* starting from Card Maker
|
||||
* Mario & Sonic
|
||||
* Mario & Sonic at the Tokyo 2020 Olympics Arcade
|
||||
* O.N.G.E.K.I.
|
||||
* starting from O.N.G.E.K.I.
|
||||
* SEGA World Drivers Championship
|
||||
* SEGA World Drivers Championship 2019
|
||||
* WACCA
|
||||
* starting from WACCA
|
||||
|
||||
|
@ -185,14 +185,14 @@ static HRESULT jvs_ioctl_sense(struct irp *irp)
|
||||
|
||||
static HRESULT jvs_ioctl_transact(struct irp *irp)
|
||||
{
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("\nJVS Port: Outbound frame:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
#endif
|
||||
|
||||
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("JVS Port: Inbound frame:\n");
|
||||
dump_iobuf(&irp->read);
|
||||
dprintf("\n");
|
||||
|
@ -230,7 +230,7 @@ static HRESULT io3_cmd(
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
return io3_cmd_read_analogs(io3, req, resp);
|
||||
|
||||
|
||||
case JVS_CMD_READ_ROTARYS:
|
||||
return io3_cmd_read_rotarys(io3, req, resp);
|
||||
|
||||
@ -390,7 +390,7 @@ static HRESULT io3_cmd_read_switches(
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_IO3)
|
||||
dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n",
|
||||
req.num_players,
|
||||
req.bytes_per_player);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
SEGA 837-15093-XX LED Controller Board emulator
|
||||
|
||||
|
||||
Supported variants:
|
||||
|
||||
837-15093
|
||||
@ -106,7 +106,7 @@ static uint8_t led15093_host_adr = 1;
|
||||
static io_led_init_t led_init;
|
||||
static io_led_set_leds_t set_leds;
|
||||
|
||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||
io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr)
|
||||
{
|
||||
|
||||
@ -236,12 +236,12 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("LED 15093: Starting backend DLL\n");
|
||||
// int res = led_init();
|
||||
hr = led_init();
|
||||
|
||||
|
||||
/*
|
||||
if (res != 0) {
|
||||
dprintf("LED 15093: Backend error, LED board disconnected: "
|
||||
@ -267,7 +267,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_LED15093)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&boarduart->written);
|
||||
#endif
|
||||
@ -294,7 +294,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_LED15093)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
@ -717,7 +717,7 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set
|
||||
resp.status = v->status_code;
|
||||
if (req->cmd == LED_15093_CMD_SET_IMM_LED) {
|
||||
resp.cmd = LED_15093_CMD_SET_IMM_LED;
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY;
|
||||
// }
|
||||
|
@ -420,7 +420,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
|
||||
f_res.nbytes = sizeof(res->payload);
|
||||
f_res.pos = 1;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
dprintf("FELICA OUTBOUND:\n");
|
||||
dump_const_iobuf(&f_req);
|
||||
#endif
|
||||
@ -434,7 +434,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
|
||||
sg_res_init(&res->res, &req->req, f_res.pos);
|
||||
res->payload[0] = f_res.pos;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
dprintf("FELICA INBOUND:\n");
|
||||
dump_iobuf(&f_res);
|
||||
#endif
|
||||
|
@ -115,14 +115,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_WRITE) {
|
||||
dprintf("WRITE:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_READ) {
|
||||
dprintf("READ:\n");
|
||||
dump_iobuf(&sg_reader_uart.readable);
|
||||
|
@ -78,7 +78,7 @@ static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobu
|
||||
uint8_t checksum_pos = src->pos - 1;
|
||||
uint8_t calculated_checksum = 0;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
|
||||
if (src->pos < 6) {
|
||||
dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos);
|
||||
return SEC_E_BUFFER_TOO_SMALL;
|
||||
@ -137,7 +137,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||
|
||||
for (;;) {
|
||||
if (controlbd_uart.written.bytes[0] == 0xE0) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_CONTROL_BD)
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
#endif
|
||||
@ -147,12 +147,12 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = controlbd_req_dispatch(&req);
|
||||
hr = controlbd_req_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||
return hr;
|
||||
}
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_CONTROL_BD)
|
||||
dprintf("Control Board: RX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.readable);
|
||||
#endif
|
||||
@ -206,7 +206,7 @@ static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
|
||||
case CONTROLBD_CMD_FIRM_SUM:
|
||||
return controlbd_req_firmware_checksum();
|
||||
|
||||
case CONTROLBD_CMD_TIMEOUT:
|
||||
case CONTROLBD_CMD_TIMEOUT:
|
||||
dprintf("Control Board: Acknowledge Timeout\n");
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
|
||||
@ -278,7 +278,7 @@ static HRESULT controlbd_req_get_board_info(void)
|
||||
resp.rev = 0x90;
|
||||
resp.bfr_size = 0x0001;
|
||||
resp.ack = 1;
|
||||
|
||||
|
||||
strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 ");
|
||||
strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 ");
|
||||
resp.chip_no[5] = 0xFF;
|
||||
@ -317,7 +317,7 @@ static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
|
||||
resp.unk7 = 3;
|
||||
resp.unk8 = 1;
|
||||
resp.unk9 = 1;
|
||||
|
||||
|
||||
resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge
|
||||
resp.coord_x = 0x0;
|
||||
resp.coord_y = 0x0;
|
||||
|
@ -94,7 +94,7 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_LED_BD)
|
||||
dprintf("LED Board: TX Buffer:\n");
|
||||
dump_iobuf(&ledbd_uart.written);
|
||||
#endif
|
||||
@ -165,4 +165,4 @@ static HRESULT ledbd_req_unkF0(uint8_t cmd)
|
||||
iobuf_write(&ledbd_uart.readable, resp, 16);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||
if (!cfg->enable) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
InitializeCriticalSection(&touch_lock);
|
||||
|
||||
uart_init(&touch_uart, 1);
|
||||
@ -112,7 +112,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_TOUCH)
|
||||
dprintf("Touchscreen: TX Buffer:\n");
|
||||
dump_iobuf(&touch_uart.written);
|
||||
#endif
|
||||
@ -188,7 +188,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
resp.touches[0].touch_id = 1;
|
||||
tmp_x = mouse_x & 0x7FFF;
|
||||
tmp_y = mouse_y & 0x7FFF;
|
||||
|
||||
|
||||
resp.touches[0].x1 = tmp_x & 0x7F;
|
||||
resp.touches[0].x2 = (tmp_x >> 7) & 0x7F;
|
||||
resp.touches[0].y1 = tmp_y & 0x7F;
|
||||
@ -201,7 +201,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
last_x1 = resp.touches[0].x1;
|
||||
last_x2 = resp.touches[0].x2;
|
||||
last_y1 = resp.touches[0].y1;
|
||||
@ -220,7 +220,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
|
||||
iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
|
||||
LeaveCriticalSection(&touch_lock);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CAROL_TOUCH)
|
||||
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
|
||||
dump_iobuf(&touch_uart.readable);
|
||||
#endif
|
||||
|
@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CHUNI_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CHUNI_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -139,9 +139,10 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback);
|
||||
void chuni_io_slider_stop(void);
|
||||
|
||||
/* Update the RGB lighting on the slider. A pointer to an array of 32 * 3 = 96
|
||||
bytes is supplied. The illuminated areas on the touch slider are some
|
||||
combination of rectangular regions and dividing lines between these regions
|
||||
but the exact mapping of this lighting control buffer is still TBD.
|
||||
bytes is supplied, organized in BRG format.
|
||||
The first set of bytes is the right-most slider key, and from there the bytes
|
||||
alternate between the dividers and the keys until the left-most key.
|
||||
There are 31 illuminated sections in total.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
|
@ -63,6 +63,8 @@ void chuni_io_config_load(
|
||||
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
||||
|
||||
cfg->controller_led_output_openithm = GetPrivateProfileIntW(L"led", L"controllerLedOutputOpeNITHM", 0, filename);
|
||||
|
||||
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
|
@ -18,6 +18,8 @@ struct chuni_io_config {
|
||||
bool controller_led_output_pipe;
|
||||
bool controller_led_output_serial;
|
||||
|
||||
bool controller_led_output_openithm;
|
||||
|
||||
// The name of a COM port to output LED data on, in serial mode
|
||||
wchar_t led_serial_port[12];
|
||||
int32_t led_serial_baud;
|
||||
|
@ -127,7 +127,11 @@ void led_output_update(uint8_t board, const byte* rgb)
|
||||
|
||||
if (config->controller_led_output_serial)
|
||||
{
|
||||
led_serial_update(escaped_data);
|
||||
if (config->controller_led_output_openithm){
|
||||
led_serial_update_openithm(rgb);
|
||||
} else {
|
||||
led_serial_update(escaped_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ chuniio_lib = static_library(
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
c_pch : '../precompiled.h',
|
||||
|
||||
sources : [
|
||||
'chu2to3.c',
|
||||
'chu2to3.h',
|
||||
|
@ -97,3 +97,27 @@ void led_serial_update(struct _chuni_led_data_buf_t* data)
|
||||
|
||||
ReleaseMutex(serial_write_mutex);
|
||||
}
|
||||
|
||||
void led_serial_update_openithm(const byte* rgb)
|
||||
{
|
||||
if (serial_port != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char led_buffer[100];
|
||||
DWORD bytes_to_write; // No of bytes to write into the port
|
||||
DWORD bytes_written = 0; // No of bytes written to the port
|
||||
bytes_to_write = sizeof(led_buffer);
|
||||
BOOL status;
|
||||
|
||||
led_buffer[0] = 0xAA;
|
||||
led_buffer[1] = 0xAA;
|
||||
memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96);
|
||||
led_buffer[98] = 0xDD;
|
||||
led_buffer[99] = 0xDD;
|
||||
|
||||
status = WriteFile(serial_port, // Handle to the Serial port
|
||||
led_buffer, // Data to be written to the port
|
||||
bytes_to_write, // No of bytes to write
|
||||
&bytes_written, // Bytes written
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
@ -13,3 +13,4 @@
|
||||
|
||||
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud);
|
||||
void led_serial_update(struct _chuni_led_data_buf_t* data);
|
||||
void led_serial_update_openithm(const byte* rgb);
|
@ -123,7 +123,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0];
|
||||
bool *dipsw = &chusan_hook_cfg.platform.system.dipsw[0];
|
||||
bool is_cvt = dipsw[2];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_CHUSAN_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CHUSAN_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -15,3 +15,59 @@ EXPORTS
|
||||
cm_io_get_opbtns
|
||||
cm_io_init
|
||||
cm_io_poll
|
||||
CFW_init
|
||||
CFW_term
|
||||
CFW_open
|
||||
CFW_close
|
||||
CFW_listupPrinter
|
||||
CFW_listupPrinterSN
|
||||
CFW_selectPrinter
|
||||
CFW_selectPrinterSN
|
||||
CFW_getPrinterInfo
|
||||
CFW_status
|
||||
CFW_statusAll
|
||||
CFW_resetPrinter
|
||||
CFW_updateFirmware
|
||||
CFW_getFirmwareInfo
|
||||
CHCUSB_init
|
||||
CHCUSB_term
|
||||
CHCUSB_MakeThread
|
||||
CHCUSB_open
|
||||
CHCUSB_close
|
||||
CHCUSB_ReleaseThread
|
||||
CHCUSB_listupPrinter
|
||||
CHCUSB_listupPrinterSN
|
||||
CHCUSB_selectPrinter
|
||||
CHCUSB_selectPrinterSN
|
||||
CHCUSB_getPrinterInfo
|
||||
CHCUSB_imageformat
|
||||
CHCUSB_setmtf
|
||||
CHCUSB_makeGamma
|
||||
CHCUSB_setIcctableProfile
|
||||
CHCUSB_setIcctable
|
||||
CHCUSB_copies
|
||||
CHCUSB_status
|
||||
CHCUSB_statusAll
|
||||
CHCUSB_startpage
|
||||
CHCUSB_endpage
|
||||
CHCUSB_write
|
||||
CHCUSB_writeLaminate
|
||||
CHCUSB_writeHolo
|
||||
CHCUSB_setPrinterInfo
|
||||
CHCUSB_setPrinterToneCurve
|
||||
CHCUSB_getGamma
|
||||
CHCUSB_getMtf
|
||||
CHCUSB_cancelCopies
|
||||
CHCUSB_getPrinterToneCurve
|
||||
CHCUSB_blinkLED
|
||||
CHCUSB_resetPrinter
|
||||
CHCUSB_AttachThreadCount
|
||||
CHCUSB_getPrintIDStatus
|
||||
CHCUSB_setPrintStandby
|
||||
CHCUSB_testCardFeed
|
||||
CHCUSB_exitCard
|
||||
CHCUSB_getCardRfidTID
|
||||
CHCUSB_commCardRfidReader
|
||||
CHCUSB_updateCardRfidReader
|
||||
CHCUSB_getErrorLog
|
||||
CHCUSB_getErrorStatus
|
||||
|
@ -39,6 +39,7 @@ void cm_hook_config_load(
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
touch_screen_config_load(&cfg->touch, filename);
|
||||
printer_config_load(&cfg->printer, filename);
|
||||
cm_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
|
||||
#include "cmhook/cm-dll.h"
|
||||
|
||||
@ -21,6 +22,7 @@ struct cm_hook_config {
|
||||
struct vfd_config vfd;
|
||||
struct cm_dll_config dll;
|
||||
struct touch_screen_config touch;
|
||||
struct printer_config printer;
|
||||
struct unity_config unity;
|
||||
};
|
||||
|
||||
|
@ -56,6 +56,10 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod);
|
||||
serial_hook_init();
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
|
@ -36,9 +36,9 @@ HRESULT cm_io_init(void);
|
||||
HRESULT cm_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
cm_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||
CM_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 cm_io_get_opbtns(uint8_t *opbtn);
|
||||
void cm_io_get_opbtns(uint8_t *opbtn);
|
||||
|
4
dist/chuni/segatools.ini
vendored
4
dist/chuni/segatools.ini
vendored
@ -82,10 +82,12 @@ cabLedOutputSerial=0
|
||||
controllerLedOutputPipe=1
|
||||
; Output slider LED data to the serial port
|
||||
controllerLedOutputSerial=0
|
||||
; Use the OpeNITHM protocol for serial LED output
|
||||
controllerLedOutputOpeNITHM=0
|
||||
|
||||
; Serial port to send data to if using serial output. Default is COM5.
|
||||
;serialPort=COM5
|
||||
; Baud rate for serial data
|
||||
; Baud rate for serial data (set to 115200 if using OpeNITHM)
|
||||
;serialBaud=921600
|
||||
|
||||
; Data output a sequence of bytes, with JVS-like framing.
|
||||
|
12
dist/chusan/segatools.ini
vendored
12
dist/chusan/segatools.ini
vendored
@ -59,8 +59,8 @@ addrSuffix=11
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.139.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
@ -108,10 +108,12 @@ cabLedOutputSerial=0
|
||||
controllerLedOutputPipe=1
|
||||
; Output slider LED data to the serial port
|
||||
controllerLedOutputSerial=0
|
||||
; Use the OpeNITHM protocol for serial LED output
|
||||
controllerLedOutputOpeNITHM=0
|
||||
|
||||
; Serial port to send data to if using serial output. Default is COM5.
|
||||
;serialPort=COM5
|
||||
; Baud rate for serial data
|
||||
; Baud rate for serial data (set to 115200 if using OpeNITHM)
|
||||
;serialBaud=921600
|
||||
|
||||
; Data output a sequence of bytes, with JVS-like framing.
|
||||
@ -202,7 +204,3 @@ ir=0x20
|
||||
; ... etc ...
|
||||
;cell31=0x53
|
||||
;cell32=0x53
|
||||
|
||||
; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol.
|
||||
; eg. COM5
|
||||
;ledport=
|
||||
|
14
dist/cm/segatools.ini
vendored
14
dist/cm/segatools.ini
vendored
@ -50,10 +50,10 @@ enable=1
|
||||
; 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
|
||||
subnet=192.168.165.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
@ -73,6 +73,14 @@ enable=0
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
[printer]
|
||||
; Sinfonia CHC-C330 printer emulation setting.
|
||||
enable=1
|
||||
; Change the printer serial number here.
|
||||
serial_no="5A-A123"
|
||||
; Insert the path to the image output directory here.
|
||||
printerOutPath="DEVICE\print"
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
4
dist/fgo/segatools.ini
vendored
4
dist/fgo/segatools.ini
vendored
@ -72,8 +72,8 @@ addrSuffix=11
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.167.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
|
18
dist/idac/segatools.ini
vendored
18
dist/idac/segatools.ini
vendored
@ -54,8 +54,8 @@ subnet=192.168.158.0
|
||||
; 1: JPN: Japan, 4: EXP: Export (for Asian markets)
|
||||
region=4
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
@ -80,8 +80,18 @@ dipsw5=0
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15070]
|
||||
; Enable emulation of the 15070-02 controlled lights, which handle the cabinet
|
||||
; and seat LEDs.
|
||||
; Enable emulation of the 837-15070-02 controlled lights, which handle the
|
||||
; cabinet and seat LEDs.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[indrun]
|
||||
; Hooks to patch GameProject-Win64-Shipping.exe and IndRun.dll. This is needed
|
||||
; to boot version 1.60.00 and up. The hooks are not needed for version 1.50.00
|
||||
; and below.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
|
4
dist/mai2/segatools.ini
vendored
4
dist/mai2/segatools.ini
vendored
@ -56,8 +56,8 @@ addrSuffix=11
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.172.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
|
4
dist/mercury/segatools.ini
vendored
4
dist/mercury/segatools.ini
vendored
@ -56,8 +56,8 @@ addrSuffix=11
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.174.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
|
4
dist/mu3/segatools.ini
vendored
4
dist/mu3/segatools.ini
vendored
@ -52,8 +52,8 @@ enable=1
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.162.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
|
4
dist/swdc/segatools.ini
vendored
4
dist/swdc/segatools.ini
vendored
@ -56,8 +56,8 @@ addrSuffix=11
|
||||
; in order to find the MAIN cabinet.
|
||||
subnet=192.168.160.0
|
||||
|
||||
[gpio]
|
||||
; ALLS DIP switches.
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
|
9
dist/tokyo/config_hook.json
vendored
Normal file
9
dist/tokyo/config_hook.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"network" :
|
||||
{
|
||||
"property" :
|
||||
{
|
||||
"dhcp" : true
|
||||
}
|
||||
}
|
||||
}
|
199
dist/tokyo/segatools.ini
vendored
Normal file
199
dist/tokyo/segatools.ini
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[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=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[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.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; The final octet of the local host's IP address on the virtualized subnet (so,
|
||||
; if the keychip subnet is `192.168.149.0` and this value is set to `205`, then the
|
||||
; local host's virtualized LAN IP is `192.168.149.205`).
|
||||
addrSuffix=205
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[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.149.0
|
||||
|
||||
; Override the keychip's region code.
|
||||
; 1: JAPAN (ALL.Net, Japanese language, Option support enabled)
|
||||
; 4: EXPORT (Local networking only, English language, No option support)
|
||||
; 8: CHINA
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset. The language can be
|
||||
; changed in the game settings, so it's possible to run the JAPAN region
|
||||
; with English language.
|
||||
region=1
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; Enable freeplay mode. This will disable the coin slot and set the game to
|
||||
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
|
||||
; allow you to start a game in freeplay mode.
|
||||
freeplay=0
|
||||
|
||||
; For Mario & Sonic at the Tokyo 2020 Olympics Arcade, DipSw 1/2/3 must be set
|
||||
; as the following:
|
||||
; Cabinet ID 1 (Server): 1 0 0
|
||||
; Cabinet ID 2 (Client): 0 1 0
|
||||
; Cabinet ID 3 (Client): 0 0 1
|
||||
; Cabinet ID 4 (Client): 0 1 1
|
||||
dipsw1=1
|
||||
dipsw2=0
|
||||
dipsw3=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable emulation of the 15093-04 controlled lights, which handle the cabinet
|
||||
; LEDs.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hook settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[zinput]
|
||||
; Disables the built-in DirectInput support, which is used to support a
|
||||
; controller out of the box.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[tokyoio]
|
||||
; To use a custom Mario & Sonic at the Tokyo 2020 Olympics Arcade IO DLL enter
|
||||
; its path here. Leave empty if you want to use Segatools built-in keyboard/
|
||||
; gamepad 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.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; Set "xinput" to use a gamepad and "keyboard" to use a keyboard.
|
||||
mode=xinput
|
||||
|
||||
; Mario & Sonic at the Tokyo 2020 Olympics Arcade Control Panel
|
||||
;
|
||||
; |--|------------------ Main-Assy ------------------|--|
|
||||
; | | YELLOW | |
|
||||
; | | --- | |
|
||||
; | | ( O ) | |
|
||||
; |--| BLUE --- RED |--|
|
||||
; | | --- PUSH CENTER --- | |
|
||||
; | | ( O ) /---------------\ ( O ) | |
|
||||
; | | --- / \ --- | |
|
||||
; | | PUSH LEFT / \ PUSH RIGHT| |
|
||||
; |--|---------/ Floor Assy \---------|--|
|
||||
; | | |JUMP SENSE JUMP SENSE| | |
|
||||
; | | |1|---------------|-|-------------->|1| | |
|
||||
; | | | | Foot Panel | | Foot Panel | | | |
|
||||
; | | |2|<- - - - - - - |-| - - - - - - - |2| | |
|
||||
; | | | | | | | | | |
|
||||
; | | |3| -FOOT SENSE - |-| - FOOT SENSE->|3| | |
|
||||
; | | | | L | | R | | | |
|
||||
; | | |4|<- - - - - - - |-| - - - - - - - |4| | |
|
||||
; | | | | | | | | | |
|
||||
; | | |5| - - - - - - - |-| - - - - - - ->|5| | |
|
||||
; | | | | | | | | | |
|
||||
; | | |6|<--------------|-|---------------|6| | |
|
||||
; | | | | | |
|
||||
; | | | | | |
|
||||
; |--|----|-------------------------------------|----|--|
|
||||
;
|
||||
|
||||
; XInput bindings
|
||||
;
|
||||
; X Push Left Blue
|
||||
; Y Push Center Yellow
|
||||
; B Push Right Red
|
||||
; D-Pad Left Push Left Blue
|
||||
; D-Pad Right Push Right Red
|
||||
; Left Trigger Foot Sense L/Jump Sense
|
||||
; Right Trigger Foot Sense R/Jump Sense
|
||||
|
||||
[keyboard]
|
||||
; Keyboard bindings
|
||||
|
||||
; Keyoard: Push button settings
|
||||
|
||||
; PUSH LEFT (BLUE) button virtual-key code. Default is the A key.
|
||||
leftBlue=0x41
|
||||
; PUSH CENTER (YELLOW) button virtual-key code. Default is the S key.
|
||||
centerYellow=0x53
|
||||
; PUSH RIGHT (RED) button virtual-key code. Default is the D key.
|
||||
rightRed=0x44
|
||||
|
||||
; Keyboard: Sensor settings
|
||||
; FOOT SENSE L (LEFT) button virtual-key code. Default is the Left Arrow key.
|
||||
footLeft=0x25
|
||||
; FOOT SENSE R (RIGHT) button virtual-key code. Default is the Right Arrow key.
|
||||
footRight=0x27
|
||||
|
||||
; Keyboard: Jump sensor settings
|
||||
; All jump sensors will also trigger the FOOT SENSE L and FOOT SENSE R buttons.
|
||||
; JUMP SENSOR 1 button virtual-key code. Default is the Z key.
|
||||
jump1=0x5A
|
||||
; JUMP SENSOR 2 button virtual-key code. Default is the X key.
|
||||
jump2=0x58
|
||||
; JUMP SENSOR 3 button virtual-key code. Default is the C key.
|
||||
jump3=0x43
|
||||
; JUMP SENSOR 4 button virtual-key code. Default is the B key.
|
||||
jump4=0x42
|
||||
; JUMP SENSOR 5 button virtual-key code. Default is the N key.
|
||||
jump5=0x4E
|
||||
; JUMP SENSOR 6 button virtual-key code. Default is the M key.
|
||||
jump6=0x4D
|
||||
|
||||
; Virtual-key code for all jump sensors. Default is the Space key.
|
||||
jumpAll=0x20
|
57
dist/tokyo/start.bat
vendored
Normal file
57
dist/tokyo/start.bat
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
set DAEMON_WAIT_SECONDS=5
|
||||
|
||||
set AMDAEMON_CFG=config_common.json ^
|
||||
config_ch.json ^
|
||||
config_ex.json ^
|
||||
config_jp.json ^
|
||||
config_st1_ch.json ^
|
||||
config_st1_ex.json ^
|
||||
config_st1_jp.json ^
|
||||
config_st2_ch.json ^
|
||||
config_st2_ex.json ^
|
||||
config_st2_jp.json ^
|
||||
config_st3_ch.json ^
|
||||
config_st3_ex.json ^
|
||||
config_st3_jp.json ^
|
||||
config_st4_ch.json ^
|
||||
config_st4_ex.json ^
|
||||
config_st4_jp.json ^
|
||||
config_laninstall_server_ch.json ^
|
||||
config_laninstall_client1_ch.json ^
|
||||
config_laninstall_client2_ch.json ^
|
||||
config_laninstall_client3_ch.json ^
|
||||
config_laninstall_server_ex.json ^
|
||||
config_laninstall_client1_ex.json ^
|
||||
config_laninstall_client2_ex.json ^
|
||||
config_laninstall_client3_ex.json ^
|
||||
config_laninstall_server_jp.json ^
|
||||
config_laninstall_client1_jp.json ^
|
||||
config_laninstall_client2_jp.json ^
|
||||
config_laninstall_client3_jp.json ^
|
||||
config_hook.json
|
||||
|
||||
start /min "AM Daemon" inject -d -k tokyohook.dll amdaemon.exe -c %AMDAEMON_CFG%
|
||||
timeout %DAEMON_WAIT_SECONDS% > nul 2>&1
|
||||
|
||||
REM ---------------------------------------------------------------------------
|
||||
REM Set configuration
|
||||
REM ---------------------------------------------------------------------------
|
||||
|
||||
REM Configuration values to be passed to the game executable.
|
||||
REM All known values:
|
||||
REM -forceapi:11
|
||||
REM -forcehal
|
||||
REM -forcevsync:0/1
|
||||
REM -fullscreen
|
||||
REM -windowed
|
||||
REM Note: -windowed is recommended as the game looks sharper in windowed mode.
|
||||
inject -d -k tokyohook.dll app.exe -windowed
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
@ -99,7 +99,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_DIVA_SLIDER)
|
||||
dprintf("TX Buffer:\n");
|
||||
dump_iobuf(&slider_uart.written);
|
||||
#endif
|
||||
@ -118,7 +118,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_DIVA_SLIDER)
|
||||
dprintf("Deframe Buffer:\n");
|
||||
dump_iobuf(&req_iobuf);
|
||||
#endif
|
||||
|
@ -352,7 +352,7 @@ Enable keychip emulation. Disable to use a real keychip.
|
||||
Default: `A69E-01A88888888`
|
||||
|
||||
Keychip serial number. Keychip serials observed in the wild follow this
|
||||
pattern: `A6xE-01Ayyyyyyyy`.
|
||||
pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
|
||||
### `gameId`
|
||||
|
||||
|
@ -52,16 +52,12 @@ HRESULT fgo_io_poll(void);
|
||||
void fgo_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
FGO_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.
|
||||
FGO_IO_GAMEBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *gamebtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void fgo_io_get_gamebtns(uint8_t *btn);
|
||||
void fgo_io_get_gamebtns(uint8_t *gamebtn);
|
||||
|
||||
/* Get the position of the cabinet stick as of the last poll. The center
|
||||
position should be equal to or close to 32767.
|
||||
|
@ -224,9 +224,19 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice(
|
||||
gfx_util_frame_window(hwnd);
|
||||
}
|
||||
|
||||
dprintf("Gfx: Using adapter %d\n", gfx_config.monitor);
|
||||
UINT max_adapter = IDirect3D9_GetAdapterCount(real);
|
||||
adapter = gfx_config.monitor;
|
||||
if (adapter >= max_adapter) {
|
||||
dprintf(
|
||||
"Gfx: Requested adapter %d but maximum is %d. Using primary monitor\n",
|
||||
gfx_config.monitor, max_adapter - 1
|
||||
);
|
||||
adapter = D3DADAPTER_DEFAULT;
|
||||
} else {
|
||||
dprintf("Gfx: Using adapter %d\n", gfx_config.monitor);
|
||||
}
|
||||
|
||||
return IDirect3D9_CreateDevice(real, gfx_config.monitor, type, hwnd, flags, pp, pdev);
|
||||
return IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice(
|
||||
|
1602
hooklib/printer.c
1602
hooklib/printer.c
File diff suppressed because it is too large
Load Diff
@ -14,3 +14,4 @@ struct printer_config {
|
||||
};
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_hook_insert_hooks(HMODULE target);
|
||||
|
@ -66,6 +66,16 @@ void idac_dll_config_load(
|
||||
filename);
|
||||
}
|
||||
|
||||
void indrun_config_load(
|
||||
struct indrun_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"indrun", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void idac_hook_config_load(
|
||||
struct idac_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -80,6 +90,7 @@ void idac_hook_config_load(
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
led15070_config_load(&cfg->led15070, filename);
|
||||
indrun_config_load(&cfg->indrun, filename);
|
||||
}
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "idachook/idac-dll.h"
|
||||
#include "idachook/zinput.h"
|
||||
#include "idachook/indrun.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
@ -21,6 +22,7 @@ struct idac_hook_config {
|
||||
struct idac_dll_config dll;
|
||||
struct zinput_config zinput;
|
||||
struct led15070_config led15070;
|
||||
struct indrun_config indrun;
|
||||
};
|
||||
|
||||
void idac_dll_config_load(
|
||||
@ -31,4 +33,10 @@ void idac_hook_config_load(
|
||||
struct idac_hook_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename);
|
||||
void zinput_config_load(
|
||||
struct zinput_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void indrun_config_load(
|
||||
struct indrun_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
@ -91,6 +91,13 @@ static DWORD CALLBACK idac_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize native plugin DLL hooks
|
||||
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the initialization. */
|
||||
|
||||
indrun_hook_init(&idac_hook_cfg.indrun);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
260
idachook/indrun.c
Normal file
260
idachook/indrun.c
Normal file
@ -0,0 +1,260 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "indrun.h"
|
||||
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"IndRun.dll",
|
||||
};
|
||||
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
static void app_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(int nIndex);
|
||||
static int (WINAPI *next_GetSystemMetrics)(int nIndex);
|
||||
|
||||
static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize);
|
||||
static DWORD WINAPI hook_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer);
|
||||
static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
||||
static int (WINAPI *next_GetVersionExW)(LPOSVERSIONINFOW lpVersionInformation);
|
||||
static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
|
||||
static BOOL (WINAPI *next_VerifyVersionInfoW)(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
|
||||
static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded);
|
||||
static BOOL (WINAPI *next_K32EnumProcesses)(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded);
|
||||
|
||||
static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
|
||||
|
||||
static const struct hook_symbol idac_app_user32_syms[] = {
|
||||
{
|
||||
.name = "GetSystemMetrics",
|
||||
.patch = hook_GetSystemMetrics,
|
||||
.link = (void **) &next_GetSystemMetrics,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol idac_app_kernel32_syms[] = {
|
||||
{
|
||||
.name = "GetComputerNameW",
|
||||
.patch = hook_GetComputerNameW,
|
||||
},
|
||||
{
|
||||
.name = "GetCurrentDirectoryW",
|
||||
.patch = hook_GetCurrentDirectoryW,
|
||||
},
|
||||
{
|
||||
.name = "GetVersionExW",
|
||||
.patch = hook_GetVersionExW,
|
||||
.link = (void **) &next_GetVersionExW,
|
||||
},
|
||||
{
|
||||
.name = "VerifyVersionInfoW",
|
||||
.patch = hook_VerifyVersionInfoW,
|
||||
.link = (void **) &next_VerifyVersionInfoW,
|
||||
},
|
||||
{
|
||||
.name = "K32EnumProcesses",
|
||||
.patch = hook_K32EnumProcesses,
|
||||
.link = (void **) &next_K32EnumProcesses,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol idac_app_advapi32_syms[] = {
|
||||
{
|
||||
.name = "GetUserNameW",
|
||||
.patch = hook_GetUserNameW,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol indrun_kernel32_syms[] = {
|
||||
{
|
||||
.name = "LoadLibraryW",
|
||||
.patch = hook_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
}
|
||||
};
|
||||
|
||||
void indrun_hook_init(struct indrun_config *cfg)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("IDAC: Hooks enabled.\n");
|
||||
|
||||
// GameProject-Win64-Shipping.exe hooks
|
||||
app_hook_insert_hooks(NULL);
|
||||
|
||||
// IndRun.dll hooks
|
||||
dll_hook_insert_hooks(NULL);
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
indrun_kernel32_syms,
|
||||
_countof(indrun_kernel32_syms));
|
||||
}
|
||||
|
||||
void app_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"user32.dll",
|
||||
idac_app_user32_syms,
|
||||
_countof(idac_app_user32_syms));
|
||||
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
idac_app_kernel32_syms,
|
||||
_countof(idac_app_kernel32_syms));
|
||||
|
||||
hook_table_apply(
|
||||
target,
|
||||
"advapi32.dll",
|
||||
idac_app_advapi32_syms,
|
||||
_countof(idac_app_advapi32_syms));
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
|
||||
{
|
||||
const wchar_t *name_end;
|
||||
const wchar_t *target_module;
|
||||
bool already_loaded;
|
||||
HMODULE result;
|
||||
size_t name_len;
|
||||
size_t target_module_len;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if the module is already loaded
|
||||
already_loaded = GetModuleHandleW(name) != NULL;
|
||||
|
||||
// Must call the next handler so the DLL reference count is incremented
|
||||
result = next_LoadLibraryW(name);
|
||||
|
||||
if (!already_loaded && result != NULL) {
|
||||
name_len = wcslen(name);
|
||||
|
||||
for (size_t i = 0; i < target_modules_len; i++) {
|
||||
target_module = target_modules[i];
|
||||
target_module_len = wcslen(target_module);
|
||||
|
||||
// Check if the newly loaded library is at least the length of
|
||||
// the name of the target module
|
||||
if (name_len < target_module_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
name_end = &name[name_len - target_module_len];
|
||||
|
||||
// Check if the name of the newly loaded library is one of the
|
||||
// modules the path hooks should be injected into
|
||||
if (_wcsicmp(name_end, target_module) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("IDAC: Hooked %S\n", target_module);
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
app_hook_insert_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(int nIndex) {
|
||||
int ret = next_GetSystemMetrics(nIndex);
|
||||
|
||||
// Disable mouse buttons detection
|
||||
if (nIndex == SM_CMOUSEBUTTONS) {
|
||||
dprintf("IDAC: GetSystemMetrics(%d) -> 0\n", nIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize) {
|
||||
dprintf("IDAC: GetComputerNameW -> ACAE01A99999999\n");
|
||||
|
||||
// Fake the computer name as ACAE01A999999999
|
||||
wcscpy(lpBuffer, L"ACAE01A999999999");
|
||||
*nSize = _countof(L"ACAE01A99999999");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) {
|
||||
dprintf("IDAC: GetCurrentDirectoryW -> X:\\\n");
|
||||
|
||||
// Fake the current diretory as X:
|
||||
wcscpy(lpBuffer, L"X");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) {
|
||||
int result = next_GetVersionExW(lpVersionInformation);
|
||||
|
||||
// Fake the version as Windows 10 1809
|
||||
if (result) {
|
||||
dprintf("IDAC: GetVersionExW -> Windows 10 1809\n");
|
||||
lpVersionInformation->dwMajorVersion = 10;
|
||||
lpVersionInformation->dwMinorVersion = 0;
|
||||
lpVersionInformation->dwBuildNumber = 17763;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) {
|
||||
dprintf("IDAC: GetUserNameW -> AppUser\n");
|
||||
|
||||
// Fake the user name as AppUser
|
||||
wcscpy(lpBuffer, L"AppUser");
|
||||
*pcbBuffer = _countof(L"AppUser");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask) {
|
||||
BOOL result = next_VerifyVersionInfoW(lpVersionInformation, dwTypeMask, dwlConditionMask);
|
||||
|
||||
// Fake the version as Windows 10 1809
|
||||
if (lpVersionInformation->dwBuildNumber == 17763) {
|
||||
dprintf("IDAC: VerifyVersionInfoW -> Windows 10 1809\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded) {
|
||||
BOOL result = next_K32EnumProcesses(lpidProcess, cb, lpcbNeeded);
|
||||
|
||||
// Rteurn an empy process list
|
||||
dprintf("IDAC: K32EnumProcesses -> NULL\n");
|
||||
lpidProcess = NULL;
|
||||
*lpcbNeeded = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
9
idachook/indrun.h
Normal file
9
idachook/indrun.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
struct indrun_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
void indrun_hook_init(struct indrun_config *cfg);
|
@ -28,5 +28,7 @@ shared_library(
|
||||
'io4.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'indrun.c',
|
||||
'indrun.h',
|
||||
],
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ void jvs_crack_request(
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("Decoded request:\n");
|
||||
dump_iobuf(&decode);
|
||||
#endif
|
||||
@ -96,7 +96,7 @@ void jvs_crack_request(
|
||||
resp_bytes[2] = 0x01; /* Status: Success */
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_JVS)
|
||||
dprintf("Encoding response:\n");
|
||||
dump_iobuf(&encode);
|
||||
#endif
|
||||
|
@ -130,7 +130,7 @@ static HRESULT touch0_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
dprintf("TX0 Buffer:\n");
|
||||
dump_iobuf(&touch0_uart.written);
|
||||
#endif
|
||||
@ -177,7 +177,7 @@ static HRESULT touch1_handle_irp_locked(struct irp *irp)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
dprintf("TX1 Buffer:\n");
|
||||
dump_iobuf(&touch1_uart.written);
|
||||
#endif
|
||||
@ -305,11 +305,11 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req)
|
||||
resp.cmd = 0xa8;
|
||||
resp.checksum = 0;
|
||||
|
||||
if (req->side == 0) {
|
||||
if (req->side == 0) {
|
||||
resp.version[6] = 'R';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
@ -322,7 +322,7 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req)
|
||||
resp.version[6] = 'L';
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < sizeof(resp.version); i++) {
|
||||
dprintf("0x%02x ", resp.version[i]);
|
||||
}
|
||||
@ -370,7 +370,7 @@ static HRESULT touch_handle_mystery2(const struct touch_req *req)
|
||||
|
||||
if (req->side == 0) {
|
||||
hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
}
|
||||
else {
|
||||
hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
@ -388,7 +388,7 @@ static HRESULT touch_handle_start_auto_scan(const struct touch_req *req)
|
||||
|
||||
dprintf("Wacca Touch%d: Start Auto", req->side);
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_MERCURY_SLIDER)
|
||||
for (int i = 0; i < req->data_length; i++)
|
||||
dprintf("0x%02x ", req->data[i]);
|
||||
#endif
|
||||
@ -451,13 +451,13 @@ static void touch_res_auto_scan(const bool *state)
|
||||
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));
|
||||
|
||||
|
39
meson.build
39
meson.build
@ -39,6 +39,43 @@ if cc.get_id() != 'msvc'
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('log_all') or get_option('log_jvs')
|
||||
add_project_arguments('-DLOG_JVS', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_io3')
|
||||
add_project_arguments('-DLOG_IO3', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_led15093')
|
||||
add_project_arguments('-DLOG_LED15093', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_nfc')
|
||||
add_project_arguments('-DLOG_NFC', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_control_bd')
|
||||
add_project_arguments('-DLOG_CAROL_CONTROL_BD', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_led_bd')
|
||||
add_project_arguments('-DLOG_CAROL_LED_BD', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_carol_touch')
|
||||
add_project_arguments('-DLOG_CAROL_TOUCH', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_chuni_slider')
|
||||
add_project_arguments('-DLOG_CHUNI_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_chusan_slider')
|
||||
add_project_arguments('-DLOG_CHUSAN_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_diva_slider')
|
||||
add_project_arguments('-DLOG_DIVA_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_mercury_slider')
|
||||
add_project_arguments('-DLOG_MERCURY_SLIDER', language: 'c')
|
||||
endif
|
||||
if get_option('log_all') or get_option('log_clock')
|
||||
add_project_arguments('-DLOG_CLOCK', language: 'c')
|
||||
endif
|
||||
|
||||
shlwapi_lib = cc.find_library('shlwapi')
|
||||
dinput8_lib = cc.find_library('dinput8')
|
||||
dxguid_lib = cc.find_library('dxguid')
|
||||
@ -71,6 +108,7 @@ subdir('mai2io')
|
||||
subdir('cmio')
|
||||
subdir('mercuryio')
|
||||
subdir('cxbio')
|
||||
subdir('tokyoio')
|
||||
subdir('fgoio')
|
||||
|
||||
subdir('chunihook')
|
||||
@ -86,4 +124,5 @@ subdir('mai2hook')
|
||||
subdir('cmhook')
|
||||
subdir('mercuryhook')
|
||||
subdir('cxbhook')
|
||||
subdir('tokyohook')
|
||||
subdir('fgohook')
|
||||
|
65
meson_options.txt
Normal file
65
meson_options.txt
Normal file
@ -0,0 +1,65 @@
|
||||
option('log_all',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enables all of the subsequent debug logging options'
|
||||
)
|
||||
option('log_jvs',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for JVS'
|
||||
)
|
||||
option('log_io3',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for JVS'
|
||||
)
|
||||
option('log_led15093',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the 15093 LED board emulation'
|
||||
)
|
||||
option('log_nfc',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for NFC'
|
||||
)
|
||||
option('log_carol_control_bd',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo Control Board'
|
||||
)
|
||||
option('log_carol_led_bd',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo LED Board'
|
||||
)
|
||||
option('log_carol_touch',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Carlo Touchscreen'
|
||||
)
|
||||
option('log_chuni_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Chunithm Slider'
|
||||
)
|
||||
option('log_chusan_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Chusan Slider'
|
||||
)
|
||||
option('log_diva_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the Diva Slider'
|
||||
)
|
||||
option('log_mercury_slider',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for the WACCA Slider'
|
||||
)
|
||||
option('log_clock',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable debug logging for clock APIs'
|
||||
)
|
@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "platform/clock.h"
|
||||
|
||||
@ -19,7 +20,9 @@ static BOOL WINAPI my_SetTimeZoneInformation(TIME_ZONE_INFORMATION *tzinfo);
|
||||
|
||||
static BOOL (WINAPI * next_GetSystemTimeAsFileTime)(FILETIME *out);
|
||||
static int64_t clock_current_day;
|
||||
static bool clock_timezone;
|
||||
static bool clock_time_warp;
|
||||
static bool clock_writeable;
|
||||
|
||||
static const struct hook_symbol clock_base_hook_syms[] = {
|
||||
{
|
||||
@ -158,7 +161,7 @@ static BOOL WINAPI my_GetSystemTime(SYSTEMTIME *out)
|
||||
return ok;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if defined(LOG_CLOCK)
|
||||
static int last_second;
|
||||
|
||||
if (out->wSecond != last_second) {
|
||||
@ -225,35 +228,41 @@ HRESULT clock_hook_init(const struct clock_config *cfg)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
|
||||
clock_timezone = cfg->timezone;
|
||||
clock_time_warp = cfg->timewarp;
|
||||
clock_writeable = cfg->writeable;
|
||||
|
||||
if (cfg->timezone || cfg->timewarp || !cfg->writeable) {
|
||||
clock_hook_insert_hooks(NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void clock_hook_insert_hooks(HMODULE target) {
|
||||
if (clock_timezone || clock_time_warp || !clock_writeable) {
|
||||
/* All the clock hooks require the core GSTAFT hook to be installed */
|
||||
/* Note the ! up there btw. */
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
target,
|
||||
"kernel32.dll",
|
||||
clock_base_hook_syms,
|
||||
_countof(clock_base_hook_syms));
|
||||
}
|
||||
|
||||
if (cfg->timezone) {
|
||||
if (clock_timezone) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
target,
|
||||
"kernel32.dll",
|
||||
clock_read_hook_syms,
|
||||
_countof(clock_read_hook_syms));
|
||||
}
|
||||
|
||||
if (!cfg->writeable) {
|
||||
if (!clock_writeable) {
|
||||
/* Install hook if this config parameter is FALSE! */
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
target,
|
||||
"kernel32.dll",
|
||||
clock_write_hook_syms,
|
||||
_countof(clock_write_hook_syms));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -11,3 +11,4 @@ struct clock_config {
|
||||
};
|
||||
|
||||
HRESULT clock_hook_init(const struct clock_config *cfg);
|
||||
void clock_hook_insert_hooks(HMODULE target);
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "platform/pcbid.h"
|
||||
#include "platform/platform.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/dipsw.h"
|
||||
#include "platform/system.h"
|
||||
|
||||
void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
@ -40,7 +40,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
||||
netenv_config_load(&cfg->netenv, filename);
|
||||
nusec_config_load(&cfg->nusec, filename);
|
||||
vfs_config_load(&cfg->vfs, filename);
|
||||
dipsw_config_load(&cfg->dipsw, filename);
|
||||
system_config_load(&cfg->system, filename);
|
||||
}
|
||||
|
||||
void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename)
|
||||
@ -329,7 +329,7 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename)
|
||||
filename);
|
||||
}
|
||||
|
||||
void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename)
|
||||
void system_config_load(struct system_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
wchar_t name[7];
|
||||
size_t i;
|
||||
@ -337,14 +337,14 @@ void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename)
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 0, filename);
|
||||
cfg->freeplay = GetPrivateProfileIntW(L"gpio", L"freeplay", 0, filename);
|
||||
cfg->enable = GetPrivateProfileIntW(L"system", L"enable", 0, filename);
|
||||
cfg->freeplay = GetPrivateProfileIntW(L"system", L"freeplay", 0, filename);
|
||||
|
||||
wcscpy_s(name, _countof(name), L"dipsw0");
|
||||
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
name[5] = L'1' + i;
|
||||
cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename);
|
||||
cfg->dipsw[i] = GetPrivateProfileIntW(L"system", name, 0, filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "platform/pcbid.h"
|
||||
#include "platform/platform.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/dipsw.h"
|
||||
#include "platform/system.h"
|
||||
|
||||
void platform_config_load(
|
||||
struct platform_config *cfg,
|
||||
@ -35,4 +35,4 @@ void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename);
|
||||
void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename);
|
||||
void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename);
|
||||
void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename);
|
||||
void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename);
|
||||
void system_config_load(struct system_config *cfg, const wchar_t *filename);
|
||||
|
@ -109,17 +109,23 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
|
||||
return hr;
|
||||
}
|
||||
|
||||
// CHN
|
||||
// PowerOn
|
||||
// WAHLAP PowerOn
|
||||
hr = dns_hook_push(L"at.sys-all.cn", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// WeChat AimeDB Server
|
||||
// WAHLAP WeChat AimeDB Server
|
||||
hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// WAHLAP Billing
|
||||
hr = dns_hook_push(L"ib.sys-all.cn", cfg->billing);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ platform_lib = static_library(
|
||||
'platform.h',
|
||||
'vfs.c',
|
||||
'vfs.h',
|
||||
'dipsw.c',
|
||||
'dipsw.h',
|
||||
'system.c',
|
||||
'system.h',
|
||||
],
|
||||
)
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "platform/pcbid.h"
|
||||
#include "platform/platform.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/dipsw.h"
|
||||
#include "platform/system.h"
|
||||
|
||||
HRESULT platform_hook_init(
|
||||
const struct platform_config *cfg,
|
||||
@ -82,7 +82,7 @@ HRESULT platform_hook_init(
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = dipsw_init(&cfg->dipsw, &cfg->vfs);
|
||||
hr = system_init(&cfg->system, &cfg->vfs);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "platform/nusec.h"
|
||||
#include "platform/pcbid.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/dipsw.h"
|
||||
#include "platform/system.h"
|
||||
|
||||
struct platform_config {
|
||||
struct amvideo_config amvideo;
|
||||
@ -27,7 +27,7 @@ struct platform_config {
|
||||
struct netenv_config netenv;
|
||||
struct nusec_config nusec;
|
||||
struct vfs_config vfs;
|
||||
struct dipsw_config dipsw;
|
||||
struct system_config system;
|
||||
};
|
||||
|
||||
HRESULT platform_hook_init(
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform/dipsw.h"
|
||||
#include "platform/system.h"
|
||||
#include "platform/vfs.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
@ -30,12 +30,12 @@ typedef struct
|
||||
char padding[4];
|
||||
uint8_t dip_switches;
|
||||
char data[DATA_SIZE];
|
||||
} DipSwitchBlock;
|
||||
} DipSwBlock;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CreditBlock credit_block;
|
||||
DipSwitchBlock dip_switch_block;
|
||||
DipSwBlock dip_switch_block;
|
||||
char *data;
|
||||
} SystemInfo;
|
||||
|
||||
@ -43,13 +43,13 @@ typedef struct
|
||||
|
||||
static SystemInfo system_info;
|
||||
|
||||
static struct dipsw_config dipsw_config;
|
||||
static struct system_config system_config;
|
||||
static struct vfs_config vfs_config;
|
||||
|
||||
static void dipsw_read_sysfile(const wchar_t *sys_file);
|
||||
static void dipsw_save_sysfile(const wchar_t *sys_file);
|
||||
static void system_read_sysfile(const wchar_t *sys_file);
|
||||
static void system_save_sysfile(const wchar_t *sys_file);
|
||||
|
||||
HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg)
|
||||
HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
wchar_t sys_file_path[MAX_PATH];
|
||||
@ -62,28 +62,28 @@ HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
memcpy(&dipsw_config, cfg, sizeof(*cfg));
|
||||
memcpy(&system_config, cfg, sizeof(*cfg));
|
||||
|
||||
sys_file_path[0] = L'\0';
|
||||
// concatenate vfs_config.amfs with L"sysfile.dat"
|
||||
wcsncpy(sys_file_path, vfs_cfg->amfs, MAX_PATH);
|
||||
wcsncat(sys_file_path, L"\\sysfile.dat", MAX_PATH);
|
||||
|
||||
dipsw_read_sysfile(sys_file_path);
|
||||
system_read_sysfile(sys_file_path);
|
||||
|
||||
// now write the dipsw_config.dipsw to the dip_switch_block
|
||||
dipsw_save_sysfile(sys_file_path);
|
||||
// now write the system_config.system to the dip_switch_block
|
||||
system_save_sysfile(sys_file_path);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void dipsw_read_sysfile(const wchar_t *sys_file)
|
||||
static void system_read_sysfile(const wchar_t *sys_file)
|
||||
{
|
||||
FILE *f = _wfopen(sys_file, L"r");
|
||||
|
||||
if (f == NULL)
|
||||
{
|
||||
dprintf("DipSw: First run detected, DipSw settings can only be applied AFTER the first run\n");
|
||||
dprintf("System: First run detected, system settings can only be applied AFTER the first run\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ static void dipsw_read_sysfile(const wchar_t *sys_file)
|
||||
|
||||
if (file_size != 0x6000)
|
||||
{
|
||||
dprintf("DipSw: Invalid sysfile.dat file size\n");
|
||||
dprintf("System: Invalid sysfile.dat file size\n");
|
||||
fclose(f);
|
||||
|
||||
return;
|
||||
@ -108,10 +108,10 @@ static void dipsw_read_sysfile(const wchar_t *sys_file)
|
||||
memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static void dipsw_save_sysfile(const wchar_t *sys_file)
|
||||
static void system_save_sysfile(const wchar_t *sys_file)
|
||||
{
|
||||
char block[BLOCK_SIZE];
|
||||
uint8_t dipsw = 0;
|
||||
uint8_t system = 0;
|
||||
uint8_t freeplay = 0;
|
||||
|
||||
// open the sysfile.dat for writing in bytes mode
|
||||
@ -122,28 +122,28 @@ static void dipsw_save_sysfile(const wchar_t *sys_file)
|
||||
return;
|
||||
}
|
||||
|
||||
// write the dipsw_config.dipsw to the dip_switch_block
|
||||
// write the system_config.system to the dip_switch_block
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (dipsw_config.dipsw[i])
|
||||
if (system_config.dipsw[i])
|
||||
{
|
||||
// print which dipsw is enabled
|
||||
dprintf("DipSw: DipSw%d=1 set\n", i + 1);
|
||||
dipsw |= (1 << i);
|
||||
// print which system is enabled
|
||||
dprintf("System: DipSw%d=1 set\n", i + 1);
|
||||
system |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (dipsw_config.freeplay)
|
||||
if (system_config.freeplay)
|
||||
{
|
||||
// print that freeplay is enabled
|
||||
dprintf("DipSw: Freeplay enabled\n");
|
||||
dprintf("System: Freeplay enabled\n");
|
||||
freeplay = 1;
|
||||
}
|
||||
|
||||
// set the new credit block
|
||||
system_info.credit_block.freeplay = freeplay;
|
||||
// set the new dip_switch_block
|
||||
system_info.dip_switch_block.dip_switches = dipsw;
|
||||
system_info.dip_switch_block.dip_switches = system;
|
||||
|
||||
// calculate the new checksum, skip the old crc32 value
|
||||
// which is at the beginning of the block, thats's why the +4
|
||||
@ -167,7 +167,7 @@ static void dipsw_save_sysfile(const wchar_t *sys_file)
|
||||
|
||||
// print the dip_switch_block in hex
|
||||
/*
|
||||
dprintf("DipSw Block: ");
|
||||
dprintf("System Block: ");
|
||||
for (size_t i = 0; i < BLOCK_SIZE; i++)
|
||||
{
|
||||
dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]);
|
@ -7,10 +7,10 @@
|
||||
|
||||
#include "platform/vfs.h"
|
||||
|
||||
struct dipsw_config {
|
||||
struct system_config {
|
||||
bool enable;
|
||||
bool freeplay;
|
||||
bool dipsw[8];
|
||||
};
|
||||
|
||||
HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg);
|
||||
HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg);
|
456
segatools.md
456
segatools.md
@ -1,456 +0,0 @@
|
||||
# Segatools common configuration settings
|
||||
|
||||
This file describes configuration settings for Segatools that are common to
|
||||
all games.
|
||||
|
||||
Keyboard binding settings use
|
||||
[Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
|
||||
|
||||
## `[aimeio]`
|
||||
|
||||
Controls the card reader driver.
|
||||
|
||||
### `path`
|
||||
|
||||
Specify a path for a third-party card reader driver DLL. Default is empty
|
||||
(use built-in emulation based on text files and keyboard input).
|
||||
|
||||
In previous versions of Segatools this was accomplished by replacing the
|
||||
AIMEIO.DLL file that came with Segatools. Segatools no longer ships with a
|
||||
separate AIMEIO.DLL file (its functionality is now built into the various hook
|
||||
DLLs).
|
||||
|
||||
## `[aime]`
|
||||
|
||||
Controls emulation of the Aime card reader assembly.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
reader (COM port number varies by game).
|
||||
|
||||
### `aimePath`
|
||||
|
||||
Default: `DEVICE\aime.txt`
|
||||
|
||||
Path to a text file containing a classic Aime IC card ID. **This does not
|
||||
currently work**.
|
||||
|
||||
### `felicaPath`
|
||||
|
||||
Default: `DEVICE\felica.txt`
|
||||
|
||||
Path to a text file containing a FeliCa e-cash card IDm serial number.
|
||||
|
||||
### `felicaGen`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Whether to generate a random FeliCa ID if the file at `felicaPath` does not
|
||||
exist.
|
||||
|
||||
### `scan`
|
||||
|
||||
Default: `0x0D` (`VK_RETURN`)
|
||||
|
||||
Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
emulated; the exact choice of card that is emulated depends on the presence or
|
||||
absence of the configured card ID files.
|
||||
|
||||
## `[amvideo]`
|
||||
|
||||
Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is
|
||||
normally present on the SEGA operating system image which is responsible for
|
||||
changing screen resolution and orientation.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable stub `amvideo.dll`. Disable to use a real `amvideo.dll` build. Note that
|
||||
you must have the correct registry settings installed and you must use the
|
||||
version of `amvideo.dll` that matches your GPU vendor (since these DLLs make
|
||||
use of vendor-specific APIs).
|
||||
|
||||
## `[clock]`
|
||||
|
||||
Controls hooks for Windows time-of-day APIs.
|
||||
|
||||
### `timezone`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Make the system time zone appear to be JST. SEGA games malfunction in strange
|
||||
ways if the system time zone is not JST. There should not be any reason to
|
||||
disable this hook other than possible implementation bugs, but the option is
|
||||
provided if you need it.
|
||||
|
||||
### `timewarp`
|
||||
|
||||
Default: `0`
|
||||
|
||||
Experimental time-of-day warping hook that skips over the hardcoded server
|
||||
maintenance period. Causes an incorrect in-game time-of-day to be reported.
|
||||
Better solutions for this problem exist and this feature will probably be
|
||||
removed soon.
|
||||
|
||||
### `writeable`
|
||||
|
||||
Default: `0`
|
||||
|
||||
Allow game to adjust system clock and time zone settings. This should normally
|
||||
be left at `0`, but the option is provided if you need it.
|
||||
|
||||
## `[dns]`
|
||||
|
||||
Controls redirection of network server hostname lookups
|
||||
|
||||
### `default`
|
||||
|
||||
Default: `localhost`
|
||||
|
||||
Controls hostname of all of the common network services servers, unless
|
||||
overriden by a specific setting below. Most users will only need to change this
|
||||
setting. Also, loopback addresses are specifically checked for and rejected by
|
||||
the games themselves; this needs to be a LAN or WAN IP (or a hostname that
|
||||
resolves to one).
|
||||
|
||||
### `router`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `tenporouter.loc` and `bbrouter.loc` hostname
|
||||
lookups.
|
||||
|
||||
### `startup`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `naominet.jp` host lookup.
|
||||
|
||||
### `billing`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `ib.naominet.jp` host lookup.
|
||||
|
||||
### `aimedb`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
|
||||
Overrides the target of the `aime.naominet.jp` host lookup.
|
||||
|
||||
## `[ds]`
|
||||
|
||||
Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX
|
||||
PCIe board. This is a small (32 byte) EEPROM that contains serial number and
|
||||
region code information. It is not normally written to outside of inital
|
||||
factory provisioning of a Sega Nu.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable DS EEPROM emulation. Disable to use the DS EEPROM chip on a real AMEX.
|
||||
|
||||
### `region`
|
||||
|
||||
Default: `1`
|
||||
|
||||
AMEX Board region code. This appears to be a bit mask?
|
||||
|
||||
- `1`: Japan
|
||||
- `2`: USA? (Dead code, not used)
|
||||
- `4`: Export
|
||||
- `8`: China
|
||||
|
||||
### `serialNo`
|
||||
|
||||
Default `AAVE-01A99999999`
|
||||
|
||||
"MAIN ID" serial number. First three characters are hardware series:
|
||||
|
||||
- `AAV`: Nu-series
|
||||
- `AAW`: NuSX-series
|
||||
- `ACA`: ALLS-series
|
||||
|
||||
## `[eeprom]`
|
||||
|
||||
Controls emulation of the bulk EEPROM on the AMEX PCIe board. This chip stores
|
||||
status and configuration information.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable bulk EEPROM emulation. Disable to use the bulk EEPROM chip on a real
|
||||
AMEX.
|
||||
|
||||
### `path`
|
||||
|
||||
Default: `DEVICE\eeprom.bin`
|
||||
|
||||
Path to the storage file for EEPROM emulation. This file is automatically
|
||||
created and initialized with a suitable number of zero bytes if it does not
|
||||
already exist.
|
||||
|
||||
## `[gpio]`
|
||||
|
||||
Configure emulation of the AMEX PCIe GPIO (General Purpose Input Output)
|
||||
controller.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable GPIO emulation. Disable to use the GPIO controller on a real AMEX.
|
||||
|
||||
### `sw1`
|
||||
|
||||
Default `0x70` (`VK_F1`)
|
||||
|
||||
Keyboard binding for Nu chassis SW1 button (alternative Test)
|
||||
|
||||
### `sw2`
|
||||
|
||||
Default `0x71` (`VK_F2`)
|
||||
|
||||
Keyboard binding for Nu chassis SW2 button (alternative Service)
|
||||
|
||||
### `dipsw1` .. `dipsw8`
|
||||
|
||||
Defaults: `1`, `0`, `0`, `0`, `0`, `0`, `0`, `0`
|
||||
|
||||
Nu chassis DIP switch settings:
|
||||
|
||||
- Switch 1: Game-specific, but usually controls the "distribution server"
|
||||
setting. Exactly one arcade machine on a cabinet router must be set to the
|
||||
Server setting.
|
||||
- `0`: Client
|
||||
- `1`: Server
|
||||
- Switch 2,3: Game-specific.
|
||||
- Used by Mario&Sonic to configure cabinet ID, possibly other games.
|
||||
- Switch 4: Screen orientation. Only used by the Nu system startup program.
|
||||
- `0`: YOKO/Horizontal
|
||||
- `1`: TATE/Vertical
|
||||
- Switch 5,6,7: Screen resolution. Only used by the Nu system startup program.
|
||||
- `000`: No change
|
||||
- `100`: 640x480
|
||||
- `010`: 1024x600
|
||||
- `110`: 1024x768
|
||||
- `001`: 1280x720
|
||||
- `101`: 1280x1024
|
||||
- `110`: 1360x768
|
||||
- `111`: 1920x1080
|
||||
- Switch 8: Game-specific. Not used in any shipping game.
|
||||
|
||||
## `[hwmon]`
|
||||
|
||||
Configure stub implementation of the platform hardware monitor driver. The
|
||||
real implementation of this driver monitors CPU temperatures by reading from
|
||||
Intel Model Specific Registers, which is an action that is only permitted from
|
||||
kernel mode.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable hwmon emulation. Disable to use the real hwmon driver.
|
||||
|
||||
## `[jvs]`
|
||||
|
||||
Configure emulation of the AMEX PCIe JVS *controller* (not IO board!)
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable JVS port emulation. Disable to use the JVS port on a real AMEX.
|
||||
|
||||
## `[keychip]`
|
||||
|
||||
Configure keychip emulation.
|
||||
|
||||
### `enable`
|
||||
|
||||
Enable keychip emulation. Disable to use a real keychip.
|
||||
|
||||
### `id`
|
||||
|
||||
Default: `A69E-01A88888888`
|
||||
|
||||
Keychip serial number. Keychip serials observed in the wild follow this
|
||||
pattern: `A\d{2}(E01|X20)[ABCDU]\d{8}`.
|
||||
|
||||
### `gameId`
|
||||
|
||||
Default: (Varies depending on game)
|
||||
|
||||
Override the game's four-character model code. Changing this from the game's
|
||||
expected value will probably just cause a system error.
|
||||
|
||||
### `platformId`
|
||||
|
||||
Default: (Varies depending on game)
|
||||
|
||||
Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
is actually supposed to be a separate three-character `platformId` and
|
||||
integer `modelType` setting, but they are combined here for convenience. Valid
|
||||
values include:
|
||||
|
||||
- `AAV0`: Nu 1 (Project DIVA)
|
||||
- `AAV1`: Nu 1.1 (Chunithm)
|
||||
- `AAV2`: Nu 2 (Initial D Zero)
|
||||
- `AAW0`: NuSX 1
|
||||
- `AAW1`: NuSX 1.1
|
||||
- `ACA0`: ALLS UX
|
||||
- `ACA1`: ALLS HX
|
||||
- `ACA2`: ALLS UX (without dedicated GPU)
|
||||
- `ACA4`: ALLS MX
|
||||
|
||||
### `region`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Override the keychip's region code. Most games seem to pay attention to the
|
||||
DS EEPROM region code and not the keychip region code, and this seems to be
|
||||
a bit mask that controls which Nu PCB region codes this keychip is authorized
|
||||
for. So it probably only affects the system software and not the game software.
|
||||
Bit values are:
|
||||
|
||||
- 1: JPN: Japan
|
||||
- 2: USA (unused)
|
||||
- 3: EXP: Export (for Asian markets)
|
||||
- 4: CHS: China (Simplified Chinese?)
|
||||
|
||||
### `systemFlag`
|
||||
|
||||
Default: `0x64`
|
||||
|
||||
An 8-bit bitfield of unclear meaning. The least significant bit indicates a
|
||||
developer dongle, I think? Changing this doesn't seem to have any effect on
|
||||
anything other than Project DIVA.
|
||||
|
||||
Other values observed in the wild:
|
||||
|
||||
- `0x04`: SDCH, SDCA
|
||||
- `0x20`: SDCA
|
||||
|
||||
### `subnet`
|
||||
|
||||
Default `192.168.100.0`
|
||||
|
||||
The LAN IP range that the game will expect. The prefix length is hardcoded into
|
||||
the game program: for some games this is `/24`, for others it is `/20`.
|
||||
|
||||
## `[netenv]`
|
||||
|
||||
Configure network environment virtualization. This module helps bypass various
|
||||
restrictions placed upon the game's LAN environment.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable network environment virtualization. You may need to disable this if
|
||||
you want to do any head-to-head play on your LAN.
|
||||
|
||||
Note: The virtualized LAN IP range is taken from the emulated keychip's
|
||||
`subnet` setting.
|
||||
|
||||
### `addrSuffix`
|
||||
|
||||
Default: `11`
|
||||
|
||||
The final octet of the local host's IP address on the virtualized subnet (so,
|
||||
if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
|
||||
local host's virtualized LAN IP is `192.168.32.11`).
|
||||
|
||||
### `routerSuffix`
|
||||
|
||||
Default: `1`
|
||||
|
||||
The final octet of the default gateway's IP address on the virtualized subnet.
|
||||
|
||||
### `macAddr`
|
||||
|
||||
Default: `01:02:03:04:05:06`
|
||||
|
||||
The MAC address of the virtualized Ethernet adapter. The exact value shouldn't
|
||||
ever matter.
|
||||
|
||||
## `[pcbid]`
|
||||
|
||||
Configure Windows host name virtualization. The ALLS-series platform no longer
|
||||
has an AMEX board, so the MAIN ID serial number is stored in the Windows
|
||||
hostname.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable Windows host name virtualization. This is only needed for ALLS-platform
|
||||
games (since the ALLS lacks an AMEX and therefore has no DS EEPROM, so it needs
|
||||
another way to store the PCB serial), but it does no harm on games that run on
|
||||
earlier hardware.
|
||||
|
||||
### `serialNo`
|
||||
|
||||
Default: `ACAE01A99999999`
|
||||
|
||||
Set the Windows host name. This should be an ALLS MAIN ID, without the
|
||||
hyphen (which is not a valid character in a Windows host name).
|
||||
|
||||
## `[sram]`
|
||||
|
||||
Configure emulation of the AMEX PCIe battery-backed SRAM. This stores
|
||||
bookkeeping state and settings. This file is automatically created and
|
||||
initialized with a suitable number of zero bytes if it does not already exist.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default `1`
|
||||
|
||||
Enable SRAM emulation. Disable to use the SRAM on a real AMEX.
|
||||
|
||||
### `path`
|
||||
|
||||
Default `DEVICE\sram.bin`
|
||||
|
||||
Path to the storage file for SRAM emulation.
|
||||
|
||||
## `[vfs]`
|
||||
|
||||
Configure Windows path redirection hooks.
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable path redirection.
|
||||
|
||||
### `amfs`
|
||||
|
||||
Default: Empty string (causes a startup error)
|
||||
|
||||
Configure the location of the SEGA AMFS volume. Stored on the `E` partition on
|
||||
real hardware.
|
||||
|
||||
### `appdata`
|
||||
|
||||
Default: Empty string (causes a startup error)
|
||||
|
||||
Configure the location of the SEGA "APPDATA" volume (nothing to do with the
|
||||
Windows user's `%APPDATA%` directory). Stored on the `Y` partition on real
|
||||
hardware.
|
||||
|
||||
### `option`
|
||||
|
||||
Default: Empty string
|
||||
|
||||
Configure the location of the "Option" data mount point. This mount point is
|
||||
optional (hence the name, probably) and contains directories which contain
|
||||
minor over-the-air content updates.
|
110
tokyohook/config.c
Normal file
110
tokyohook/config.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
#include "tokyohook/config.h"
|
||||
|
||||
void tokyo_dll_config_load(
|
||||
struct tokyo_dll_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"tokyoio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
|
||||
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
|
||||
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
|
||||
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename);
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAED9, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"boardNumber",
|
||||
L"15093-04",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
|
||||
for (int i = n; i < sizeof(cfg->board_number); i++)
|
||||
{
|
||||
cfg->board_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"chipNumber",
|
||||
L"6704 ",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
|
||||
for (int i = n; i < sizeof(cfg->chip_number); i++)
|
||||
{
|
||||
cfg->chip_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"bootChipNumber",
|
||||
L"6709 ",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
|
||||
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
|
||||
{
|
||||
cfg->boot_chip_number[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void tokyo_hook_config_load(
|
||||
struct tokyo_hook_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
platform_config_load(&cfg->platform, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
zinput_config_load(&cfg->zinput, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
tokyo_dll_config_load(&cfg->dll, filename);
|
||||
}
|
30
tokyohook/config.h
Normal file
30
tokyohook/config.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "board/led15093.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "tokyohook/tokyo-dll.h"
|
||||
#include "tokyohook/zinput.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
struct tokyo_hook_config {
|
||||
struct platform_config platform;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct led15093_config led15093;
|
||||
struct zinput_config zinput;
|
||||
struct tokyo_dll_config dll;
|
||||
};
|
||||
|
||||
void tokyo_dll_config_load(
|
||||
struct tokyo_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void tokyo_hook_config_load(
|
||||
struct tokyo_hook_config *cfg,
|
||||
const wchar_t *filename);
|
112
tokyohook/dllmain.c
Normal file
112
tokyohook/dllmain.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
"Mario & Sonic at the Tokyo 2020 Olympics Arcade" (tokyo) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
COM1: 837-15093-04 LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "tokyohook/config.h"
|
||||
#include "tokyohook/io4.h"
|
||||
#include "tokyohook/tokyo-dll.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE tokyo_hook_mod;
|
||||
static process_entry_t tokyo_startup;
|
||||
static struct tokyo_hook_config tokyo_hook_cfg;
|
||||
|
||||
static DWORD CALLBACK tokyo_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin tokyo_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
tokyo_hook_config_load(&tokyo_hook_cfg, L".\\segatools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&tokyo_hook_cfg.dvd, tokyo_hook_mod);
|
||||
zinput_hook_init(&tokyo_hook_cfg.zinput);
|
||||
serial_hook_init();
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&tokyo_hook_cfg.platform,
|
||||
"SDFV",
|
||||
"ACA1",
|
||||
tokyo_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = tokyo_dll_init(&tokyo_hook_cfg.dll, tokyo_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15093_hook_init(&tokyo_hook_cfg.led15093,
|
||||
tokyo_dll.led_init, tokyo_dll.led_set_leds, 1, 1, 1, 2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = tokyo_io4_hook_init(&tokyo_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
||||
dprintf("--- End tokyo_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return tokyo_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
tokyo_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(tokyo_pre_startup, &tokyo_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
163
tokyohook/io4.c
Normal file
163
tokyohook/io4.c
Normal file
@ -0,0 +1,163 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "tokyohook/tokyo-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT tokyo_io4_poll(void *ctx, struct io4_state *state);
|
||||
static HRESULT tokyo_io4_write_gpio(uint8_t* payload, size_t len);
|
||||
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops tokyo_io4_ops = {
|
||||
.poll = tokyo_io4_poll,
|
||||
.write_gpio = tokyo_io4_write_gpio,
|
||||
};
|
||||
|
||||
HRESULT tokyo_io4_hook_init(const struct io4_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(tokyo_dll.init != NULL);
|
||||
|
||||
hr = io4_hook_init(cfg, &tokyo_io4_ops, NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return tokyo_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT tokyo_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
uint8_t opbtn;
|
||||
uint8_t gamebtn;
|
||||
uint8_t sense;
|
||||
HRESULT hr;
|
||||
|
||||
assert(tokyo_dll.get_opbtns != NULL);
|
||||
assert(tokyo_dll.get_gamebtns != NULL);
|
||||
assert(tokyo_dll.get_sensors != NULL);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
opbtn = 0;
|
||||
gamebtn = 0;
|
||||
sense = 0;
|
||||
|
||||
tokyo_dll.get_opbtns(&opbtn);
|
||||
tokyo_dll.get_gamebtns(&gamebtn);
|
||||
tokyo_dll.get_sensors(&sense);
|
||||
|
||||
if (opbtn & TOKYO_IO_OPBTN_TEST) {
|
||||
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||
}
|
||||
|
||||
if (opbtn & TOKYO_IO_OPBTN_SERVICE) {
|
||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||
}
|
||||
|
||||
if (opbtn & TOKYO_IO_OPBTN_COIN) {
|
||||
coins++;
|
||||
}
|
||||
state->chutes[0] = coins << 8;
|
||||
|
||||
/* Update gamebtns */
|
||||
|
||||
if (gamebtn & TOKYO_IO_GAMEBTN_BLUE) {
|
||||
state->buttons[0] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (gamebtn & TOKYO_IO_GAMEBTN_YELLOW) {
|
||||
state->buttons[0] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (gamebtn & TOKYO_IO_GAMEBTN_RED) {
|
||||
state->buttons[0] |= 1 << 15;
|
||||
}
|
||||
|
||||
/* Update sensors */
|
||||
|
||||
// Invert the logic so that it's active high
|
||||
if (!(sense & TOKYO_IO_SENSE_FOOT_LEFT)) {
|
||||
state->buttons[0] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (!(sense & TOKYO_IO_SENSE_FOOT_RIGHT)) {
|
||||
state->buttons[1] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_1) {
|
||||
state->buttons[0] |= 1 << 12;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_2) {
|
||||
state->buttons[1] |= 1 << 12;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_3) {
|
||||
state->buttons[0] |= 1 << 11;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_4) {
|
||||
state->buttons[1] |= 1 << 11;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_5) {
|
||||
state->buttons[0] |= 1 << 10;
|
||||
}
|
||||
|
||||
if (sense & TOKYO_IO_SENSE_JUMP_6) {
|
||||
state->buttons[1] |= 1 << 10;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT tokyo_io4_write_gpio(uint8_t* payload, size_t len)
|
||||
{
|
||||
// Just fast fail if there aren't enough bytes in the payload
|
||||
if (len < 3)
|
||||
return S_OK;
|
||||
|
||||
// This command is used for lights in Mario & Sonic at the Tokyo 2020 Olympics
|
||||
// Arcade, but it only contains button lights, and only in the first 3 bytes of
|
||||
// the payload; everything else is padding to make the payload 62 bytes. The
|
||||
// rest of the cabinet lights and the side button lights are handled separately,
|
||||
// by the 15093 lights controller.
|
||||
uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 |
|
||||
(uint8_t)(payload[1]) << 16 |
|
||||
(uint8_t)(payload[2]) << 8);
|
||||
|
||||
// Since Sega uses an odd ordering for the first part of the bitfield,
|
||||
// let's normalize the data and just send over bytes for the receiver
|
||||
// to interpret as RGB values.
|
||||
uint8_t rgb_out[5 * 3] = {
|
||||
lights_data & TOKYO_IO_LED_LEFT_BLUE ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CENTER_YELLOW ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_RIGHT_RED ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_LEFT_R ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_LEFT_G ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_LEFT_B ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_RIGHT_R ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_RIGHT_G ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_CONTROL_RIGHT_B ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_LEFT_R ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_LEFT_G ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_LEFT_B ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_RIGHT_R ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_RIGHT_G ? 0xFF : 0x00,
|
||||
lights_data & TOKYO_IO_LED_FLOOR_RIGHT_B ? 0xFF : 0x00,
|
||||
};
|
||||
|
||||
tokyo_dll.led_set_leds(1, rgb_out);
|
||||
|
||||
return S_OK;
|
||||
}
|
7
tokyohook/io4.h
Normal file
7
tokyohook/io4.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
HRESULT tokyo_io4_hook_init(const struct io4_config *cfg);
|
32
tokyohook/meson.build
Normal file
32
tokyohook/meson.build
Normal file
@ -0,0 +1,32 @@
|
||||
shared_library(
|
||||
'tokyohook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'tokyohook.def',
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
xinput_lib,
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
board_lib,
|
||||
hooklib_lib,
|
||||
tokyoio_lib,
|
||||
platform_lib,
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'io4.c',
|
||||
'io4.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'tokyo-dll.c',
|
||||
'tokyo-dll.h',
|
||||
],
|
||||
)
|
115
tokyohook/tokyo-dll.c
Normal file
115
tokyohook/tokyo-dll.c
Normal file
@ -0,0 +1,115 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tokyohook/tokyo-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym tokyo_dll_syms[] = {
|
||||
{
|
||||
.sym = "tokyo_io_init",
|
||||
.off = offsetof(struct tokyo_dll, init),
|
||||
}, {
|
||||
.sym = "tokyo_io_get_opbtns",
|
||||
.off = offsetof(struct tokyo_dll, get_opbtns),
|
||||
}, {
|
||||
.sym = "tokyo_io_get_gamebtns",
|
||||
.off = offsetof(struct tokyo_dll, get_gamebtns),
|
||||
}, {
|
||||
.sym = "tokyo_io_get_sensors",
|
||||
.off = offsetof(struct tokyo_dll, get_sensors),
|
||||
}, {
|
||||
.sym = "tokyo_io_led_init",
|
||||
.off = offsetof(struct tokyo_dll, led_init),
|
||||
}, {
|
||||
.sym = "tokyo_io_led_set_colors",
|
||||
.off = offsetof(struct tokyo_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
struct tokyo_dll tokyo_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 tokyo_dll_init(const struct tokyo_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("Tokyo IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Tokyo IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "tokyo_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
tokyo_dll.api_version = get_api_version();
|
||||
} else {
|
||||
tokyo_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose tokyo_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (tokyo_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Tokyo IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
tokyo_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = tokyo_dll_syms;
|
||||
hr = dll_bind(&tokyo_dll, src, &sym, _countof(tokyo_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Tokyo 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;
|
||||
}
|
24
tokyohook/tokyo-dll.h
Normal file
24
tokyohook/tokyo-dll.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "tokyoio/tokyoio.h"
|
||||
|
||||
struct tokyo_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
void (*get_sensors)(uint8_t *sense);
|
||||
HRESULT (*gpio_out)(uint32_t state);
|
||||
HRESULT (*led_init)(void);
|
||||
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||
};
|
||||
|
||||
struct tokyo_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct tokyo_dll tokyo_dll;
|
||||
|
||||
HRESULT tokyo_dll_init(const struct tokyo_dll_config *cfg, HINSTANCE self);
|
20
tokyohook/tokyohook.def
Normal file
20
tokyohook/tokyohook.def
Normal file
@ -0,0 +1,20 @@
|
||||
LIBRARY tokyohook
|
||||
|
||||
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
|
||||
tokyo_io_get_api_version
|
||||
tokyo_io_init
|
||||
tokyo_io_get_opbtns
|
||||
tokyo_io_get_gamebtns
|
||||
tokyo_io_get_sensors
|
||||
tokyo_io_led_init
|
||||
tokyo_io_led_set_colors
|
118
tokyohook/zinput.c
Normal file
118
tokyohook/zinput.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include <dinput.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tokyohook/config.h"
|
||||
#include "tokyohook/zinput.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/lib.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
HRESULT WINAPI hook_DirectInput8Create(
|
||||
HINSTANCE hinst,
|
||||
DWORD dwVersion,
|
||||
REFIID riidltf,
|
||||
LPVOID *ppvOut,
|
||||
LPUNKNOWN punkOuter);
|
||||
|
||||
static HRESULT WINAPI hook_EnumDevices(
|
||||
IDirectInput8W *self,
|
||||
DWORD dwDevType,
|
||||
LPDIENUMDEVICESCALLBACKW lpCallback,
|
||||
LPVOID pvRef,
|
||||
DWORD dwFlags);
|
||||
|
||||
static unsigned long WINAPI hook_AddRef(IUnknown *self);
|
||||
static unsigned long WINAPI hook_Release(IUnknown *self);
|
||||
|
||||
static const IDirectInput8WVtbl api_vtbl = {
|
||||
.EnumDevices = hook_EnumDevices,
|
||||
.AddRef = (void *) hook_AddRef,
|
||||
.Release = (void *) hook_Release,
|
||||
};
|
||||
|
||||
static const IDirectInput8W api = { (void *) &api_vtbl };
|
||||
|
||||
static const struct hook_symbol zinput_hook_syms[] = {
|
||||
{
|
||||
.name = "DirectInput8Create",
|
||||
.patch = hook_DirectInput8Create,
|
||||
.link = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT zinput_hook_init(struct zinput_config *cfg)
|
||||
{
|
||||
wchar_t *module_path;
|
||||
wchar_t *file_name;
|
||||
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
module_path = module_file_name(NULL);
|
||||
|
||||
if (module_path != NULL) {
|
||||
file_name = PathFindFileNameW(module_path);
|
||||
|
||||
free(module_path);
|
||||
module_path = NULL;
|
||||
|
||||
_wcslwr(file_name);
|
||||
|
||||
if (wcsstr(file_name, L"amdaemon") != NULL) {
|
||||
// dprintf("Executable filename contains 'amdaemon', disabling zinput\n");
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"dinput8.dll",
|
||||
zinput_hook_syms,
|
||||
_countof(zinput_hook_syms));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI hook_DirectInput8Create(
|
||||
HINSTANCE hinst,
|
||||
DWORD dwVersion,
|
||||
REFIID riidltf,
|
||||
LPVOID *ppvOut,
|
||||
LPUNKNOWN punkOuter)
|
||||
{
|
||||
dprintf("ZInput: Blocking built-in DirectInput support\n");
|
||||
*ppvOut = (void *) &api;
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI hook_EnumDevices(
|
||||
IDirectInput8W *self,
|
||||
DWORD dwDevType,
|
||||
LPDIENUMDEVICESCALLBACKW lpCallback,
|
||||
LPVOID pvRef,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
dprintf("ZInput: %s\n", __func__);
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static unsigned long WINAPI hook_AddRef(IUnknown *self)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned long WINAPI hook_Release(IUnknown *self)
|
||||
{
|
||||
return 1;
|
||||
}
|
11
tokyohook/zinput.h
Normal file
11
tokyohook/zinput.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct zinput_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
HRESULT zinput_hook_init(struct zinput_config *cfg);
|
10
tokyoio/backend.h
Normal file
10
tokyoio/backend.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tokyoio/tokyoio.h"
|
||||
|
||||
struct tokyo_io_backend {
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
void (*get_sensors)(uint8_t *sense);
|
||||
};
|
54
tokyoio/config.c
Normal file
54
tokyoio/config.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tokyoio/config.h"
|
||||
|
||||
|
||||
void tokyo_kb_config_load(
|
||||
struct tokyo_kb_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
/* Load game button keyboard bindings */
|
||||
cfg->vk_push_left_b = GetPrivateProfileIntW(L"keyboard", L"leftBlue", 'A', filename);
|
||||
cfg->vk_push_center_y = GetPrivateProfileIntW(L"keyboard", L"centerYellow", 'S', filename);
|
||||
cfg->vk_push_right_r = GetPrivateProfileIntW(L"keyboard", L"rightRed", 'D', filename);
|
||||
|
||||
/* Load sensor keyboard bindings */
|
||||
cfg->vk_foot_l = GetPrivateProfileIntW(L"keyboard", L"footLeft", VK_LEFT, filename);
|
||||
cfg->vk_foot_r = GetPrivateProfileIntW(L"keyboard", L"footRight", VK_RIGHT, filename);
|
||||
cfg->vk_jump_1 = GetPrivateProfileIntW(L"keyboard", L"jump1", 'Z', filename);
|
||||
cfg->vk_jump_2 = GetPrivateProfileIntW(L"keyboard", L"jump2", 'X', filename);
|
||||
cfg->vk_jump_3 = GetPrivateProfileIntW(L"keyboard", L"jump3", 'C', filename);
|
||||
cfg->vk_jump_4 = GetPrivateProfileIntW(L"keyboard", L"jump4", 'B', filename);
|
||||
cfg->vk_jump_5 = GetPrivateProfileIntW(L"keyboard", L"jump5", 'N', filename);
|
||||
cfg->vk_jump_6 = GetPrivateProfileIntW(L"keyboard", L"jump6", 'M', filename);
|
||||
cfg->vk_jump_all = GetPrivateProfileIntW(L"keyboard", L"jumpAll", VK_SPACE, filename);
|
||||
}
|
||||
|
||||
void tokyo_io_config_load(
|
||||
struct tokyo_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"io4",
|
||||
L"mode",
|
||||
L"xinput",
|
||||
cfg->mode,
|
||||
_countof(cfg->mode),
|
||||
filename);
|
||||
|
||||
tokyo_kb_config_load(&cfg->kb, filename);
|
||||
}
|
34
tokyoio/config.h
Normal file
34
tokyoio/config.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct tokyo_kb_config {
|
||||
uint8_t vk_push_left_b;
|
||||
uint8_t vk_push_center_y;
|
||||
uint8_t vk_push_right_r;
|
||||
uint8_t vk_foot_l;
|
||||
uint8_t vk_foot_r;
|
||||
uint8_t vk_jump_1;
|
||||
uint8_t vk_jump_2;
|
||||
uint8_t vk_jump_3;
|
||||
uint8_t vk_jump_4;
|
||||
uint8_t vk_jump_5;
|
||||
uint8_t vk_jump_6;
|
||||
uint8_t vk_jump_all;
|
||||
};
|
||||
|
||||
struct tokyo_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
wchar_t mode[9];
|
||||
|
||||
struct tokyo_kb_config kb;
|
||||
};
|
||||
|
||||
void tokyo_io_config_load(
|
||||
struct tokyo_io_config *cfg,
|
||||
const wchar_t *filename);
|
135
tokyoio/dllmain.c
Normal file
135
tokyoio/dllmain.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tokyoio/backend.h"
|
||||
#include "tokyoio/config.h"
|
||||
#include "tokyoio/kb.h"
|
||||
#include "tokyoio/tokyoio.h"
|
||||
#include "tokyoio/xi.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static struct tokyo_io_config tokyo_io_cfg;
|
||||
static const struct tokyo_io_backend *tokyo_io_backend;
|
||||
static bool tokyo_io_coin;
|
||||
|
||||
uint16_t tokyo_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT tokyo_io_init(void)
|
||||
{
|
||||
HINSTANCE inst;
|
||||
HRESULT hr;
|
||||
|
||||
assert(tokyo_io_backend == NULL);
|
||||
|
||||
inst = GetModuleHandleW(NULL);
|
||||
|
||||
if (inst == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("GetModuleHandleW failed: %lx\n", hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
tokyo_io_config_load(&tokyo_io_cfg, L".\\segatools.ini");
|
||||
|
||||
if (wstr_ieq(tokyo_io_cfg.mode, L"keyboard")) {
|
||||
hr = tokyo_kb_init(&tokyo_io_cfg.kb, &tokyo_io_backend);
|
||||
} else if (wstr_ieq(tokyo_io_cfg.mode, L"xinput")) {
|
||||
hr = tokyo_xi_init(&tokyo_io_backend);
|
||||
} else {
|
||||
hr = E_INVALIDARG;
|
||||
dprintf("IDAC IO: Invalid IO mode \"%S\", use keyboard or xinput\n",
|
||||
tokyo_io_cfg.mode);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void tokyo_io_get_opbtns(uint8_t *opbtn_out)
|
||||
{
|
||||
uint8_t opbtn;
|
||||
|
||||
assert(tokyo_io_backend != NULL);
|
||||
assert(opbtn_out != NULL);
|
||||
|
||||
opbtn = 0;
|
||||
|
||||
/* Common operator buttons, not backend-specific */
|
||||
|
||||
if (GetAsyncKeyState(tokyo_io_cfg.vk_test) & 0x8000) {
|
||||
opbtn |= TOKYO_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_io_cfg.vk_service) & 0x8000) {
|
||||
opbtn |= TOKYO_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_io_cfg.vk_coin) & 0x8000) {
|
||||
if (!tokyo_io_coin) {
|
||||
tokyo_io_coin = true;
|
||||
opbtn |= TOKYO_IO_OPBTN_COIN;
|
||||
}
|
||||
} else {
|
||||
tokyo_io_coin = false;
|
||||
}
|
||||
|
||||
*opbtn_out = opbtn;
|
||||
}
|
||||
|
||||
|
||||
void tokyo_io_get_gamebtns(uint8_t *gamebtn_out)
|
||||
{
|
||||
assert(tokyo_io_backend != NULL);
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
tokyo_io_backend->get_gamebtns(gamebtn_out);
|
||||
}
|
||||
|
||||
void tokyo_io_get_sensors(uint8_t *sense_out)
|
||||
{
|
||||
assert(sense_out != NULL);
|
||||
assert(tokyo_io_backend != NULL);
|
||||
|
||||
tokyo_io_backend->get_sensors(sense_out);
|
||||
}
|
||||
|
||||
HRESULT tokyo_io_led_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void tokyo_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
if (board == 0) {
|
||||
dprintf("Board 0:\n");
|
||||
// Change GRB order to RGB order
|
||||
for (int i = 0; i < 27; i++) {
|
||||
dprintf("Tokyo LED: MONITOR LEFT: %02X %02X %02X\n", rgb[i * 3 + 1], rgb[i * 3], rgb[i * 3 + 2]);
|
||||
}
|
||||
|
||||
for (int i = 27; i < 54; i++) {
|
||||
dprintf("Tokyo LED: MONITOR RIGHT: %d, %02X %02X %02X\n", i, rgb[i * 3 + 1], rgb[i * 3], rgb[i * 3 + 2]);
|
||||
}
|
||||
} else {
|
||||
dprintf("Board 1:\n");
|
||||
dprintf("Tokyo LED: LEFT BLUE: %02X\n", rgb[0]);
|
||||
dprintf("Tokyo LED: CENTER YELLOW: %02X\n", rgb[1]);
|
||||
dprintf("Tokyo LED: RIGHT RED: %02X\n", rgb[2]);
|
||||
dprintf("Tokyo LED: CONTROL LEFT: %02X %02X %02X\n", rgb[3], rgb[4], rgb[5]);
|
||||
dprintf("Tokyo LED: CONTROL RIGHT: %02X %02X %02X\n", rgb[6], rgb[7], rgb[8]);
|
||||
dprintf("Tokyo LED: FLOOR LEFT: %02X %02X %02X\n", rgb[9], rgb[10], rgb[11]);
|
||||
dprintf("Tokyo LED: FLOOR RIGHT: %02X %02X %02X\n", rgb[12], rgb[13], rgb[14]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
135
tokyoio/kb.c
Normal file
135
tokyoio/kb.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tokyoio/backend.h"
|
||||
#include "tokyoio/config.h"
|
||||
#include "tokyoio/kb.h"
|
||||
#include "tokyoio/tokyoio.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static HRESULT tokyo_kb_config_apply(const struct tokyo_kb_config *cfg);
|
||||
|
||||
static void tokyo_kb_get_gamebtns(uint8_t *gamebtn_out);
|
||||
static void tokyo_kb_get_sensors(uint8_t *sense_out);
|
||||
|
||||
static const struct tokyo_io_backend tokyo_kb_backend = {
|
||||
.get_gamebtns = tokyo_kb_get_gamebtns,
|
||||
.get_sensors = tokyo_kb_get_sensors,
|
||||
};
|
||||
|
||||
static struct tokyo_kb_config tokyo_kb_cfg;
|
||||
|
||||
HRESULT tokyo_kb_init(const struct tokyo_kb_config *cfg, const struct tokyo_io_backend **backend)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(backend != NULL);
|
||||
|
||||
hr = tokyo_kb_config_apply(cfg);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("TokyoIO: Using keyboard input\n");
|
||||
*backend = &tokyo_kb_backend;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT tokyo_kb_config_apply(const struct tokyo_kb_config *cfg)
|
||||
{
|
||||
tokyo_kb_cfg = *cfg;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void tokyo_kb_get_gamebtns(uint8_t *gamebtn_out)
|
||||
{
|
||||
uint8_t gamebtn;
|
||||
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
gamebtn = 0;
|
||||
|
||||
/* PUSH BUTTON inputs */
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_left_b) & 0x8000) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_BLUE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_center_y) & 0x8000) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_YELLOW;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_right_r) & 0x8000) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_RED;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void tokyo_kb_get_sensors(uint8_t *sense_out)
|
||||
{
|
||||
uint8_t sense;
|
||||
|
||||
assert(sense_out != NULL);
|
||||
|
||||
sense = 0;
|
||||
|
||||
/* FOOT SENSOR inputs */
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_foot_l) & 0x8000) {
|
||||
sense |= TOKYO_IO_SENSE_FOOT_LEFT;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_foot_r) & 0x8000) {
|
||||
sense |= TOKYO_IO_SENSE_FOOT_RIGHT;
|
||||
}
|
||||
|
||||
/* JUMP SENSOR inputs */
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_1) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_1);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_2) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_2);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_3) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_3);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_4) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_4);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_5) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_5);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_6) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_6);
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_all) & 0x8000) {
|
||||
sense |= (TOKYO_IO_SENSE_FOOT_LEFT+ TOKYO_IO_SENSE_FOOT_RIGHT +
|
||||
TOKYO_IO_SENSE_JUMP_1 + TOKYO_IO_SENSE_JUMP_2 +
|
||||
TOKYO_IO_SENSE_JUMP_3 + TOKYO_IO_SENSE_JUMP_4 +
|
||||
TOKYO_IO_SENSE_JUMP_5 + TOKYO_IO_SENSE_JUMP_6);
|
||||
}
|
||||
|
||||
*sense_out = sense;
|
||||
}
|
10
tokyoio/kb.h
Normal file
10
tokyoio/kb.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "tokyoio/backend.h"
|
||||
#include "tokyoio/config.h"
|
||||
|
||||
HRESULT tokyo_kb_init(
|
||||
const struct tokyo_kb_config *cfg,
|
||||
const struct tokyo_io_backend **backend);
|
21
tokyoio/meson.build
Normal file
21
tokyoio/meson.build
Normal file
@ -0,0 +1,21 @@
|
||||
tokyoio_lib = static_library(
|
||||
'tokyoio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'backend.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'tokyoio.h',
|
||||
'kb.c',
|
||||
'kb.h',
|
||||
'xi.c',
|
||||
'xi.h',
|
||||
],
|
||||
)
|
139
tokyoio/tokyoio.h
Normal file
139
tokyoio/tokyoio.h
Normal file
@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
TOKYO_IO_OPBTN_TEST = 0x01,
|
||||
TOKYO_IO_OPBTN_SERVICE = 0x02,
|
||||
TOKYO_IO_OPBTN_COIN = 0x04,
|
||||
};
|
||||
|
||||
enum {
|
||||
TOKYO_IO_GAMEBTN_BLUE = 0x01,
|
||||
TOKYO_IO_GAMEBTN_YELLOW = 0x02,
|
||||
TOKYO_IO_GAMEBTN_RED = 0x04,
|
||||
};
|
||||
|
||||
enum {
|
||||
TOKYO_IO_SENSE_FOOT_LEFT = 0x01,
|
||||
TOKYO_IO_SENSE_FOOT_RIGHT = 0x02,
|
||||
TOKYO_IO_SENSE_JUMP_1 = 0x04,
|
||||
TOKYO_IO_SENSE_JUMP_2 = 0x08,
|
||||
TOKYO_IO_SENSE_JUMP_3 = 0x10,
|
||||
TOKYO_IO_SENSE_JUMP_4 = 0x20,
|
||||
TOKYO_IO_SENSE_JUMP_5 = 0x40,
|
||||
TOKYO_IO_SENSE_JUMP_6 = 0x80,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* These are the bitmasks to use when checking which
|
||||
lights are triggered on incoming IO4 GPIO writes. */
|
||||
TOKYO_IO_LED_LEFT_BLUE = 1 << 31,
|
||||
TOKYO_IO_LED_CENTER_YELLOW = 1 << 30,
|
||||
TOKYO_IO_LED_RIGHT_RED = 1 << 29,
|
||||
TOKYO_IO_LED_CONTROL_LEFT_R = 1 << 25,
|
||||
TOKYO_IO_LED_CONTROL_LEFT_G = 1 << 24,
|
||||
TOKYO_IO_LED_CONTROL_LEFT_B = 1 << 23,
|
||||
TOKYO_IO_LED_CONTROL_RIGHT_R = 1 << 22,
|
||||
TOKYO_IO_LED_CONTROL_RIGHT_G = 1 << 21,
|
||||
TOKYO_IO_LED_CONTROL_RIGHT_B = 1 << 20,
|
||||
TOKYO_IO_LED_FLOOR_LEFT_R = 1 << 19,
|
||||
TOKYO_IO_LED_FLOOR_LEFT_G = 1 << 18,
|
||||
TOKYO_IO_LED_FLOOR_LEFT_B = 1 << 17,
|
||||
TOKYO_IO_LED_FLOOR_RIGHT_R = 1 << 16,
|
||||
TOKYO_IO_LED_FLOOR_RIGHT_G = 1 << 15,
|
||||
TOKYO_IO_LED_FLOOR_RIGHT_B = 1 << 14,
|
||||
};
|
||||
|
||||
/* Get the version of the Mario & Sonic at the Olympic Games Tokyo 2020 Arcade
|
||||
Edition 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 tokyo_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after tokyo_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT tokyo_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 tokyo_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
TOKYO_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 tokyo_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
TOKYO_IO_GAMEBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *gamebtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void tokyo_io_get_gamebtns(uint8_t *gamebtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
TOKYO_IO_SENSE enum above: this contains bit mask definitions for button
|
||||
states returned in *sense. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void tokyo_io_get_sensors(uint8_t *sense);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other tokyo_io_led_*() function calls.
|
||||
|
||||
All subsequent calls may originate from arbitrary threads and some may
|
||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||
your responsibility.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT tokyo_io_led_init(void);
|
||||
|
||||
/* Update the RGB LEDs. rgb is a pointer to an array of up to 54 * 3 = 162 bytes.
|
||||
|
||||
Mario & Sonic at the Tokyo 2020 Olympics Arcade uses one board with 15 LEDs for
|
||||
all buttons, control panel, and floor LEDs. Board 1 is just used for the
|
||||
left and right monitor LEDs.
|
||||
|
||||
Board 0 has 54 LEDs (GRB order):
|
||||
[0]-[26]: left monitor LEDs
|
||||
[27]-[53]: right monitor LEDs
|
||||
|
||||
Board 1 has 15 LEDs (RGB order):
|
||||
[0]: left blue LED
|
||||
[1]: center yellow LED
|
||||
[2]: right red LED
|
||||
[3]-[5]: left control panel LEDs
|
||||
[6]-[8]: right control panel LEDs
|
||||
[9]-[11]: left floor LEDs
|
||||
[12]-[14]: right floor LEDs
|
||||
|
||||
Each rgb value is comprised of 3 bytes in G,R,B order for board 0 and R,G,B
|
||||
order for board 1. The tricky part is that the board 0 is called from app and
|
||||
the board 1 is called from amdaemon. So the library must be able to handle both
|
||||
calls, using shared memory f.e. This is up to the developer to decide how to
|
||||
handle this, recommended way is to use the amdaemon process as the main one
|
||||
and the app process as a sub one.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void tokyo_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
130
tokyoio/xi.c
Normal file
130
tokyoio/xi.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tokyoio/backend.h"
|
||||
#include "tokyoio/config.h"
|
||||
#include "tokyoio/tokyoio.h"
|
||||
#include "tokyoio/xi.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static void tokyo_xi_get_gamebtns(uint8_t *gamebtn_out);
|
||||
static void tokyo_xi_get_sensors(uint8_t *sense_out);
|
||||
|
||||
static const struct tokyo_io_backend tokyo_xi_backend = {
|
||||
.get_gamebtns = tokyo_xi_get_gamebtns,
|
||||
.get_sensors = tokyo_xi_get_sensors,
|
||||
};
|
||||
|
||||
HRESULT tokyo_xi_init(const struct tokyo_io_backend **backend)
|
||||
{
|
||||
wchar_t dll_path[MAX_PATH];
|
||||
HMODULE xinput;
|
||||
HRESULT hr;
|
||||
UINT path_pos;
|
||||
|
||||
assert(backend != NULL);
|
||||
|
||||
dprintf("TokyoIO: IO4: Using XInput controller\n");
|
||||
*backend = &tokyo_xi_backend;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void tokyo_xi_get_gamebtns(uint8_t *gamebtn_out)
|
||||
{
|
||||
uint8_t gamebtn;
|
||||
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
gamebtn = 0;
|
||||
|
||||
XINPUT_STATE xi;
|
||||
WORD xb;
|
||||
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
xb = xi.Gamepad.wButtons;
|
||||
|
||||
/* PUSH BUTTON inputs */
|
||||
|
||||
if ((xb & XINPUT_GAMEPAD_X) || (xb & XINPUT_GAMEPAD_DPAD_LEFT)) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_BLUE;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_Y || (xb & XINPUT_GAMEPAD_A)) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_YELLOW;
|
||||
}
|
||||
|
||||
if ((xb & XINPUT_GAMEPAD_B) || (xb & XINPUT_GAMEPAD_DPAD_RIGHT)) {
|
||||
gamebtn |= TOKYO_IO_GAMEBTN_RED;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void tokyo_xi_get_sensors(uint8_t *sense_out)
|
||||
{
|
||||
uint8_t sense;
|
||||
|
||||
XINPUT_STATE xi;
|
||||
WORD xb;
|
||||
BYTE xt_l;
|
||||
BYTE xt_r;
|
||||
|
||||
assert(sense_out != NULL);
|
||||
|
||||
sense = 0;
|
||||
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
xb = xi.Gamepad.wButtons;
|
||||
xt_l = xi.Gamepad.bLeftTrigger;
|
||||
xt_r = xi.Gamepad.bRightTrigger;
|
||||
|
||||
float xt_l_f = xt_l / 255.0f;
|
||||
float xt_r_f = xt_r / 255.0f;
|
||||
|
||||
// Normalize both triggers to 0..1 and find the max directly
|
||||
float trigger = fmaxf(xt_l_f, xt_r_f);
|
||||
|
||||
const int max_jump_levels = 6;
|
||||
float jump_threshold = 1.0f / max_jump_levels;
|
||||
|
||||
/* FOOT SENSOR inputs */
|
||||
|
||||
// Determine if both foot sensors should be set
|
||||
bool left_active = xt_l_f > jump_threshold;
|
||||
bool right_active = xt_r_f > jump_threshold;
|
||||
|
||||
// Set foot sensors based on individual trigger activity
|
||||
if (left_active) {
|
||||
sense |= TOKYO_IO_SENSE_FOOT_LEFT;
|
||||
}
|
||||
if (right_active) {
|
||||
sense |= TOKYO_IO_SENSE_FOOT_RIGHT;
|
||||
}
|
||||
|
||||
/* JUMP SENSOR inputs */
|
||||
|
||||
// If both triggers are active, set jump levels and both foot sensors
|
||||
if (left_active && right_active) {
|
||||
float trigger_avg = (xt_l_f + xt_r_f) / 2.0f;
|
||||
|
||||
// Calculate the appropriate jump level
|
||||
for (int i = 1; i <= max_jump_levels; ++i) {
|
||||
if (trigger_avg >= i * jump_threshold) {
|
||||
sense |= (TOKYO_IO_SENSE_JUMP_1 << (i - 1));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*sense_out = sense;
|
||||
}
|
8
tokyoio/xi.h
Normal file
8
tokyoio/xi.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "tokyoio/backend.h"
|
||||
#include "tokyoio/config.h"
|
||||
|
||||
HRESULT tokyo_xi_init(const struct tokyo_io_backend **backend);
|
@ -1,6 +1,8 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "platform/clock.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hook/iohook.h"
|
||||
@ -139,11 +141,14 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
|
||||
dll_hook_insert_hooks(result);
|
||||
path_hook_insert_hooks(result);
|
||||
|
||||
// printer_hook_insert_hooks(result);
|
||||
reg_hook_insert_hooks(result);
|
||||
clock_hook_insert_hooks(result);
|
||||
proc_addr_insert_hooks(result);
|
||||
serial_hook_apply_hooks(result);
|
||||
iohook_apply_hooks(result);
|
||||
|
||||
// Not needed?
|
||||
// serial_hook_apply_hooks(result);
|
||||
// Unity will crash during option loading when we hook this twice
|
||||
// iohook_apply_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user