forked from Hay1tsme/segatools
Compare commits
30 Commits
2024-02-22
...
2024-06-30
Author | SHA1 | Date | |
---|---|---|---|
965126c68a
|
|||
050951e56f
|
|||
7e5e0f132e
|
|||
4e58d3b9a2
|
|||
b0f307f427
|
|||
7aa996193c | |||
9353c9872f | |||
d8b3d41809
|
|||
3bfb046afc
|
|||
9fe98b227b
|
|||
b77ce7b457
|
|||
517469a60c
|
|||
1069cfee26 | |||
d3a0faa530 | |||
00b3d5b7bb
|
|||
04fcd0d09a
|
|||
25e954fb55 | |||
a8c6ac70e4 | |||
eb1ec0e261
|
|||
482a6e530a | |||
65173e1fa6 | |||
4041844ea9 | |||
47a65e5e51
|
|||
774a639bb7
|
|||
097b74d849
|
|||
2590e749ca
|
|||
9c66488906
|
|||
f570869946
|
|||
629ded4018 | |||
ca36a879cb
|
30
README.md
30
README.md
@ -1,33 +1,33 @@
|
||||
# Segatools
|
||||
|
||||
Version: `2023-11-22`
|
||||
Version: `2024-03-13`
|
||||
|
||||
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
|
||||
|
||||
## List of supported games
|
||||
|
||||
* Chunithm
|
||||
* [Chunithm (Plus)](doc/chunihook.md)
|
||||
* [Chunithm Air (Plus)](doc/chunihook.md)
|
||||
* [Chunithm Star (Plus)](doc/chunihook.md)
|
||||
* [Chunithm Amazon (Plus)](doc/chunihook.md)
|
||||
* [Chunithm Crystal (Plus)](doc/chunihook.md)
|
||||
* Chunithm SUN
|
||||
* CHUNITHM
|
||||
* up to [CHUNITHM PARADISE LOST](doc/chunihook.md)
|
||||
* starting from CHUNITHM NEW!!
|
||||
* crossbeats REV.
|
||||
* up to crossbeats REV. SUNRISE
|
||||
* 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
|
||||
* up to SEGA World Drivers Championship 2019
|
||||
* SEGA World Drivers Championship 2019
|
||||
* Fate/Grand Order
|
||||
* Fate/Grand Order Arcade
|
||||
* ONGEKI
|
||||
* up to bright MEMORY
|
||||
* O.N.G.E.K.I.
|
||||
* starting from O.N.G.E.K.I.
|
||||
* maimai DX
|
||||
* up to maimai DX FESTiVAL PLUS
|
||||
* starting from maimai DX
|
||||
* Card Maker
|
||||
* up to Card Maker 1.35
|
||||
* Wacca
|
||||
* up to WACCA Reverse
|
||||
* starting from Card Maker
|
||||
* WACCA
|
||||
* starting from WACCA
|
||||
|
||||
## End-users
|
||||
|
||||
|
@ -68,7 +68,6 @@ static void aime_io_config_read(
|
||||
cfg->felica_path,
|
||||
_countof(cfg->felica_path),
|
||||
filename);
|
||||
// dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError());
|
||||
|
||||
cfg->felica_gen = GetPrivateProfileIntW(
|
||||
L"aime",
|
||||
|
69
board/io3.c
69
board/io3.c
@ -79,6 +79,11 @@ static HRESULT io3_cmd_read_analogs(
|
||||
struct const_iobuf *req_buf,
|
||||
struct iobuf *resp_buf);
|
||||
|
||||
static HRESULT io3_cmd_read_rotarys(
|
||||
struct io3 *io3,
|
||||
struct const_iobuf *req_buf,
|
||||
struct iobuf *resp_buf);
|
||||
|
||||
static HRESULT io3_cmd_write_gpio(
|
||||
struct io3 *io3,
|
||||
struct const_iobuf *req_buf,
|
||||
@ -116,6 +121,13 @@ static uint8_t io3_features[] = {
|
||||
|
||||
0x03, 8, 10, 0,
|
||||
|
||||
/* Feature : 0x04 : Rotary inputs
|
||||
Param1 : 4 : Number of rotary channels
|
||||
Param2 : 0 : N/A
|
||||
Param3 : 0 : N/A */
|
||||
|
||||
0x04, 4, 0, 0,
|
||||
|
||||
/* Feature : 0x12 : GPIO outputs
|
||||
Param1 : 3 : Number of ports (8 bits per port)
|
||||
Param2 : 0 : N/A
|
||||
@ -218,6 +230,9 @@ 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);
|
||||
|
||||
case JVS_CMD_WRITE_GPIO:
|
||||
return io3_cmd_write_gpio(io3, req, resp);
|
||||
@ -536,6 +551,60 @@ static HRESULT io3_cmd_read_analogs(
|
||||
|
||||
}
|
||||
|
||||
static HRESULT io3_cmd_read_rotarys(
|
||||
struct io3 *io3,
|
||||
struct const_iobuf *req_buf,
|
||||
struct iobuf *resp_buf)
|
||||
{
|
||||
struct jvs_req_read_rotarys req;
|
||||
uint16_t rotarys[4];
|
||||
uint8_t i;
|
||||
HRESULT hr;
|
||||
|
||||
/* Read req */
|
||||
|
||||
hr = iobuf_read(req_buf, &req, sizeof(req));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (req.nrotarys > _countof(rotarys)) {
|
||||
dprintf("JVS I/O: Invalid analog count %i\n", req.nrotarys);
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
//dprintf("JVS I/O: Read rotarys, nrotarys=%i\n", req.nrotarys);
|
||||
|
||||
/* Write report byte */
|
||||
|
||||
hr = iobuf_write_8(resp_buf, 0x01);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Write analogs */
|
||||
|
||||
memset(rotarys, 0, sizeof(rotarys));
|
||||
|
||||
if (io3->ops->read_rotarys != NULL) {
|
||||
io3->ops->read_rotarys(io3->ops_ctx, rotarys, req.nrotarys);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < req.nrotarys ; i++) {
|
||||
hr = iobuf_write_be16(resp_buf, rotarys[i]);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
||||
}
|
||||
|
||||
static HRESULT io3_cmd_write_gpio(
|
||||
struct io3 *io3,
|
||||
struct const_iobuf *req_buf,
|
||||
|
@ -18,6 +18,7 @@ struct io3_ops {
|
||||
void (*write_gpio)(void *ctx, uint32_t state);
|
||||
void (*read_switches)(void *ctx, struct io3_switch_state *out);
|
||||
void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs);
|
||||
void (*read_rotarys)(void *ctx, uint16_t *rotaries, uint8_t nrotaries);
|
||||
void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out);
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
|
||||
struct io4_report_out {
|
||||
uint8_t report_id;
|
||||
uint8_t cmd;
|
||||
uint8_t payload[62];
|
||||
uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
|
||||
@ -223,7 +223,11 @@ static HRESULT io4_handle_write(struct irp *irp)
|
||||
return S_OK;
|
||||
|
||||
case IO4_CMD_SET_GENERAL_OUTPUT:
|
||||
dprintf("USB I/O: GPIO Out\n");
|
||||
// dprintf("USB I/O: GPIO Out\n");
|
||||
|
||||
if (io4_ops->write_gpio != NULL) {
|
||||
return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define IO4_REPORT_OUT_PAYLOAD_LEN 62
|
||||
|
||||
enum {
|
||||
/* System buttons in button[0] */
|
||||
|
||||
@ -24,6 +26,7 @@ struct io4_state {
|
||||
|
||||
struct io4_ops {
|
||||
HRESULT (*poll)(void *ctx, struct io4_state *state);
|
||||
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
|
||||
};
|
||||
|
||||
HRESULT io4_hook_init(
|
||||
|
81
board/led15070-cmd.h
Normal file
81
board/led15070-cmd.h
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "board/led15070-frame.h"
|
||||
|
||||
/* Command IDs */
|
||||
|
||||
enum {
|
||||
LED_15070_CMD_RESET = 0x10,
|
||||
LED_15070_CMD_SET_INPUT = 0x28, // No known use case
|
||||
LED_15070_CMD_SET_NORMAL_12BIT = 0x30, // TODO
|
||||
LED_15070_CMD_SET_NORMAL_8BIT = 0x31,
|
||||
LED_15070_CMD_SET_MULTI_FLASH_8BIT = 0x32,
|
||||
LED_15070_CMD_SET_MULTI_FADE_8BIT = 0x33,
|
||||
LED_15070_CMD_SET_PALETTE_7_NORMAL_LED = 0x34, // No known use case
|
||||
LED_15070_CMD_SET_PALETTE_6_FLASH_LED = 0x35, // No known use case
|
||||
LED_15070_CMD_SET_15DC_OUT = 0x36, // No known use case
|
||||
LED_15070_CMD_SET_15GS_OUT = 0x37, // No known use case
|
||||
LED_15070_CMD_SET_PSC_MAX = 0x38, // No known use case
|
||||
LED_15070_CMD_SET_FET_OUTPUT = 0x39,
|
||||
LED_15070_CMD_SET_GS_PALETTE = 0x3A,
|
||||
LED_15070_CMD_DC_UPDATE = 0x3B,
|
||||
LED_15070_CMD_GS_UPDATE = 0x3C,
|
||||
LED_15070_CMD_ROTATE = 0x3E, // No known use case, wtf is this?
|
||||
LED_15070_CMD_SET_DC_DATA = 0x3F,
|
||||
LED_15070_CMD_EEPROM_WRITE = 0x7B,
|
||||
LED_15070_CMD_EEPROM_READ = 0x7C,
|
||||
LED_15070_CMD_ACK_ON = 0x7D,
|
||||
LED_15070_CMD_ACK_OFF = 0x7E,
|
||||
LED_15070_CMD_BOARD_INFO = 0xF0,
|
||||
LED_15070_CMD_BOARD_STATUS = 0xF1,
|
||||
LED_15070_CMD_FW_SUM = 0xF2,
|
||||
LED_15070_CMD_PROTOCOL_VER = 0xF3,
|
||||
LED_15070_CMD_TO_BOOT_MODE = 0xFD,
|
||||
LED_15070_CMD_FW_UPDATE = 0xFE,
|
||||
};
|
||||
|
||||
/* Response codes */
|
||||
|
||||
enum {
|
||||
LED_15070_STATUS_OK = 0x01,
|
||||
LED_15070_STATUS_SUM_ERR = 0x02,
|
||||
LED_15070_STATUS_PARITY_ERR = 0x03,
|
||||
LED_15070_STATUS_FRAMING_ERR = 0x04,
|
||||
LED_15070_STATUS_OVERRUN_ERR = 0x05,
|
||||
LED_15070_STATUS_BUFFER_OVERFLOW = 0x06,
|
||||
};
|
||||
|
||||
enum {
|
||||
LED_15070_REPORT_OK = 0x01,
|
||||
LED_15070_REPORT_WAIT = 0x02,
|
||||
LED_15070_REPORT_ERR1 = 0x03,
|
||||
LED_15070_REPORT_ERR2 = 0x04,
|
||||
};
|
||||
|
||||
/* Request data structures */
|
||||
|
||||
struct led15070_req_any {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t cmd;
|
||||
uint8_t payload[256];
|
||||
};
|
||||
|
||||
/* Response data structures */
|
||||
|
||||
struct led15070_resp_any {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t status;
|
||||
uint8_t cmd;
|
||||
uint8_t report;
|
||||
uint8_t data[32];
|
||||
};
|
||||
|
||||
struct led15070_resp_board_info {
|
||||
struct led15070_hdr hdr;
|
||||
uint8_t status;
|
||||
uint8_t cmd;
|
||||
uint8_t report;
|
||||
char board_num[8];
|
||||
uint8_t endcode; // Always 0xFF
|
||||
uint8_t fw_ver;
|
||||
};
|
194
board/led15070-frame.c
Normal file
194
board/led15070-frame.c
Normal file
@ -0,0 +1,194 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/led15070-frame.h"
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
static void led15070_frame_sync(struct iobuf *src);
|
||||
static HRESULT led15070_frame_accept(const struct iobuf *dest);
|
||||
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte);
|
||||
|
||||
/* Frame structure:
|
||||
|
||||
[0] Sync byte (0xE0)
|
||||
[1] Destination address
|
||||
[2] Source Address
|
||||
[3] Length of data/payload
|
||||
[4] Data/payload
|
||||
For requests (host to board):
|
||||
[0] Command
|
||||
... Payload
|
||||
For responses (board to host):
|
||||
[0] Status
|
||||
[1] Command
|
||||
[2] Report
|
||||
... Payload
|
||||
[n] Checksum: Sum of all prior bytes (excluding sync byte)
|
||||
|
||||
Byte stuffing:
|
||||
|
||||
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
|
||||
|
||||
static void led15070_frame_sync(struct iobuf *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++);
|
||||
|
||||
src->pos -= i;
|
||||
memmove(&src->bytes[0], &src->bytes[i], i);
|
||||
}
|
||||
|
||||
static HRESULT led15070_frame_accept(const struct iobuf *dest)
|
||||
{
|
||||
uint8_t checksum;
|
||||
size_t i;
|
||||
|
||||
if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
checksum = 0;
|
||||
|
||||
for (i = 1 ; i < dest->pos - 1 ; i++) {
|
||||
checksum += dest->bytes[i];
|
||||
}
|
||||
|
||||
//dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]);
|
||||
|
||||
if (checksum != dest->bytes[dest->pos - 1]) {
|
||||
return HRESULT_FROM_WIN32(ERROR_CRC);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src)
|
||||
{
|
||||
uint8_t byte;
|
||||
bool escape;
|
||||
size_t i;
|
||||
HRESULT hr;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(src != NULL);
|
||||
assert(src->bytes != NULL || src->nbytes == 0);
|
||||
assert(src->pos <= src->nbytes);
|
||||
|
||||
led15070_frame_sync(src);
|
||||
|
||||
dest->pos = 0;
|
||||
escape = false;
|
||||
|
||||
for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) {
|
||||
/* Step the FSM to unstuff another byte */
|
||||
|
||||
byte = src->bytes[i];
|
||||
|
||||
if (dest->pos >= dest->nbytes) {
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
} else if (i == 0) {
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
} else if (byte == 0xE0) {
|
||||
hr = E_FAIL;
|
||||
} else if (byte == 0xD0) {
|
||||
if (escape) {
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
escape = true;
|
||||
} else if (escape) {
|
||||
dest->bytes[dest->pos++] = byte + 1;
|
||||
escape = false;
|
||||
} else {
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
}
|
||||
|
||||
/* Try to accept the packet we've built up so far */
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = led15070_frame_accept(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle FSM terminal state */
|
||||
|
||||
if (hr != S_FALSE) {
|
||||
/* Frame was either accepted or rejected, remove it from src */
|
||||
memmove(&src->bytes[0], &src->bytes[i], src->pos - i);
|
||||
src->pos -= i;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT led15070_frame_encode(
|
||||
struct iobuf *dest,
|
||||
const void *ptr,
|
||||
size_t nbytes)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint8_t checksum;
|
||||
uint8_t byte;
|
||||
size_t i;
|
||||
HRESULT hr;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(ptr != NULL);
|
||||
|
||||
src = ptr;
|
||||
|
||||
assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes);
|
||||
|
||||
if (dest->pos >= dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = 0xE0;
|
||||
checksum = 0;
|
||||
// dprintf("%02x ", 0xe0);
|
||||
|
||||
for (i = 1 ; i < nbytes ; i++) {
|
||||
byte = src[i];
|
||||
checksum += byte;
|
||||
// dprintf("%02x ", byte);
|
||||
|
||||
hr = led15070_frame_encode_byte(dest, byte);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// dprintf("%02x \n", checksum);
|
||||
|
||||
return led15070_frame_encode_byte(dest, checksum);
|
||||
}
|
||||
|
||||
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte)
|
||||
{
|
||||
if (byte == 0xE0 || byte == 0xD0) {
|
||||
if (dest->pos + 2 > dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = 0xD0;
|
||||
dest->bytes[dest->pos++] = byte - 1;
|
||||
} else {
|
||||
if (dest->pos + 1 > dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
26
board/led15070-frame.h
Normal file
26
board/led15070-frame.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
enum {
|
||||
LED_15070_FRAME_SYNC = 0xE0,
|
||||
};
|
||||
|
||||
struct led15070_hdr {
|
||||
uint8_t sync;
|
||||
uint8_t dest_adr;
|
||||
uint8_t src_adr;
|
||||
uint8_t nbytes;
|
||||
};
|
||||
|
||||
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src);
|
||||
|
||||
HRESULT led15070_frame_encode(
|
||||
struct iobuf *dest,
|
||||
const void *ptr,
|
||||
size_t nbytes);
|
1250
board/led15070.c
Normal file
1250
board/led15070.c
Normal file
File diff suppressed because it is too large
Load Diff
29
board/led15070.h
Normal file
29
board/led15070.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct led15070_config {
|
||||
bool enable;
|
||||
unsigned int port_no;
|
||||
char board_number[8];
|
||||
uint8_t fw_ver;
|
||||
uint16_t fw_sum;
|
||||
wchar_t eeprom_path[MAX_PATH];
|
||||
};
|
||||
|
||||
typedef HRESULT (*io_led_init_t)(void);
|
||||
typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb);
|
||||
typedef void (*io_led_dc_update_t)(const uint8_t *rgb);
|
||||
typedef void (*io_led_gs_update_t)(const uint8_t *rgb);
|
||||
|
||||
HRESULT led15070_hook_init(
|
||||
const struct led15070_config *cfg,
|
||||
io_led_init_t _led_init,
|
||||
io_led_set_fet_output_t _led_set_fet_output,
|
||||
io_led_dc_update_t _led_dc_update,
|
||||
io_led_gs_update_t _led_gs_update,
|
||||
unsigned int first_port,
|
||||
unsigned int num_boards);
|
@ -25,6 +25,11 @@ board_lib = static_library(
|
||||
'led15093-frame.h',
|
||||
'led15093.c',
|
||||
'led15093.h',
|
||||
'led15070-cmd.h',
|
||||
'led15070-frame.c',
|
||||
'led15070-frame.h',
|
||||
'led15070.c',
|
||||
'led15070.h',
|
||||
'sg-cmd.c',
|
||||
'sg-cmd.h',
|
||||
'sg-frame.c',
|
||||
|
@ -25,6 +25,13 @@ struct sg_res_header {
|
||||
uint8_t payload_len;
|
||||
};
|
||||
|
||||
/* struct to save the version string with its length
|
||||
to fix NUL terminator issues */
|
||||
struct version_info {
|
||||
const char *version;
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
typedef HRESULT (*sg_dispatch_fn_t)(
|
||||
void *ctx,
|
||||
const void *req,
|
||||
|
@ -27,11 +27,11 @@ static HRESULT sg_led_cmd_set_color(
|
||||
const struct sg_led *led,
|
||||
const struct sg_led_req_set_color *req);
|
||||
|
||||
const char *sg_led_info[] = {
|
||||
"15084\xFF\x10\x00\x12",
|
||||
"000-00000\xFF\x11\x40",
|
||||
static const struct version_info led_version[] = {
|
||||
{"15084\xFF\x10\x00\x12", 9},
|
||||
{"000-00000\xFF\x11\x40", 12},
|
||||
// maybe the same?
|
||||
"000-00000\xFF\x11\x40"
|
||||
{"000-00000\xFF\x11\x40", 12}
|
||||
};
|
||||
|
||||
void sg_led_init(
|
||||
@ -156,10 +156,10 @@ static HRESULT sg_led_cmd_get_info(
|
||||
{
|
||||
sg_led_dprintf(led, "Get info\n");
|
||||
|
||||
unsigned int len = strlen(sg_led_info[led->gen - 1]);
|
||||
const struct version_info *fw = &led_version[led->gen - 1];
|
||||
|
||||
sg_res_init(&res->res, req, len);
|
||||
memcpy(res->payload, sg_led_info[led->gen - 1], len);
|
||||
sg_res_init(&res->res, req, fw->length);
|
||||
memcpy(res->payload, fw->version, fw->length);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -65,16 +65,16 @@ static HRESULT sg_nfc_cmd_dummy(
|
||||
const struct sg_req_header *req,
|
||||
struct sg_res_header *res);
|
||||
|
||||
static const char *hw_version[] = {
|
||||
"TN32MSEC003S H/W Ver3.0",
|
||||
"837-15286",
|
||||
"837-15396"
|
||||
static const struct version_info hw_version[] = {
|
||||
{"TN32MSEC003S H/W Ver3.0", 23},
|
||||
{"837-15286", 9},
|
||||
{"837-15396", 9}
|
||||
};
|
||||
|
||||
static const char *fw_version[] = {
|
||||
"TN32MSEC003S F/W Ver1.2",
|
||||
"\x94",
|
||||
"\x94"
|
||||
static const struct version_info fw_version[] = {
|
||||
{"TN32MSEC003S F/W Ver1.2", 23},
|
||||
{"\x94", 1},
|
||||
{"\x94", 1}
|
||||
};
|
||||
|
||||
void sg_nfc_init(
|
||||
@ -217,11 +217,11 @@ static HRESULT sg_nfc_cmd_get_fw_version(
|
||||
const struct sg_req_header *req,
|
||||
struct sg_nfc_res_get_fw_version *res)
|
||||
{
|
||||
unsigned int len = strlen(fw_version[nfc->gen - 1]);
|
||||
const struct version_info *fw = &fw_version[nfc->gen - 1];
|
||||
|
||||
/* Dest version is not NUL terminated, this is intentional */
|
||||
sg_res_init(&res->res, req, len);
|
||||
memcpy(res->version, fw_version[nfc->gen - 1], len);
|
||||
sg_res_init(&res->res, req, fw->length);
|
||||
memcpy(res->version, fw->version, fw->length);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@ -231,11 +231,11 @@ static HRESULT sg_nfc_cmd_get_hw_version(
|
||||
const struct sg_req_header *req,
|
||||
struct sg_nfc_res_get_hw_version *res)
|
||||
{
|
||||
unsigned int len = strlen(hw_version[nfc->gen - 1]);
|
||||
const struct version_info *hw = &hw_version[nfc->gen - 1];
|
||||
|
||||
/* Dest version is not NUL terminated, this is intentional */
|
||||
sg_res_init(&res->res, req, len);
|
||||
memcpy(res->version, hw_version[nfc->gen - 1], len);
|
||||
sg_res_init(&res->res, req, hw->length);
|
||||
memcpy(res->version, hw->version, hw->length);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
58
board/vfd.c
58
board/vfd.c
@ -26,6 +26,7 @@ static HRESULT vfd_handle_irp(struct irp *irp);
|
||||
static struct uart vfd_uart;
|
||||
static uint8_t vfd_written[512];
|
||||
static uint8_t vfd_readable[512];
|
||||
UINT codepage;
|
||||
|
||||
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
|
||||
{
|
||||
@ -41,6 +42,7 @@ HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
|
||||
vfd_uart.readable.bytes = vfd_readable;
|
||||
vfd_uart.readable.nbytes = sizeof(vfd_readable);
|
||||
|
||||
codepage = GetACP();
|
||||
dprintf("VFD: hook enabled.\n");
|
||||
|
||||
return iohook_push_handler(vfd_handle_irp);
|
||||
@ -62,8 +64,60 @@ static HRESULT vfd_handle_irp(struct irp *irp)
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("VFD TX:\n");
|
||||
dump_iobuf(&vfd_uart.written);
|
||||
uint8_t cmd = 0;
|
||||
uint8_t str_1[512];
|
||||
uint8_t str_2[512];
|
||||
uint8_t str_1_len = 0;
|
||||
uint8_t str_2_len = 0;
|
||||
for (size_t i = 0; i < vfd_uart.written.pos; i++) {
|
||||
if (vfd_uart.written.bytes[i] == 0x1B) {
|
||||
i++;
|
||||
cmd = vfd_uart.written.bytes[i];
|
||||
if (cmd == 0x30) {
|
||||
i += 3;
|
||||
}
|
||||
else if (cmd == 0x50) {
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (cmd == 0x30) {
|
||||
str_1[str_1_len++] = vfd_uart.written.bytes[i];
|
||||
}
|
||||
else if (cmd == 0x50) {
|
||||
str_2[str_2_len++] = vfd_uart.written.bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (str_1_len) {
|
||||
str_1[str_1_len++] = '\0';
|
||||
if (codepage != 932) {
|
||||
WCHAR buffer[512];
|
||||
MultiByteToWideChar(932, 0, (LPCSTR)str_1, str_1_len, buffer, str_1_len);
|
||||
char str_recode[str_1_len * 3];
|
||||
WideCharToMultiByte(codepage, 0, buffer, str_1_len, str_recode, str_1_len * 3, NULL, NULL);
|
||||
dprintf("VFD: %s\n", str_recode);
|
||||
}
|
||||
else {
|
||||
dprintf("VFD: %s\n", str_1);
|
||||
}
|
||||
}
|
||||
|
||||
if (str_2_len) {
|
||||
str_2[str_2_len++] = '\0';
|
||||
if (codepage != 932) {
|
||||
WCHAR buffer[512];
|
||||
MultiByteToWideChar(932, 0, (LPCSTR)str_2, str_2_len, buffer, str_2_len);
|
||||
char str_recode[str_2_len * 3];
|
||||
WideCharToMultiByte(codepage, 0, buffer, str_2_len, str_recode, str_2_len * 3, NULL, NULL);
|
||||
dprintf("VFD: %s\n", str_recode);
|
||||
} else {
|
||||
dprintf("VFD: %s\n", str_2);
|
||||
}
|
||||
}
|
||||
|
||||
// dprintf("VFD TX:\n");
|
||||
// dump_iobuf(&vfd_uart.written);
|
||||
vfd_uart.written.pos = 0;
|
||||
|
||||
return hr;
|
||||
|
@ -1,3 +1,31 @@
|
||||
/*
|
||||
"Wonderland Wars" (carol*) hook
|
||||
|
||||
Devices:
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
|
||||
[Satellite]
|
||||
|
||||
USB: "WinTouch" Controller Board
|
||||
^ (DIPSW2 ON, Version 5.xx.xx or above)
|
||||
COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board
|
||||
^ (DIPSW2 OFF)
|
||||
COM10: TN32MSEC003S "Gen 1" Aime Reader
|
||||
OR
|
||||
837-15286 "Gen 2" Aime Reader
|
||||
^ (Version 1.6x.xx or above)
|
||||
COM11: 837-15070-02 LED Controller Board
|
||||
COM12: 837-15312 Pen Controller I/O Board
|
||||
|
||||
[Terminal]
|
||||
|
||||
COM10: 837-15286 "Gen 2" Aime Reader
|
||||
|
||||
*: SEGA's abbreviation for Lewis Carroll, author of Alice's Adventures in
|
||||
Wonderland.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -1,3 +1,15 @@
|
||||
/*
|
||||
"CHUNITHM" (chuni) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
COM1: 837-15330 Ground Slider
|
||||
COM10: 837-15093-06 LED Controller Board
|
||||
COM11: 837-15093-06 LED Controller Board
|
||||
COM12: TN32MSEC003S "Gen 1" Aime Reader
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -163,9 +163,17 @@ HRESULT chuni_io_led_init(void);
|
||||
Chunithm uses two chains/boards with WS2811 protocol (each logical led corresponds to 3 physical leds).
|
||||
board 0 is on the left side and board 1 on the right side of the cab
|
||||
|
||||
left side has 5*10 rgb values for the billboard, followed by 3 rgb values for the air tower
|
||||
right side has 6*10 rgb values for the billboard, followed by 3 rgb values for the air tower
|
||||
Board 0 has 53 LEDs:
|
||||
[0]-[49]: snakes through left half of billboard (first column starts at top)
|
||||
[50]-[52]: left side partition LEDs
|
||||
|
||||
Board 1 has 63 LEDs:
|
||||
[0]-[59]: right half of billboard (first column starts at bottom)
|
||||
[60]-[62]: right side partition LEDs
|
||||
|
||||
Board 2 is the slider and has 31 LEDs:
|
||||
[0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||
|
||||
Each rgb value is comprised of 3 bytes in R,G,B order
|
||||
|
||||
NOTE: billboard strips have alternating direction (bottom to top, top to bottom, ...)
|
||||
|
@ -57,11 +57,11 @@ void chuni_io_config_load(
|
||||
filename);
|
||||
}
|
||||
|
||||
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||
cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||
cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||
|
||||
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||
cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
||||
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->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
||||
|
||||
@ -70,7 +70,7 @@ void chuni_io_config_load(
|
||||
L"serialPort",
|
||||
L"COM5",
|
||||
port_input,
|
||||
6,
|
||||
_countof(port_input),
|
||||
filename);
|
||||
|
||||
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
|
||||
|
@ -12,16 +12,15 @@ struct chuni_io_config {
|
||||
uint8_t vk_cell[32];
|
||||
|
||||
// Which ways to output LED information are enabled
|
||||
bool led_output_pipe;
|
||||
bool led_output_serial;
|
||||
bool cab_led_output_pipe;
|
||||
bool cab_led_output_serial;
|
||||
|
||||
bool slider_led_output_pipe;
|
||||
bool slider_led_output_serial;
|
||||
bool controller_led_output_pipe;
|
||||
bool controller_led_output_serial;
|
||||
|
||||
// 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;
|
||||
|
||||
};
|
||||
|
||||
void chuni_io_config_load(
|
||||
|
@ -48,15 +48,15 @@ HRESULT led_output_init(struct chuni_io_config* const cfg)
|
||||
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
||||
}
|
||||
|
||||
any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe
|
||||
|| config->led_output_serial || config->slider_led_output_serial;
|
||||
any_outputs_enabled = config->cab_led_output_pipe || config->controller_led_output_pipe
|
||||
|| config->cab_led_output_serial || config->controller_led_output_serial;
|
||||
|
||||
if (config->led_output_pipe || config->slider_led_output_pipe)
|
||||
if (config->cab_led_output_pipe || config->controller_led_output_pipe)
|
||||
{
|
||||
led_pipe_init(); // don't really care about errors here tbh
|
||||
}
|
||||
|
||||
if (config->led_output_serial || config->slider_led_output_serial)
|
||||
if (config->cab_led_output_serial || config->controller_led_output_serial)
|
||||
{
|
||||
led_serial_init(config->led_serial_port, config->led_serial_baud);
|
||||
}
|
||||
@ -106,13 +106,13 @@ void led_output_update(uint8_t board, const byte* rgb)
|
||||
|
||||
if (board < 2)
|
||||
{
|
||||
// billboard
|
||||
if (config->led_output_pipe)
|
||||
// billboard (cab)
|
||||
if (config->cab_led_output_pipe)
|
||||
{
|
||||
led_pipe_update(escaped_data);
|
||||
}
|
||||
|
||||
if (config->led_output_serial)
|
||||
if (config->cab_led_output_serial)
|
||||
{
|
||||
led_serial_update(escaped_data);
|
||||
}
|
||||
@ -120,12 +120,12 @@ void led_output_update(uint8_t board, const byte* rgb)
|
||||
else
|
||||
{
|
||||
// slider
|
||||
if (config->slider_led_output_pipe)
|
||||
if (config->controller_led_output_pipe)
|
||||
{
|
||||
led_pipe_update(escaped_data);
|
||||
}
|
||||
|
||||
if (config->slider_led_output_serial)
|
||||
if (config->controller_led_output_serial)
|
||||
{
|
||||
led_serial_update(escaped_data);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -170,7 +170,7 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
dprintf("imported %d symbols\n",bind_count);
|
||||
dprintf("imported %d symbols\n", bind_count);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
|
@ -1,3 +1,27 @@
|
||||
/*
|
||||
"CHUNITHM NEW" (chusan) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-02 "Type 4" I/O Board
|
||||
COM1: 837-15330 Ground Slider
|
||||
|
||||
[CVT mode (DIPSW2 ON)]
|
||||
|
||||
COM2: 837-15093-06 LED Controller Board
|
||||
COM3: 837-15093-06 LED Controller Board
|
||||
COM4: 837-15286 "Gen 2" Aime Reader
|
||||
|
||||
[SP mode (DIPSW2 OFF)]
|
||||
|
||||
USB: 837-15067-02 USB Serial I/F Board
|
||||
connected to
|
||||
837-15093-06 LED Controller Board (COM20)
|
||||
837-15093-06 LED Controller Board (COM21)
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM4: 837-15396 "Gen 3" Aime Reader
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -40,4 +40,5 @@ void cm_hook_config_load(
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
touch_screen_config_load(&cfg->touch, filename);
|
||||
cm_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
#include "unityhook/config.h"
|
||||
|
||||
struct cm_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
@ -19,6 +21,7 @@ struct cm_hook_config {
|
||||
struct vfd_config vfd;
|
||||
struct cm_dll_config dll;
|
||||
struct touch_screen_config touch;
|
||||
struct unity_config unity;
|
||||
};
|
||||
|
||||
void cm_dll_config_load(
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"Card Maker" (cm) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 838-20006 "WinTouch" Controller Board
|
||||
USB: 630-00009 Sinfonia CHC-C310 Printer
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 220-5872 AS-6DB Coin Selector
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -16,10 +29,11 @@
|
||||
#include "cmhook/config.h"
|
||||
#include "cmhook/io4.h"
|
||||
#include "cmhook/cm-dll.h"
|
||||
#include "cmhook/unity.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "unityhook/hook.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE cm_hook_mod;
|
||||
@ -54,6 +68,12 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
@ -66,12 +86,6 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = cm_io4_hook_init(&cm_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
@ -83,7 +97,7 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the `cmhook` initialization. */
|
||||
|
||||
unity_hook_init();
|
||||
unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
|
@ -16,6 +16,7 @@ shared_library(
|
||||
hooklib_lib,
|
||||
cmio_lib,
|
||||
platform_lib,
|
||||
unityhook_lib,
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
@ -26,7 +27,5 @@ shared_library(
|
||||
'io4.h',
|
||||
'cm-dll.c',
|
||||
'cm-dll.h',
|
||||
'unity.h',
|
||||
'unity.c',
|
||||
],
|
||||
)
|
||||
|
@ -1,95 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
|
||||
static const struct hook_symbol unity_kernel32_syms[] = {
|
||||
{
|
||||
.name = "LoadLibraryW",
|
||||
.patch = my_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
},
|
||||
};
|
||||
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"mono.dll",
|
||||
L"cri_ware_unity.dll",
|
||||
};
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
|
||||
void unity_hook_init(void)
|
||||
{
|
||||
dll_hook_insert_hooks(NULL);
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
unity_kernel32_syms,
|
||||
_countof(unity_kernel32_syms));
|
||||
}
|
||||
|
||||
static HMODULE WINAPI my_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("Unity: Loaded %S\n", target_module);
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
path_hook_insert_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void unity_hook_init(void);
|
@ -23,22 +23,32 @@ void cxb_dll_config_load(
|
||||
struct cxb_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"cxbio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void revio_config_load(struct revio_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
}
|
||||
|
||||
void network_config_load(struct network_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"revio", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void led_config_load(struct led_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void cxb_hook_config_load(
|
||||
@ -56,6 +66,5 @@ void cxb_hook_config_load(
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
cxb_dll_config_load(&cfg->dll, filename);
|
||||
revio_config_load(&cfg->revio, filename);
|
||||
network_config_load(&cfg->network, filename);
|
||||
led_config_load(&cfg->led, filename);
|
||||
}
|
@ -10,7 +10,6 @@
|
||||
#include "cxbhook/cxb-dll.h"
|
||||
#include "cxbhook/revio.h"
|
||||
#include "cxbhook/led.h"
|
||||
#include "cxbhook/network.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
@ -23,7 +22,6 @@ struct cxb_hook_config {
|
||||
struct gfx_config gfx;
|
||||
struct cxb_dll_config dll;
|
||||
struct revio_config revio;
|
||||
struct network_config network;
|
||||
struct led_config led;
|
||||
};
|
||||
|
||||
@ -32,7 +30,6 @@ void cxb_dll_config_load(
|
||||
const wchar_t *filename);
|
||||
|
||||
void revio_config_load(struct revio_config *cfg, const wchar_t *filename);
|
||||
void network_config_load(struct network_config *cfg, const wchar_t *filename);
|
||||
void led_config_load(struct led_config *cfg, const wchar_t *filename);
|
||||
|
||||
void cxb_hook_config_load(
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "cxbhook/config.h"
|
||||
#include "cxbhook/revio.h"
|
||||
#include "cxbhook/led.h"
|
||||
#include "cxbhook/network.h"
|
||||
|
||||
#include "cxbio/cxbio.h"
|
||||
|
||||
@ -103,12 +102,6 @@ static DWORD CALLBACK cxb_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = network_hook_init(&cxb_hook_cfg.network);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led_hook_init(&cxb_hook_cfg.led);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "cxbhook/led.h"
|
||||
#include "cxbhook/cxb-dll.h"
|
||||
|
||||
#include "hooklib/procaddr.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
@ -49,8 +49,14 @@ static struct hook_symbol lamp_syms[] = {
|
||||
|
||||
HRESULT led_hook_init(struct led_config *cfg)
|
||||
{
|
||||
dprintf("LED: Init\n");
|
||||
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
dprintf("LED: Hook enabled.\n");
|
||||
return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
||||
}
|
||||
|
||||
static int my_cCommLamp_Open(char *port)
|
||||
|
@ -30,7 +30,5 @@ shared_library(
|
||||
'revio.h',
|
||||
'led.c',
|
||||
'led.h',
|
||||
'network.c',
|
||||
'network.h',
|
||||
],
|
||||
)
|
||||
|
@ -1,13 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cxbhook/network.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
HRESULT network_hook_init(struct network_config *cfg)
|
||||
{
|
||||
dprintf("Network: Init\n");
|
||||
return S_OK;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct network_config {
|
||||
bool enable;
|
||||
bool disable_ssl;
|
||||
char title_server[PATH_MAX];
|
||||
};
|
||||
|
||||
HRESULT network_hook_init(struct network_config *cfg);
|
@ -6,7 +6,7 @@
|
||||
#include "cxbhook/revio.h"
|
||||
#include "cxbhook/cxb-dll.h"
|
||||
|
||||
#include "hooklib/procaddr.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
@ -82,8 +82,14 @@ static struct hook_symbol revio_syms[] = {
|
||||
|
||||
HRESULT revio_hook_init(struct revio_config *cfg)
|
||||
{
|
||||
dprintf("Revio: Init\n");
|
||||
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
dprintf("Revio: Hook enabled.\n");
|
||||
return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms));
|
||||
}
|
||||
|
||||
static int my_cCommIo_Open(char *port)
|
||||
@ -154,7 +160,7 @@ static int my_cCommIo_GetTrigger()
|
||||
|
||||
out &= ~last_triggers;
|
||||
|
||||
dprintf("Revio: GetTrigger %X\n", out);
|
||||
// dprintf("Revio: GetTrigger %X\n", out);
|
||||
last_triggers = out;
|
||||
return out;
|
||||
}
|
||||
@ -188,7 +194,7 @@ static int my_cCommIo_GetRelease()
|
||||
|
||||
out &= ~btns;
|
||||
|
||||
dprintf("Revio: GetRelease %X\n", out);
|
||||
// dprintf("Revio: GetRelease %X\n", out);
|
||||
last_triggers = btns;
|
||||
return out;
|
||||
}
|
||||
|
28
dist/chuni/segatools.ini
vendored
28
dist/chuni/segatools.ini
vendored
@ -63,20 +63,6 @@ framed=1
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[chuniio]
|
||||
; To use a custom Chunithm IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
@ -122,6 +108,20 @@ controllerLedOutputSerial=0
|
||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[chuniio]
|
||||
; To use a custom Chunithm IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
39
dist/chusan/segatools.ini
vendored
39
dist/chusan/segatools.ini
vendored
@ -43,6 +43,7 @@ default=127.0.0.1
|
||||
; Chunithm is extremely picky about its LAN environment, so leaving this
|
||||
; setting enabled is strongly 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.32.0` and this value is set to `11`, then the
|
||||
; local host's virtualized LAN IP is `192.168.32.11`).
|
||||
@ -88,25 +89,6 @@ framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL (x64) enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[chuniio]
|
||||
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
||||
; (will use chu2to3 engine internally)
|
||||
;path=
|
||||
|
||||
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||
;path32=
|
||||
;path64=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
@ -152,6 +134,25 @@ controllerLedOutputSerial=0
|
||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL (x64) enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[chuniio]
|
||||
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
||||
; (will use chu2to3 engine internally)
|
||||
;path=
|
||||
|
||||
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||
;path32=
|
||||
;path64=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
3
dist/chusan/start.bat
vendored
3
dist/chusan/start.bat
vendored
@ -2,8 +2,9 @@
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json
|
||||
start "AM Daemon" /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json
|
||||
inject_x86 -d -k chusanhook_x86.dll chusanApp.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
|
5
dist/cm/segatools.ini
vendored
5
dist/cm/segatools.ini
vendored
@ -68,6 +68,11 @@ dipsw1=0
|
||||
; Enable/Disable WinTouch emulation
|
||||
enable=0
|
||||
|
||||
[unity]
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
2
dist/cm/start.bat
vendored
2
dist/cm/start.bat
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json
|
||||
start "AM Daemon" /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json
|
||||
inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
11
dist/cxb/segatools.ini
vendored
11
dist/cxb/segatools.ini
vendored
@ -19,10 +19,10 @@ appdata=
|
||||
|
||||
[aime]
|
||||
; Aime reader emulation
|
||||
; CXB is stupid, so we have to make the paths go back one
|
||||
enable=1
|
||||
; CXB is stupid, so we have to make the paths go back two directories. This
|
||||
; will load the file from "resource\DEVICE\aime.txt".
|
||||
aimePath=../DEVICE/aime.txt
|
||||
felicaPath=../DEVICE/felica.txt
|
||||
|
||||
[led]
|
||||
; Emulation for the LED board. Currently it's just dummy responses,
|
||||
@ -39,6 +39,10 @@ enable=1
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
; Set the title server hostname or IP address here, as the title server
|
||||
; is hardcoded in the game.
|
||||
title=https://127.0.0.1:9002
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; Crossbeats is extremely picky about its LAN environment, so leaving this
|
||||
@ -106,13 +110,14 @@ path=
|
||||
|
||||
[revio]
|
||||
; Enable emulation of the rev IO board
|
||||
enabe=1
|
||||
enable=1
|
||||
; 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
|
||||
|
||||
; Menu up key. Default is up arrow.
|
||||
up=0x26
|
||||
; Menu down key. Default is down arrow.
|
||||
|
17
dist/fgo/segatools.ini
vendored
17
dist/fgo/segatools.ini
vendored
@ -128,13 +128,12 @@ path=
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Input API selection for JVS input emulator.
|
||||
; Test button virtual-key code. Default is the 1 key.
|
||||
test=0x31
|
||||
; Service button virtual-key code. Default is the 2 key.
|
||||
service=0x32
|
||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||
coin=0x33
|
||||
; 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
|
||||
|
||||
; .·:'''''''''''''''''''''''''''''''''''''''''''''':·.
|
||||
; : : ______ / \ [] : :
|
||||
@ -151,8 +150,8 @@ coin=0x33
|
||||
;
|
||||
; Only XInput is currently supported.
|
||||
|
||||
; Controller Button
|
||||
; -------------------------------------------------------
|
||||
; XInput bindings
|
||||
;
|
||||
; Left Stick Joystick
|
||||
; Left Stick Click Reset Camera
|
||||
; Left Trigger Dash
|
||||
|
19
dist/idac/segatools.ini
vendored
19
dist/idac/segatools.ini
vendored
@ -75,6 +75,25 @@ dipsw3=0
|
||||
dipsw4=0
|
||||
dipsw5=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15070]
|
||||
; 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
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
27
dist/idac/start.bat
vendored
27
dist/idac/start.bat
vendored
@ -2,20 +2,6 @@
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM set the APP_DIR to the Y drive
|
||||
set APP_DIR=Y:\SDGT
|
||||
|
||||
REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder
|
||||
if not exist "%APP_DIR%" (
|
||||
subst Y: %TEMP%
|
||||
REM timeout /t 1
|
||||
if not exist "%APP_DIR%" (
|
||||
mkdir "%APP_DIR%"
|
||||
)
|
||||
)
|
||||
|
||||
echo Mounted the Y:\ drive to the %TEMP%\SDGT folder
|
||||
|
||||
set AMDAEMON_CFG=config_common.json ^
|
||||
config_ex.json ^
|
||||
config_jp.json ^
|
||||
@ -39,12 +25,15 @@ config_seat_single_ex.json ^
|
||||
config_seat_single_jp.json ^
|
||||
config_hook.json
|
||||
|
||||
start /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG%
|
||||
inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
start "AM Daemon" /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG%
|
||||
|
||||
REM unmount the APP_DIR
|
||||
subst Y: /d > nul 2>&1
|
||||
rem JP
|
||||
rem inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
||||
|
||||
rem EXP
|
||||
inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
|
12
dist/mai2/segatools.ini
vendored
12
dist/mai2/segatools.ini
vendored
@ -69,6 +69,18 @@ freeplay=0
|
||||
; this to 1 on exactly one machine and set this to 0 on all others.
|
||||
dipsw1=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hook settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[unity]
|
||||
; Enable Unity hook. This will allow you to run custom .NET code before the game
|
||||
enable=1
|
||||
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
5
dist/mai2/start.bat
vendored
5
dist/mai2/start.bat
vendored
@ -2,8 +2,9 @@
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
|
||||
inject -d -k mai2hook.dll sinmai -screen-fullscreen 0
|
||||
start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
|
||||
inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 -popupwindow -screen-width 2160 -screen-height 1920 -silent-crashes
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
|
4
dist/mercury/start.bat
vendored
4
dist/mercury/start.bat
vendored
@ -4,10 +4,10 @@ pushd %~dp0
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
REM USA
|
||||
REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
|
||||
REM JP
|
||||
start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
58
dist/mu3/segatools.ini
vendored
58
dist/mu3/segatools.ini
vendored
@ -72,6 +72,62 @@ dipsw1=1
|
||||
[gfx]
|
||||
enable=1
|
||||
|
||||
[unity]
|
||||
; Enable Unity hook. This will allow you to run custom .NET code before the game
|
||||
enable=1
|
||||
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable emulation of the 15093-06 controlled lights, which handle the air tower
|
||||
; RGBs and the rear LED panel (billboard) on the cabinet.
|
||||
enable=1
|
||||
|
||||
[led]
|
||||
; Output billboard LED strip data to a named pipe called "\\.\pipe\ongeki_led"
|
||||
cabLedOutputPipe=1
|
||||
; Output billboard LED strip data to serial
|
||||
cabLedOutputSerial=0
|
||||
|
||||
; Output slider LED data to the named pipe
|
||||
controllerLedOutputPipe=1
|
||||
; Output slider LED data to the serial port
|
||||
controllerLedOutputSerial=0
|
||||
|
||||
; Serial port to send data to if using serial output. Default is COM5.
|
||||
;serialPort=COM5
|
||||
; Baud rate for serial data
|
||||
;serialBaud=921600
|
||||
|
||||
; Data output a sequence of bytes, with JVS-like framing.
|
||||
; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere,
|
||||
; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore
|
||||
; it and use the next sent byte plus one instead.
|
||||
;
|
||||
; After the sync is one byte for the board number that was updated, followed by
|
||||
; the red, green and blue values for each LED.
|
||||
;
|
||||
; Board 0 has 61 LEDs:
|
||||
; [0]-[1]: left side button
|
||||
; [2]-[8]: left pillar lower LEDs
|
||||
; [9]-[17]: left pillar center LEDs
|
||||
; [18]-[24]: left pillar upper LEDs
|
||||
; [25]-[35]: billboard LEDs
|
||||
; [36]-[42]: right pillar upper LEDs
|
||||
; [43]-[51]: right pillar center LEDs
|
||||
; [52]-[58]: right pillar lower LEDs
|
||||
; [59]-[60]: right side button
|
||||
;
|
||||
; Board 1 has 6 LEDs:
|
||||
; [0]-[5]: 3 left and 3 right controller buttons
|
||||
;
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
@ -81,7 +137,7 @@ enable=1
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[fgoio]
|
||||
[mu3io]
|
||||
; To use a custom O.N.G.E.K.I. IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
2
dist/mu3/start.bat
vendored
2
dist/mu3/start.bat
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
|
||||
start "AM Daemon" /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
|
||||
inject -d -k mu3hook.dll mu3 -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
|
2
dist/swdc/segatools.ini
vendored
2
dist/swdc/segatools.ini
vendored
@ -63,7 +63,7 @@ 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´
|
||||
freeplay=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
|
@ -1,3 +1,14 @@
|
||||
/*
|
||||
"Hatsune Miku Project DIVA Arcade " (diva) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-14572 "Type 3" I/O Board
|
||||
COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board
|
||||
COM10: TN32MSEC003S "Gen 1" Aime Reader
|
||||
COM11: 837-15275 Touch Slider
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -153,6 +153,13 @@ 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).
|
||||
|
||||
### `title`
|
||||
|
||||
Default: `title`
|
||||
|
||||
Leave it as `title` to use the title server returned by ALL.Net. Rewrites
|
||||
the title server hostname for certain games, such as crossbeats REV.
|
||||
|
||||
### `router`
|
||||
|
||||
Default: Empty string (i.e. use value from `default` setting)
|
||||
@ -388,13 +395,29 @@ Bit values are:
|
||||
- 3: EXP: Export (for Asian markets)
|
||||
- 4: CHS: China (Simplified Chinese?)
|
||||
|
||||
### `billingCa`
|
||||
|
||||
Default: `DEVICE\\ca.crt`
|
||||
|
||||
Set the billing certificate path. This has to match the one used for the
|
||||
SSL billing server. The DER certificate must fit in 1024 bytes so it must be
|
||||
small.
|
||||
|
||||
### `billingPub`
|
||||
|
||||
Default: `DEVICE\\billing.pub`
|
||||
|
||||
Set the actual keychip RSA public key path. This public key has to match the
|
||||
private key `billing.key` of the billing server in order to decrypt/encrypt
|
||||
the billing transactions.
|
||||
|
||||
### `billingType`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Set the billing "type" for the keychip. The type determins what kind of revenue share,
|
||||
if any, the game maker has with SEGA. Some games may be picky and require types other
|
||||
then 1 (ex. Crossbeats requires billing type 2), so this option is provided if this
|
||||
then 1 (ex. crossbeats REV. requires billing type 2), so this option is provided if this
|
||||
is an issue. Billing types are:
|
||||
|
||||
- 0: No billing?
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
"Fate Grand/Order Arcade" (fgo) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
USB: 838-15405 "WinTouch" Controller Board
|
||||
USB: 630-00008 Sinfonia CHC-C330 Printer
|
||||
USB: 837-14509-02 USB-SER I/F BD Mini-B FTDI Board
|
||||
connected to
|
||||
837-15093-06 LED Controller Board
|
||||
COM1: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM2: 837-15345 RFID Deck Reader Noard
|
||||
COM3: 837-15396 "Gen 3" Aime Reader
|
||||
COM4: 837-15347 RFID Reader/Writer Board (inside the printer)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -28,7 +28,7 @@ const struct dll_bind_sym fgo_dll_syms[] = {
|
||||
.sym = "fgo_io_led_init",
|
||||
.off = offsetof(struct fgo_dll, led_init),
|
||||
}, {
|
||||
.sym = "fgo_io_led_set_leds",
|
||||
.sym = "fgo_io_led_set_colors",
|
||||
.off = offsetof(struct fgo_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ EXPORTS
|
||||
fgo_io_init
|
||||
fgo_io_poll
|
||||
fgo_io_led_init
|
||||
fgo_io_led_set_leds
|
||||
fgo_io_led_set_colors
|
||||
fwdlusb_open
|
||||
fwdlusb_close
|
||||
fwdlusb_listupPrinter
|
||||
|
@ -145,7 +145,7 @@ HRESULT fgo_io_led_init(void)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb)
|
||||
void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -83,4 +83,4 @@ HRESULT fgo_io_led_init(void);
|
||||
|
||||
Exact layout is TBD. */
|
||||
|
||||
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb);
|
||||
void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||
|
166
hooklib/dns.c
166
hooklib/dns.c
@ -3,6 +3,7 @@
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
@ -12,6 +13,8 @@
|
||||
#include "hook/hr.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "hooklib/dns.h"
|
||||
|
||||
/* Latest w32headers does not include DnsQueryEx, so we'll have to "polyfill"
|
||||
@ -66,6 +69,18 @@ static int WSAAPI hook_getaddrinfo(
|
||||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved);
|
||||
|
||||
static bool WINAPI hook_WinHttpCrackUrl(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static DNS_STATUS (WINAPI *next_DnsQuery_A)(
|
||||
@ -95,6 +110,18 @@ static int (WSAAPI *next_getaddrinfo)(
|
||||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static HINTERNET (WINAPI *next_WinHttpConnect)(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved);
|
||||
|
||||
static bool (WINAPI *next_WinHttpCrackUrl)(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents);
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_dnsapi[] = {
|
||||
{
|
||||
.name = "DnsQuery_A",
|
||||
@ -120,10 +147,24 @@ static const struct hook_symbol dns_hook_syms_ws2[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_winhttp[] = {
|
||||
{
|
||||
.name = "WinHttpConnect",
|
||||
.patch = hook_WinHttpConnect,
|
||||
.link = (void **) &next_WinHttpConnect,
|
||||
}, {
|
||||
.name = "WinHttpCrackUrl",
|
||||
.patch = hook_WinHttpCrackUrl,
|
||||
.link = (void **) &next_WinHttpCrackUrl,
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static bool dns_hook_initted;
|
||||
static CRITICAL_SECTION dns_hook_lock;
|
||||
static struct dns_hook_entry *dns_hook_entries;
|
||||
static size_t dns_hook_nentries;
|
||||
static char received_title_url[255];
|
||||
|
||||
static void dns_hook_init(void)
|
||||
{
|
||||
@ -145,6 +186,43 @@ static void dns_hook_init(void)
|
||||
"ws2_32.dll",
|
||||
dns_hook_syms_ws2,
|
||||
_countof(dns_hook_syms_ws2));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"winhttp.dll",
|
||||
dns_hook_syms_winhttp,
|
||||
_countof(dns_hook_syms_winhttp));
|
||||
}
|
||||
|
||||
// This function match domain and subdomains like *.naominet.jp.
|
||||
bool match_domain(const wchar_t* target, const wchar_t* pattern) {
|
||||
if (_wcsicmp(pattern, target) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int pattern_ptr_index = 0;
|
||||
int target_ptr_index = 0;
|
||||
|
||||
while (pattern[pattern_ptr_index] != '\0' && target[target_ptr_index] != '\0') {
|
||||
if (pattern[pattern_ptr_index] == '*') {
|
||||
pattern_ptr_index++; // Check next character for wildcard match.
|
||||
|
||||
while (pattern[pattern_ptr_index] != target[target_ptr_index]) {
|
||||
target_ptr_index++;
|
||||
|
||||
if (target[target_ptr_index] == '\0') return false;
|
||||
}
|
||||
}
|
||||
else if (pattern[pattern_ptr_index] != target[target_ptr_index]) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
pattern_ptr_index++;
|
||||
target_ptr_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return pattern[pattern_ptr_index] == '\0' && target[target_ptr_index] == '\0';
|
||||
}
|
||||
|
||||
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src)
|
||||
@ -250,7 +328,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_A(
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (_wcsicmp(wstr, pos->from) == 0) {
|
||||
if (match_domain(wstr, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
@ -314,7 +392,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_W(
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (_wcsicmp(pszName, pos->from) == 0) {
|
||||
if (match_domain(pszName, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
@ -358,7 +436,7 @@ static DNS_STATUS WINAPI hook_DnsQueryEx(
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (_wcsicmp(pRequest->QueryName, pos->from) == 0) {
|
||||
if (match_domain(pRequest->QueryName, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
@ -425,7 +503,7 @@ static int WSAAPI hook_getaddrinfo(
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (_wcsicmp(wstr, pos->from) == 0) {
|
||||
if (match_domain(wstr, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = EAI_NONAME;
|
||||
@ -460,3 +538,83 @@ end:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
|
||||
if (pwszServerName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pwszServerName, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pwszServerName = pos->to;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
return next_WinHttpConnect(hSession, pwszServerName, nServerPort, dwReserved);
|
||||
}
|
||||
|
||||
// Hook to replace CXB title url
|
||||
static bool WINAPI hook_WinHttpCrackUrl(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pwszUrl, pos->from)) {
|
||||
wchar_t* toAddr = pos->to;
|
||||
wchar_t titleBuffer[255];
|
||||
|
||||
if(wcscmp(toAddr, L"title") == 0) {
|
||||
size_t wstr_c;
|
||||
mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url));
|
||||
toAddr = titleBuffer;
|
||||
}
|
||||
|
||||
bool result = next_WinHttpCrackUrl(
|
||||
toAddr,
|
||||
wcslen(toAddr),
|
||||
dwFlags,
|
||||
lpUrlComponents
|
||||
);
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return next_WinHttpCrackUrl(
|
||||
pwszUrl,
|
||||
dwUrlLength,
|
||||
dwFlags,
|
||||
lpUrlComponents
|
||||
);
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ hooklib_lib = static_library(
|
||||
'fdshark.h',
|
||||
'path.c',
|
||||
'path.h',
|
||||
'procaddr.c',
|
||||
'procaddr.h',
|
||||
'reg.c',
|
||||
'reg.h',
|
||||
'setupapi.c',
|
||||
|
305
hooklib/path.c
305
hooklib/path.c
@ -101,6 +101,40 @@ static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath);
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
|
||||
|
||||
static BOOL WINAPI hook_MoveFileA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName);
|
||||
|
||||
static BOOL WINAPI hook_MoveFileW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName);
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileA(
|
||||
const char *lpReplacedFileName,
|
||||
const char *lpReplacementFileName,
|
||||
const char *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved);
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileW(
|
||||
const wchar_t *lpReplacedFileName,
|
||||
const wchar_t *lpReplacementFileName,
|
||||
const wchar_t *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved);
|
||||
|
||||
static BOOL WINAPI hook_DeleteFileA(const char *lpFileName);
|
||||
|
||||
static BOOL WINAPI hook_DeleteFileW(const wchar_t *lpFileName);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||
@ -185,6 +219,39 @@ static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
|
||||
|
||||
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
|
||||
|
||||
static BOOL (WINAPI *next_MoveFileA)(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName);
|
||||
|
||||
static BOOL (WINAPI *next_MoveFileW)(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName);
|
||||
|
||||
static BOOL (WINAPI *next_MoveFileExA)(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
static BOOL (WINAPI *next_ReplaceFileA)(
|
||||
const char *lpReplacedFileName,
|
||||
const char *lpReplacementFileName,
|
||||
const char *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved);
|
||||
|
||||
static BOOL (WINAPI *next_ReplaceFileW)(
|
||||
const wchar_t *lpReplacedFileName,
|
||||
const wchar_t *lpReplacementFileName,
|
||||
const wchar_t *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved);
|
||||
|
||||
static BOOL (WINAPI *next_DeleteFileA)(const char *lpFileName);
|
||||
|
||||
static BOOL (WINAPI *next_DeleteFileW)(const wchar_t *lpFileName);
|
||||
|
||||
/* Hook table */
|
||||
|
||||
static const struct hook_symbol path_hook_syms[] = {
|
||||
@ -260,6 +327,34 @@ static const struct hook_symbol path_hook_syms[] = {
|
||||
.name = "PathFileExistsW",
|
||||
.patch = hook_PathFileExistsW,
|
||||
.link = (void **) &next_PathFileExistsW,
|
||||
}, {
|
||||
.name = "MoveFileA",
|
||||
.patch = hook_MoveFileA,
|
||||
.link = (void **) &next_MoveFileA,
|
||||
}, {
|
||||
.name = "MoveFileW",
|
||||
.patch = hook_MoveFileW,
|
||||
.link = (void **) &next_MoveFileW,
|
||||
}, {
|
||||
.name = "MoveFileExA",
|
||||
.patch = hook_MoveFileExA,
|
||||
.link = (void **) &next_MoveFileExA,
|
||||
}, {
|
||||
.name = "ReplaceFileA",
|
||||
.patch = hook_ReplaceFileA,
|
||||
.link = (void **) &next_ReplaceFileA,
|
||||
}, {
|
||||
.name = "ReplaceFileW",
|
||||
.patch = hook_ReplaceFileW,
|
||||
.link = (void **) &next_ReplaceFileW,
|
||||
}, {
|
||||
.name = "DeleteFileA",
|
||||
.patch = hook_DeleteFileA,
|
||||
.link = (void **) &next_DeleteFileA,
|
||||
}, {
|
||||
.name = "DeleteFileW",
|
||||
.patch = hook_DeleteFileW,
|
||||
.link = (void **) &next_DeleteFileW,
|
||||
}
|
||||
};
|
||||
|
||||
@ -906,3 +1001,213 @@ static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_MoveFileA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName)
|
||||
{
|
||||
char *oldTrans;
|
||||
char *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_a(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_MoveFileA(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_MoveFileW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName)
|
||||
{
|
||||
wchar_t *oldTrans;
|
||||
wchar_t *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_MoveFileW(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
uint32_t dwFlags)
|
||||
{
|
||||
char *oldTrans;
|
||||
char *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_a(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_MoveFileExA(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
dwFlags);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileA(
|
||||
const char *lpReplacedFileName,
|
||||
const char *lpReplacementFileName,
|
||||
const char *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved)
|
||||
{
|
||||
char *oldTrans;
|
||||
char *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&oldTrans, lpReplacedFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_a(&newTrans, lpReplacementFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_ReplaceFileA(
|
||||
oldTrans ? oldTrans : lpReplacedFileName,
|
||||
newTrans ? newTrans : lpReplacementFileName,
|
||||
lpBackupFileName,
|
||||
dwReplaceFlags,
|
||||
lpExclude,
|
||||
lpReserved);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileW(
|
||||
const wchar_t *lpReplacedFileName,
|
||||
const wchar_t *lpReplacementFileName,
|
||||
const wchar_t *lpBackupFileName,
|
||||
uint32_t dwReplaceFlags,
|
||||
void *lpExclude,
|
||||
void *lpReserved)
|
||||
{
|
||||
wchar_t *oldTrans;
|
||||
wchar_t *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&oldTrans, lpReplacedFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&newTrans, lpReplacementFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_ReplaceFileW(
|
||||
oldTrans ? oldTrans : lpReplacedFileName,
|
||||
newTrans ? newTrans : lpReplacementFileName,
|
||||
lpBackupFileName,
|
||||
dwReplaceFlags,
|
||||
lpExclude,
|
||||
lpReserved);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_DeleteFileA(const char *lpFileName)
|
||||
{
|
||||
char *trans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&trans, lpFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_DeleteFileA(trans ? trans: lpFileName);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_DeleteFileW(const wchar_t *lpFileName)
|
||||
{
|
||||
wchar_t *trans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_DeleteFileW(trans ? trans: lpFileName);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -1,125 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "hooklib/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static struct proc_addr_table *proc_addr_hook_list;
|
||||
static size_t proc_addr_hook_count;
|
||||
static CRITICAL_SECTION proc_addr_hook_lock;
|
||||
static bool proc_addr_hook_initted;
|
||||
|
||||
static FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name);
|
||||
static FARPROC (WINAPI *next_GetProcAddress)(HMODULE hModule, const char *name);
|
||||
static void proc_addr_hook_init(void);
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "GetProcAddress",
|
||||
.patch = my_GetProcAddress,
|
||||
.link = (void **) &next_GetProcAddress
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT proc_addr_table_push(
|
||||
const char *target,
|
||||
struct hook_symbol *syms,
|
||||
size_t nsyms
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct proc_addr_table *new_item;
|
||||
struct proc_addr_table *new_mem;
|
||||
|
||||
proc_addr_hook_init();
|
||||
|
||||
EnterCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
proc_addr_hook_list,
|
||||
(proc_addr_hook_count + 1) * sizeof(struct proc_addr_table));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
LeaveCriticalSection(&proc_addr_hook_lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
new_item = &new_mem[proc_addr_hook_count];
|
||||
new_item->name = target;
|
||||
new_item->nsyms = nsyms;
|
||||
new_item->syms = syms;
|
||||
|
||||
proc_addr_hook_list = new_mem;
|
||||
proc_addr_hook_count++;
|
||||
hr = S_OK;
|
||||
|
||||
LeaveCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void proc_addr_hook_init(void)
|
||||
{
|
||||
if (proc_addr_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("ProcAddr: Hook init\n");
|
||||
proc_addr_hook_initted = true;
|
||||
|
||||
InitializeCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
}
|
||||
|
||||
FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name)
|
||||
{
|
||||
uintptr_t ordinal = (uintptr_t) name;
|
||||
char mod_path[PATH_MAX];
|
||||
char *mod_name;
|
||||
const struct hook_symbol *sym;
|
||||
FARPROC result = next_GetProcAddress(hModule, name);
|
||||
|
||||
GetModuleFileNameA(hModule, mod_path, PATH_MAX);
|
||||
mod_name = basename(mod_path);
|
||||
|
||||
for (int i = 0; i < proc_addr_hook_count; i++) {
|
||||
|
||||
if (strcmp(proc_addr_hook_list[i].name, mod_name) == 0) {
|
||||
|
||||
for (int j = 0; j < proc_addr_hook_list[i].nsyms; j++) {
|
||||
sym = &proc_addr_hook_list[i].syms[j];
|
||||
|
||||
if (ordinal > 0xFFFF) {
|
||||
|
||||
if (strcmp(sym->name, name) == 0) {
|
||||
|
||||
dprintf("ProcAddr: Hooking %s from %s\n", name, mod_name);
|
||||
result = (FARPROC) sym->patch;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (sym->ordinal == ordinal) {
|
||||
|
||||
dprintf("ProcAddr: Hooking Ord %p from %s\n", (void *)ordinal, mod_name);
|
||||
result = (FARPROC) sym->patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
struct proc_addr_table {
|
||||
const char *name;
|
||||
size_t nsyms;
|
||||
struct hook_symbol *syms;
|
||||
};
|
||||
|
||||
HRESULT proc_addr_table_push(
|
||||
const char *target,
|
||||
struct hook_symbol *syms,
|
||||
size_t nsyms
|
||||
);
|
165
hooklib/reg.c
165
hooklib/reg.c
@ -7,6 +7,7 @@
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/str.h"
|
||||
@ -99,6 +100,29 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
||||
uint32_t *numData
|
||||
);
|
||||
|
||||
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime);
|
||||
|
||||
static LSTATUS WINAPI hook_RegEnumValueW(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData);
|
||||
/* Link pointers */
|
||||
|
||||
static LSTATUS (WINAPI *next_RegOpenKeyExW)(
|
||||
@ -155,6 +179,30 @@ static LSTATUS (WINAPI *next_RegGetValueW)(
|
||||
uint32_t *numData
|
||||
);
|
||||
|
||||
static LSTATUS (WINAPI *next_RegQueryInfoKeyW)(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime);
|
||||
|
||||
static LSTATUS (WINAPI *next_RegEnumValueW)(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData);
|
||||
|
||||
static const struct hook_symbol reg_hook_syms[] = {
|
||||
{
|
||||
.name = "RegOpenKeyExW",
|
||||
@ -184,6 +232,14 @@ static const struct hook_symbol reg_hook_syms[] = {
|
||||
.name = "RegGetValueW",
|
||||
.patch = hook_RegGetValueW,
|
||||
.link = (void **) &next_RegGetValueW,
|
||||
}, {
|
||||
.name = "RegQueryInfoKeyW",
|
||||
.patch = hook_RegQueryInfoKeyW,
|
||||
.link = (void **) &next_RegQueryInfoKeyW,
|
||||
}, {
|
||||
.name = "RegEnumValueW",
|
||||
.patch = hook_RegEnumValueW,
|
||||
.link = (void **) &next_RegEnumValueW,
|
||||
}
|
||||
};
|
||||
|
||||
@ -254,11 +310,24 @@ static void reg_hook_init(void)
|
||||
InitializeCriticalSection(®_hook_lock);
|
||||
dprintf("Reg hook init\n");
|
||||
|
||||
reg_hook_insert_hooks(NULL);
|
||||
|
||||
proc_addr_table_push(
|
||||
NULL,
|
||||
"ADVAPI32.dll",
|
||||
(struct hook_symbol *) reg_hook_syms,
|
||||
_countof(reg_hook_syms));
|
||||
|
||||
}
|
||||
|
||||
void reg_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
target,
|
||||
"advapi32.dll",
|
||||
reg_hook_syms,
|
||||
_countof(reg_hook_syms));
|
||||
|
||||
}
|
||||
|
||||
static LRESULT reg_hook_propagate_hr(HRESULT hr)
|
||||
@ -331,6 +400,7 @@ static LSTATUS reg_hook_open_locked(
|
||||
/* Assume reg keys are referenced from a root key and not from some
|
||||
intermediary key */
|
||||
key = ®_hook_keys[i];
|
||||
//dprintf("Reg: %ls vs %ls\n", name, key->name);
|
||||
|
||||
if (key->root == parent && wstr_ieq(key->name, name)) {
|
||||
break;
|
||||
@ -821,6 +891,99 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
||||
return err;
|
||||
}
|
||||
|
||||
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime)
|
||||
{
|
||||
struct reg_hook_key *key;
|
||||
LSTATUS err;
|
||||
|
||||
EnterCriticalSection(®_hook_lock);
|
||||
|
||||
key = reg_hook_match_key_locked(hKey);
|
||||
|
||||
/* Check if this is a virtualized registry key */
|
||||
|
||||
if (key == NULL) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
|
||||
return next_RegQueryInfoKeyW(
|
||||
hKey,
|
||||
lpClass,
|
||||
lpcchClass,
|
||||
lpReserved,
|
||||
lpcSubKeys,
|
||||
lpcbMaxSubKeyLen,
|
||||
lpcbMaxClassLen,
|
||||
lpcValues,
|
||||
lpcbMaxValueNameLen,
|
||||
lpcbMaxValueLen,
|
||||
lpcbSecurityDescriptor,
|
||||
lpftLastWriteTime);
|
||||
}
|
||||
|
||||
// This is the only one I've seen even be changed, so it's all I'm doing
|
||||
// until I see otherwise.
|
||||
*lpcValues = key->nvals;
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static LSTATUS WINAPI hook_RegEnumValueW(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData)
|
||||
{
|
||||
struct reg_hook_key *key;
|
||||
HRESULT hr;
|
||||
LSTATUS err;
|
||||
|
||||
EnterCriticalSection(®_hook_lock);
|
||||
|
||||
key = reg_hook_match_key_locked(hkey);
|
||||
|
||||
/* Check if this is a virtualized registry key */
|
||||
|
||||
if (key == NULL) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
|
||||
return next_RegEnumValueW(
|
||||
hkey,
|
||||
dwIndex,
|
||||
lpValueName,
|
||||
lpcchValueName,
|
||||
lpReserved,
|
||||
lpType,
|
||||
lpData,
|
||||
lpcbData);
|
||||
}
|
||||
|
||||
if (dwIndex >= key->nvals) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_NO_MORE_ITEMS; // Pretty sure this is what it actually returns here?
|
||||
}
|
||||
|
||||
wcscpy_s(lpValueName, *lpcchValueName, key->vals[dwIndex].name);
|
||||
*lpcchValueName = wcslen(key->vals[dwIndex].name);
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
HRESULT reg_hook_read_bin(
|
||||
void *bytes,
|
||||
uint32_t *nbytes,
|
||||
|
@ -12,6 +12,8 @@ struct reg_hook_val {
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
void reg_hook_insert_hooks(HMODULE target);
|
||||
|
||||
HRESULT reg_hook_push_key(
|
||||
HKEY root,
|
||||
const wchar_t *name,
|
||||
|
@ -119,10 +119,19 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel
|
||||
defaultCursor = LoadCursorA(NULL, IDC_CROSS);
|
||||
|
||||
memcpy(&touch_config, cfg, sizeof(*cfg));
|
||||
hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks));
|
||||
touch_hook_insert_hooks(NULL);
|
||||
dprintf("TOUCH: hook enabled.\n");
|
||||
}
|
||||
|
||||
void touch_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"user32.dll",
|
||||
touch_hooks,
|
||||
_countof(touch_hooks));
|
||||
}
|
||||
|
||||
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
|
||||
if (cursor == 0 && touch_config.cursor)
|
||||
return next_SetCursor(defaultCursor);
|
||||
|
@ -14,3 +14,4 @@ struct touch_screen_config {
|
||||
blah blah you know the drill by now. */
|
||||
|
||||
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self);
|
||||
void touch_hook_insert_hooks(HMODULE target);
|
||||
|
@ -13,6 +13,43 @@
|
||||
#include "platform/config.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
|
||||
void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
|
||||
cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename);
|
||||
/* TODO: Unknown, no firmware file available */
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15070",
|
||||
L"boardNumber",
|
||||
L"15070-02",
|
||||
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"led15070",
|
||||
L"eepromPath",
|
||||
L"DEVICE",
|
||||
cfg->eeprom_path,
|
||||
_countof(cfg->eeprom_path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void idac_dll_config_load(
|
||||
struct idac_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -29,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)
|
||||
@ -42,6 +89,8 @@ void idac_hook_config_load(
|
||||
zinput_config_load(&cfg->zinput, filename);
|
||||
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)
|
||||
|
@ -4,11 +4,13 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "board/led15070.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "idachook/idac-dll.h"
|
||||
#include "idachook/zinput.h"
|
||||
#include "idachook/indrun.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
@ -19,6 +21,8 @@ struct idac_hook_config {
|
||||
struct io4_config io4;
|
||||
struct idac_dll_config dll;
|
||||
struct zinput_config zinput;
|
||||
struct led15070_config led15070;
|
||||
struct indrun_config indrun;
|
||||
};
|
||||
|
||||
void idac_dll_config_load(
|
||||
@ -29,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);
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"Initial D THE ARCADE" (idac) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257 "Type 4" I/O Board
|
||||
COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board
|
||||
COM2: 837-15070-02 IC BD LED Controller Board
|
||||
COM3: 837-15286 "Gen 2" Aime Reader (DIPSW2 OFF)
|
||||
OR
|
||||
837-15396 "Gen 3" Aime Reader (DIPSW2 ON)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
@ -53,13 +66,13 @@ static DWORD CALLBACK idac_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
||||
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
||||
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
@ -71,6 +84,20 @@ static DWORD CALLBACK idac_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init,
|
||||
idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
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");
|
||||
|
@ -24,6 +24,18 @@ const struct dll_bind_sym idac_dll_syms[] = {
|
||||
}, {
|
||||
.sym = "idac_io_get_analogs",
|
||||
.off = offsetof(struct idac_dll, get_analogs),
|
||||
}, {
|
||||
.sym = "idac_io_led_init",
|
||||
.off = offsetof(struct idac_dll, led_init),
|
||||
}, {
|
||||
.sym = "idac_io_led_set_fet_output",
|
||||
.off = offsetof(struct idac_dll, led_set_fet_output),
|
||||
}, {
|
||||
.sym = "idac_io_led_gs_update",
|
||||
.off = offsetof(struct idac_dll, led_gs_update),
|
||||
}, {
|
||||
.sym = "idac_io_led_set_leds",
|
||||
.off = offsetof(struct idac_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,10 @@ struct idac_dll {
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
void (*get_shifter)(uint8_t *gear);
|
||||
void (*get_analogs)(struct idac_io_analog_state *out);
|
||||
HRESULT (*led_init)(void);
|
||||
void (*led_set_fet_output)(const uint8_t *rgb);
|
||||
void (*led_gs_update)(const uint8_t *rgb);
|
||||
void (*led_set_leds)(const uint8_t *rgb);
|
||||
};
|
||||
|
||||
struct idac_dll_config {
|
||||
|
@ -13,8 +13,11 @@ EXPORTS
|
||||
amDllVideoSetResolution @3
|
||||
idac_io_get_api_version
|
||||
idac_io_init
|
||||
idac_io_poll
|
||||
idac_io_get_opbtns
|
||||
idac_io_get_gamebtns
|
||||
idac_io_get_shifter
|
||||
idac_io_get_analogs
|
||||
idac_io_led_init
|
||||
idac_io_led_set_fet_output
|
||||
idac_io_led_gs_update
|
||||
idac_io_led_set_leds
|
||||
|
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);
|
@ -11,10 +11,12 @@
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT idac_io4_poll(void *ctx, struct io4_state *state);
|
||||
static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len);
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops idac_io4_ops = {
|
||||
.poll = idac_io4_poll,
|
||||
.write_gpio = idac_io4_write_gpio
|
||||
};
|
||||
|
||||
static const uint16_t idac_gear_signals[] = {
|
||||
@ -128,3 +130,34 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state)
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT idac_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 IDAC, 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 15070 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 ON/OFF values.
|
||||
uint8_t rgb_out[6] = {
|
||||
lights_data & IDAC_IO_LED_START ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_UP ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_DOWN ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_RIGHT ? 0xFF : 0x00,
|
||||
lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00,
|
||||
};
|
||||
|
||||
idac_dll.led_set_leds(rgb_out);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -28,5 +28,7 @@ shared_library(
|
||||
'io4.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'indrun.c',
|
||||
'indrun.h',
|
||||
],
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ static bool idac_io_coin;
|
||||
|
||||
uint16_t idac_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
return 0x0101;
|
||||
}
|
||||
|
||||
HRESULT idac_io_init(void)
|
||||
@ -118,3 +118,44 @@ void idac_io_get_analogs(struct idac_io_analog_state *out)
|
||||
out->accel = tmp.accel;
|
||||
out->brake = tmp.brake;
|
||||
}
|
||||
|
||||
HRESULT idac_io_led_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void idac_io_led_set_fet_output(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]);
|
||||
dprintf("IDAC LED: RIGHT SEAT LED: %02X\n", rgb[1]);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void idac_io_led_gs_update(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
for (int i = 0; i < 9; i++) {
|
||||
dprintf("IDAC LED: LED %d: %02X %02X %02X Speed: %02X\n",
|
||||
i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void idac_io_led_set_leds(const uint8_t *rgb)
|
||||
{
|
||||
#if 0
|
||||
dprintf("IDAC LED: START: %02X\n", rgb[0]);
|
||||
dprintf("IDAC LED: VIEW CHANGE: %02X\n", rgb[1]);
|
||||
dprintf("IDAC LED: UP: %02X\n", rgb[2]);
|
||||
dprintf("IDAC LED: DOWN: %02X\n", rgb[3]);
|
||||
dprintf("IDAC LED: RIGHT: %02X\n", rgb[4]);
|
||||
dprintf("IDAC LED: LEFT: %02X\n", rgb[5]);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -6,3 +6,7 @@ EXPORTS
|
||||
idac_io_get_gamebtns
|
||||
idac_io_get_shifter
|
||||
idac_io_get_analogs
|
||||
idac_io_led_init
|
||||
idac_io_led_set_fet_output
|
||||
idac_io_led_gs_update
|
||||
idac_io_led_set_leds
|
||||
|
@ -19,6 +19,17 @@ enum {
|
||||
IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* These are the bitmasks to use when checking which
|
||||
lights are triggered on incoming IO4 GPIO writes. */
|
||||
IDAC_IO_LED_START = 1 << 31,
|
||||
IDAC_IO_LED_VIEW_CHANGE = 1 << 30,
|
||||
IDAC_IO_LED_UP = 1 << 25,
|
||||
IDAC_IO_LED_DOWN = 1 << 24,
|
||||
IDAC_IO_LED_LEFT = 1 << 23,
|
||||
IDAC_IO_LED_RIGHT = 1 << 22,
|
||||
};
|
||||
|
||||
struct idac_io_analog_state {
|
||||
/* Current steering wheel position, where zero is the centered position.
|
||||
|
||||
@ -92,4 +103,60 @@ void idac_io_get_analogs(struct idac_io_analog_state *out);
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void idac_io_get_shifter(uint8_t *gear);
|
||||
void idac_io_get_shifter(uint8_t *gear);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other idac_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: 0x0101 */
|
||||
|
||||
HRESULT idac_io_led_init(void);
|
||||
|
||||
/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes.
|
||||
|
||||
The following bits are used to control the FET outputs:
|
||||
[0]: LEFT SEAT LED
|
||||
[1]: RIGHT SEAT LED
|
||||
|
||||
The LED is truned on when the byte is 255 and turned off when the byte is 0.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_set_fet_output(const uint8_t *rgb);
|
||||
|
||||
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
|
||||
|
||||
The LEDs are laid out as follows:
|
||||
[0]: LEFT UP LED
|
||||
[1-2]: LEFT CENTER LED
|
||||
[3]: LEFT DOWN LED
|
||||
[5]: RIGHT UP LED
|
||||
[6-7]: RIGHT CENTER LED
|
||||
[8]: RIGHT DOWN LED
|
||||
|
||||
Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed.
|
||||
Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_gs_update(const uint8_t *rgb);
|
||||
|
||||
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
|
||||
|
||||
The LEDs are laid out as follows:
|
||||
[0]: START LED
|
||||
[1]: VIEW CHANGE LED
|
||||
[2]: UP LED
|
||||
[3]: DOWN LED
|
||||
[4]: RIGHT LED
|
||||
[5]: LEFT LED
|
||||
|
||||
The LED is turned on when the byte is 255 and turned off when the byte is 0.
|
||||
|
||||
Minimum API version: 0x0101 */
|
||||
|
||||
void idac_io_led_set_leds(const uint8_t *rgb);
|
||||
|
@ -52,10 +52,6 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT idac_io_poll(void) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) {
|
||||
/* Deadzones check */
|
||||
if (cfg->left_stick_deadzone > 32767 || cfg->left_stick_deadzone < 0) {
|
||||
|
@ -1,3 +1,14 @@
|
||||
/*
|
||||
"Initial D ARCADE STAGE Zero" (idz) hook
|
||||
|
||||
Devices
|
||||
|
||||
JVS: 837-15257 "Type 4" I/O Board
|
||||
COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board
|
||||
COM10: 837-15286 "Gen 2" Aime Reader
|
||||
COM11: 837-15070-02 IC BD LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
|
@ -9,6 +9,7 @@ enum {
|
||||
JVS_CMD_READ_SWITCHES = 0x20,
|
||||
JVS_CMD_READ_COIN = 0x21,
|
||||
JVS_CMD_READ_ANALOGS = 0x22,
|
||||
JVS_CMD_READ_ROTARYS = 0x23,
|
||||
JVS_CMD_WRITE_GPIO = 0x32,
|
||||
JVS_CMD_RESET = 0xF0,
|
||||
JVS_CMD_ASSIGN_ADDR = 0xF1,
|
||||
@ -32,6 +33,11 @@ struct jvs_req_read_analogs {
|
||||
uint8_t nanalogs;
|
||||
};
|
||||
|
||||
struct jvs_req_read_rotarys {
|
||||
uint8_t cmd;
|
||||
uint8_t nrotarys;
|
||||
};
|
||||
|
||||
struct jvs_req_reset {
|
||||
uint8_t cmd;
|
||||
uint8_t unknown;
|
||||
|
@ -39,4 +39,5 @@ void mai2_hook_config_load(
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
mai2_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
#include "unityhook/config.h"
|
||||
|
||||
struct mai2_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
@ -17,6 +19,7 @@ struct mai2_hook_config {
|
||||
struct io4_config io4;
|
||||
struct vfd_config vfd;
|
||||
struct mai2_dll_config dll;
|
||||
struct unity_config unity;
|
||||
};
|
||||
|
||||
void mai2_dll_config_load(
|
||||
|
@ -1,3 +1,22 @@
|
||||
/*
|
||||
"maimai DX" (mai2) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 2 * 601-13216 USB "QR Code" Camera (SDEZ2, SDEZ3)
|
||||
USB: 601-13249 USB "Player" Camera (SDEZ1)
|
||||
USB: 837-15067-02 IC BD USB to Serial 232
|
||||
connected to
|
||||
837-15070-04 LED Board Controller (COM21)
|
||||
837-15070-04 LED Board Controller (COM23)
|
||||
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 509-6483 Touch Panel Controller
|
||||
COM4: 509-6483 Touch Panel Controller
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
@ -5,6 +24,8 @@
|
||||
#include "board/vfd.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
#include "hook/table.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
@ -12,10 +33,11 @@
|
||||
#include "mai2hook/config.h"
|
||||
#include "mai2hook/io4.h"
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
#include "mai2hook/unity.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "unityhook/hook.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE mai2_hook_mod;
|
||||
@ -80,7 +102,7 @@ static DWORD CALLBACK mai2_pre_startup(void)
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the `mai2hook` initialization. */
|
||||
|
||||
unity_hook_init();
|
||||
unity_hook_init(&mai2_hook_cfg.unity, mai2_hook_mod);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
|
@ -15,6 +15,7 @@ shared_library(
|
||||
hooklib_lib,
|
||||
mai2io_lib,
|
||||
platform_lib,
|
||||
unityhook_lib,
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
@ -25,7 +26,5 @@ shared_library(
|
||||
'io4.h',
|
||||
'mai2-dll.c',
|
||||
'mai2-dll.h',
|
||||
'unity.h',
|
||||
'unity.c',
|
||||
],
|
||||
)
|
||||
|
@ -1,95 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
|
||||
static const struct hook_symbol unity_kernel32_syms[] = {
|
||||
{
|
||||
.name = "LoadLibraryW",
|
||||
.patch = my_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
},
|
||||
};
|
||||
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"mono-2.0-bdwgc.dll",
|
||||
L"cri_ware_unity.dll",
|
||||
};
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
|
||||
void unity_hook_init(void)
|
||||
{
|
||||
dll_hook_insert_hooks(NULL);
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
unity_kernel32_syms,
|
||||
_countof(unity_kernel32_syms));
|
||||
}
|
||||
|
||||
static HMODULE WINAPI my_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("Unity: Loaded %S\n", target_module);
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
path_hook_insert_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void unity_hook_init(void);
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
"WACCA" (mercury) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 14-1497-R "Elisabeth" LED Board Controller
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: PSS-7135-L02-01 "Left Side" Touch Board
|
||||
COM4: PSS-7135-L02-01 "Right Sdde" Touch Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
@ -14,6 +14,7 @@ add_project_arguments(
|
||||
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
|
||||
'-DMINGW_HAS_SECURE_API=1',
|
||||
'-Wno-unused',
|
||||
# '-ggdb', # Add debug information
|
||||
language: 'c',
|
||||
)
|
||||
|
||||
@ -23,7 +24,6 @@ if cc.get_id() != 'msvc'
|
||||
add_project_arguments(
|
||||
'-ffunction-sections',
|
||||
'-fdata-sections',
|
||||
'-flto', # Enable Link-Time Optimization
|
||||
language: 'c',
|
||||
)
|
||||
|
||||
@ -32,8 +32,9 @@ if cc.get_id() != 'msvc'
|
||||
'-Wl,--exclude-all-symbols',
|
||||
'-Wl,--gc-sections',
|
||||
'-static-libgcc',
|
||||
'-flto', # Enable Link-Time Optimization
|
||||
'-Wl,-s', # Strip debug symbols
|
||||
# '-ggdb', # Add debug information
|
||||
'-lcrypt32', # Bcrypt needed for prashook
|
||||
# '-Wl,-s', # Strip debug symbols
|
||||
language: 'c',
|
||||
)
|
||||
endif
|
||||
@ -42,6 +43,7 @@ shlwapi_lib = cc.find_library('shlwapi')
|
||||
dinput8_lib = cc.find_library('dinput8')
|
||||
dxguid_lib = cc.find_library('dxguid')
|
||||
xinput_lib = cc.find_library('xinput')
|
||||
pathcch_lib = cc.find_library('pathcch')
|
||||
|
||||
inc = include_directories('.')
|
||||
capnhook = subproject('capnhook')
|
||||
@ -55,6 +57,7 @@ subdir('platform')
|
||||
subdir('util')
|
||||
|
||||
subdir('gfxhook')
|
||||
subdir('unityhook')
|
||||
|
||||
subdir('aimeio')
|
||||
subdir('chuniio')
|
||||
|
@ -28,6 +28,66 @@ void mu3_dll_config_load(
|
||||
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", 0xA0, filename);
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"boardNumber",
|
||||
L"15093-06",
|
||||
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"6710A",
|
||||
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 mu3_hook_config_load(
|
||||
struct mu3_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -40,6 +100,8 @@ void mu3_hook_config_load(
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
mu3_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
// #include "board/led15093.h"
|
||||
#include "board/led15093.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
@ -13,15 +13,18 @@
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
#include "unityhook/config.h"
|
||||
|
||||
struct mu3_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct gfx_config gfx;
|
||||
// struct led15093_config led15093;
|
||||
struct led15093_config led15093;
|
||||
struct vfd_config vfd;
|
||||
struct mu3_dll_config dll;
|
||||
struct unity_config unity;
|
||||
};
|
||||
|
||||
void mu3_dll_config_load(
|
||||
|
@ -1,8 +1,19 @@
|
||||
/*
|
||||
"O.N.G.E.K.I." (mu3) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
USB: 3 * 601-13216 USB "QR Code" Camera (SDDT1-SDDT3)
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM2: 200-6275 VFD GP1232A02A FUTABA Board
|
||||
COM3: 837-15093-06 LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/vfd.h"
|
||||
|
||||
@ -20,10 +31,12 @@
|
||||
#include "mu3hook/config.h"
|
||||
#include "mu3hook/io4.h"
|
||||
#include "mu3hook/mu3-dll.h"
|
||||
#include "mu3hook/unity.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "unityhook/config.h"
|
||||
#include "unityhook/hook.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE mu3_hook_mod;
|
||||
@ -61,14 +74,18 @@ static DWORD CALLBACK mu3_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
// Does not work, Unity moment
|
||||
hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2);
|
||||
hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15093_hook_init(&mu3_hook_cfg.led15093,
|
||||
mu3_dll.led_init, mu3_dll.led_set_leds, 3, 1, 1, 2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
*/
|
||||
|
||||
hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod);
|
||||
|
||||
@ -82,12 +99,6 @@ static DWORD CALLBACK mu3_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mu3_io4_hook_init(&mu3_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
@ -99,7 +110,7 @@ static DWORD CALLBACK mu3_pre_startup(void)
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the `mu3hook` initialization. */
|
||||
|
||||
unity_hook_init();
|
||||
unity_hook_init(&mu3_hook_cfg.unity, mu3_hook_mod);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
|
@ -11,10 +11,13 @@
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
|
||||
static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len);
|
||||
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops mu3_io4_ops = {
|
||||
.poll = mu3_io4_poll,
|
||||
.write_gpio = mu3_io4_write_gpio,
|
||||
};
|
||||
|
||||
HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
|
||||
@ -124,3 +127,46 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state)
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT mu3_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 Ongeki, 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[6 * 3] = {
|
||||
lights_data & MU3_IO_LED_L1_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L1_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L1_B ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L2_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L2_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L2_B ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L3_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L3_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_L3_B ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R1_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R1_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R1_B ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R2_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R2_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R2_B ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R3_R ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R3_G ? 0xFF : 0x00,
|
||||
lights_data & MU3_IO_LED_R3_B ? 0xFF : 0x00,
|
||||
};
|
||||
|
||||
mu3_dll.led_set_leds(1, rgb_out);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ shared_library(
|
||||
hooklib_lib,
|
||||
mu3io_lib,
|
||||
platform_lib,
|
||||
unityhook_lib,
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
@ -27,7 +28,5 @@ shared_library(
|
||||
'io4.h',
|
||||
'mu3-dll.c',
|
||||
'mu3-dll.h',
|
||||
'unity.h',
|
||||
'unity.c',
|
||||
],
|
||||
)
|
||||
|
@ -24,9 +24,28 @@ const struct dll_bind_sym mu3_dll_syms[] = {
|
||||
}, {
|
||||
.sym = "mu3_io_get_lever",
|
||||
.off = offsetof(struct mu3_dll, get_lever),
|
||||
}, {
|
||||
.sym = "mu3_io_led_init",
|
||||
.off = offsetof(struct mu3_dll, led_init),
|
||||
}, {
|
||||
.sym = "mu3_io_led_set_colors",
|
||||
.off = offsetof(struct mu3_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
/* Helper function to determine upon dll_bind failure whether the required functions were found
|
||||
NOTE: relies on symbols order declared above */
|
||||
static HRESULT has_enough_symbols(uint16_t version, uint8_t count)
|
||||
{
|
||||
if ( version <= 0x0100 && count == 5 )
|
||||
return S_OK;
|
||||
|
||||
if ( version >= 0x0101 && count == 7 )
|
||||
return S_OK;
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
struct mu3_dll mu3_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
@ -86,16 +105,25 @@ HRESULT mu3_dll_init(const struct mu3_dll_config *cfg, HINSTANCE self)
|
||||
}
|
||||
|
||||
sym = mu3_dll_syms;
|
||||
const struct dll_bind_sym *init_sym = &sym[0];
|
||||
|
||||
hr = dll_bind(&mu3_dll, src, &sym, _countof(mu3_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Ongeki IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
// Might still be ok depending on external dll API version
|
||||
int bind_count = sym - init_sym;
|
||||
if (has_enough_symbols(mu3_dll.api_version, bind_count) == S_OK)
|
||||
{
|
||||
hr = S_OK;
|
||||
} else {
|
||||
dprintf("Ongeki IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user