forked from TeamTofuShop/segatools
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
64240aa74c | |||
cf1ab0e13f | |||
a16a2338c7 | |||
748b3557ee | |||
e09bf6571e | |||
b7a961ff71 | |||
5becf8798c | |||
7051b849fa | |||
94f9357382 | |||
434382ce4b | |||
16f7272751 | |||
67ffde7289 | |||
eb93c6cf75 | |||
ba9fb5d0b9 | |||
2ec0ee4794 | |||
ccdd07e262 | |||
9d8a38bbf7 | |||
4dcf01f643 | |||
962e14dc9b | |||
5d04685c73 | |||
528ec4379c | |||
5a4e947354 | |||
157f52da4c | |||
0d83977073 | |||
dca84e08d0 | |||
2dbb4aec8c | |||
3d7d9fcaa5 | |||
98d2ea1390 | |||
4c67843f08 | |||
02201dfba5 | |||
9113766c22 | |||
6fc2482c19 | |||
74c8b312c5 | |||
ef00932c64 | |||
8c97dc09c0 | |||
301a0e0ce7 | |||
5935e322e8 | |||
05e762d3ce |
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,6 +1,17 @@
|
|||||||
.*.swp
|
.*.swp
|
||||||
|
|
||||||
.vscode/
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
# Suggested names for build dirs
|
# Suggested names for build dirs
|
||||||
build/
|
build/
|
||||||
|
34
.vscode/settings.json
vendored
34
.vscode/settings.json
vendored
@ -1,3 +1,37 @@
|
|||||||
{
|
{
|
||||||
"editor.formatOnSave": false,
|
"editor.formatOnSave": false,
|
||||||
|
"mesonbuild.configureOnOpen": false,
|
||||||
|
"files.associations": {
|
||||||
|
"string.h": "c",
|
||||||
|
"stdbool.h": "c",
|
||||||
|
"windows.h": "c",
|
||||||
|
"dprintf.h": "c",
|
||||||
|
"touch.h": "c",
|
||||||
|
"mai2-dll.h": "c",
|
||||||
|
"led.h": "c",
|
||||||
|
"path.h": "c",
|
||||||
|
"reg.h": "c",
|
||||||
|
"platform.h": "c",
|
||||||
|
"procaddr.h": "c",
|
||||||
|
"table.h": "c",
|
||||||
|
"serial.h": "c",
|
||||||
|
"stdarg.h": "c",
|
||||||
|
"iphlpapi.h": "c",
|
||||||
|
"iptypes.h": "c",
|
||||||
|
"netenv.h": "c",
|
||||||
|
"nusec.h": "c",
|
||||||
|
"vfs.h": "c",
|
||||||
|
"ws2ipdef.h": "c",
|
||||||
|
"winternl.h": "c",
|
||||||
|
"wincrypt.h": "c",
|
||||||
|
"assert.h": "c",
|
||||||
|
"stdint.h": "c",
|
||||||
|
"limits.h": "c",
|
||||||
|
"stdlib.h": "c",
|
||||||
|
"config.h": "c",
|
||||||
|
"mu3-dll.h": "c",
|
||||||
|
"io4.h": "c",
|
||||||
|
"dvd.h": "c",
|
||||||
|
"uart.h": "c"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
13
Makefile
13
Makefile
@ -5,16 +5,12 @@ V ?= @
|
|||||||
BUILD_DIR := build
|
BUILD_DIR := build
|
||||||
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
||||||
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
||||||
BUILD_DIR_DOCKER := $(BUILD_DIR)/docker
|
|
||||||
BUILD_DIR_ZIP := $(BUILD_DIR)/zip
|
BUILD_DIR_ZIP := $(BUILD_DIR)/zip
|
||||||
|
|
||||||
DOC_DIR := doc
|
DOC_DIR := doc
|
||||||
|
|
||||||
DIST_DIR := dist
|
DIST_DIR := dist
|
||||||
|
|
||||||
DOCKER_CONTAINER_NAME := "segatools-build"
|
|
||||||
DOCKER_IMAGE_NAME := "segatools:build"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Targets
|
# Targets
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@ -42,15 +38,6 @@ zip: $(BUILD_DIR_ZIP)/segatools.zip
|
|||||||
clean:
|
clean:
|
||||||
$(V)rm -rf $(BUILD_DIR) subprojects/capnhook
|
$(V)rm -rf $(BUILD_DIR) subprojects/capnhook
|
||||||
|
|
||||||
.PHONY: build-docker # Build the project in a docker container
|
|
||||||
build-docker:
|
|
||||||
$(V)docker rm -f $(DOCKER_CONTAINER_NAME) 2> /dev/null || true
|
|
||||||
$(V)docker build -t $(DOCKER_IMAGE_NAME) -f Dockerfile .
|
|
||||||
$(V)docker create --name $(DOCKER_CONTAINER_NAME) $(DOCKER_IMAGE_NAME)
|
|
||||||
$(V)rm -rf $(BUILD_DIR_DOCKER)
|
|
||||||
$(V)mkdir -p $(BUILD_DIR_DOCKER)
|
|
||||||
$(V)docker cp $(DOCKER_CONTAINER_NAME):/segatools/$(BUILD_DIR_ZIP) $(BUILD_DIR_DOCKER)
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Utility, combo and alias targets
|
# Utility, combo and alias targets
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
32
Package.mk
32
Package.mk
@ -104,6 +104,36 @@ $(BUILD_DIR_ZIP)/mu3.zip:
|
|||||||
$(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll}
|
$(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll}
|
||||||
$(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip *
|
$(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip *
|
||||||
|
|
||||||
|
$(BUILD_DIR_ZIP)/hkb.zip:
|
||||||
|
$(V)echo ... $@
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/hkb
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/hkb/DEVICE
|
||||||
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
|
$(BUILD_DIR_64)/hkbhook/hkbhook.dll \
|
||||||
|
$(DIST_DIR)/hkb/segatools.ini \
|
||||||
|
$(DIST_DIR)/hkb/start.bat \
|
||||||
|
$(BUILD_DIR_ZIP)/hkb
|
||||||
|
$(V)cp pki/billing.pub \
|
||||||
|
pki/ca.crt \
|
||||||
|
$(BUILD_DIR_ZIP)/hkb/DEVICE
|
||||||
|
$(V)strip $(BUILD_DIR_ZIP)/hkb/*.{exe,dll}
|
||||||
|
$(V)cd $(BUILD_DIR_ZIP)/hkb ; zip -r ../hkb.zip *
|
||||||
|
|
||||||
|
$(BUILD_DIR_ZIP)/mai2.zip:
|
||||||
|
$(V)echo ... $@
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||||
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
|
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
|
||||||
|
$(DIST_DIR)/mai2/segatools.ini \
|
||||||
|
$(DIST_DIR)/mai2/start.bat \
|
||||||
|
$(BUILD_DIR_ZIP)/mai2
|
||||||
|
$(V)cp pki/billing.pub \
|
||||||
|
pki/ca.crt \
|
||||||
|
$(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||||
|
$(V)strip $(BUILD_DIR_ZIP)/mai2/*.{exe,dll}
|
||||||
|
$(V)cd $(BUILD_DIR_ZIP)/mai2 ; zip -r ../mai2.zip *
|
||||||
|
|
||||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||||
$(DOC_DIR)/config \
|
$(DOC_DIR)/config \
|
||||||
$(DOC_DIR)/chunihook.md \
|
$(DOC_DIR)/chunihook.md \
|
||||||
@ -121,6 +151,8 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
|
|||||||
$(BUILD_DIR_ZIP)/idz.zip \
|
$(BUILD_DIR_ZIP)/idz.zip \
|
||||||
$(BUILD_DIR_ZIP)/mercury.zip \
|
$(BUILD_DIR_ZIP)/mercury.zip \
|
||||||
$(BUILD_DIR_ZIP)/mu3.zip \
|
$(BUILD_DIR_ZIP)/mu3.zip \
|
||||||
|
$(BUILD_DIR_ZIP)/hkb.zip \
|
||||||
|
$(BUILD_DIR_ZIP)/mai2.zip \
|
||||||
CHANGELOG.md \
|
CHANGELOG.md \
|
||||||
README.md \
|
README.md \
|
||||||
|
|
||||||
|
35
README.md
35
README.md
@ -1,33 +1,2 @@
|
|||||||
# Segatools
|
# This repository is no longer maintained
|
||||||
|
Please see the new joint repository from [TeamTofuShop](https://gitea.tendokyu.moe/TeamTofuShop/segatools)
|
||||||
Version: `v005`
|
|
||||||
|
|
||||||
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)
|
|
||||||
* Initial D
|
|
||||||
* [Initial D Arcade Stage Zero](doc/idzhook.md)
|
|
||||||
* Wacca
|
|
||||||
* Wacca Lilly R (WIP)
|
|
||||||
|
|
||||||
## End-users
|
|
||||||
|
|
||||||
For setup and configuration guides, refer to the dedicated documents available for each game, see
|
|
||||||
[the links in the previous section](#list-of-supported-games).
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
If you are/want to be a contributor of any kind, e.g. new features, bug fixes, documentation improvements, ..., please
|
|
||||||
read the [contributing documentation](CONTRIBUTING.md), first.
|
|
||||||
|
|
||||||
## Developers
|
|
||||||
|
|
||||||
For development setup and instructions how to build the project, refer to the
|
|
||||||
[dedicated development documentation](doc/development.md).
|
|
||||||
|
@ -3,7 +3,6 @@ aimeio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
link_with : [
|
link_with : [
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
|
13
amex/ds.c
13
amex/ds.c
@ -1,6 +1,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <devioctl.h>
|
#include <devioctl.h>
|
||||||
#include <ntdddisk.h>
|
#include <stdlib.h>
|
||||||
|
#include <winioctl.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -19,13 +20,11 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#define DS_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
|
#define DS_IOCTL_SETUP CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
|
#define DS_IOCTL_READ_SECTOR CTL_CODE(0x8000, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
|
|
||||||
enum {
|
#pragma pack(push, 1)
|
||||||
DS_IOCTL_GET_ABI_VERSION = 0x80006000,
|
|
||||||
DS_IOCTL_SETUP = 0x80006004,
|
|
||||||
DS_IOCTL_READ_SECTOR = 0x80006010,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ds_eeprom {
|
struct ds_eeprom {
|
||||||
uint32_t crc32;
|
uint32_t crc32;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
#endif
|
#endif
|
||||||
#include <devioctl.h>
|
#include <devioctl.h>
|
||||||
#include <ntdddisk.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@ -20,9 +20,7 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
enum {
|
#define EEPROM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
EEPROM_IOCTL_GET_ABI_VERSION = 0x80006000,
|
|
||||||
};
|
|
||||||
|
|
||||||
static HRESULT eeprom_handle_irp(struct irp *irp);
|
static HRESULT eeprom_handle_irp(struct irp *irp);
|
||||||
static HRESULT eeprom_handle_open(struct irp *irp);
|
static HRESULT eeprom_handle_open(struct irp *irp);
|
||||||
|
11
amex/gpio.c
11
amex/gpio.c
@ -1,5 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <ntstatus.h>
|
#include <ntstatus.h>
|
||||||
|
#include <winioctl.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -13,12 +14,10 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
enum {
|
#define GPIO_IOCTL_SET_LEDS CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||||
GPIO_IOCTL_SET_LEDS = 0x8000A004,
|
#define GPIO_IOCTL_GET_PSW CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
GPIO_IOCTL_GET_PSW = 0x80006008,
|
#define GPIO_IOCTL_GET_DIPSW CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
GPIO_IOCTL_GET_DIPSW = 0x8000600C,
|
#define GPIO_IOCTL_DESCRIBE CTL_CODE(0x8000, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
GPIO_IOCTL_DESCRIBE = 0x80006014,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GPIO_TYPE_NONE = 0,
|
GPIO_TYPE_NONE = 0,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <winternl.h>
|
#include <winternl.h>
|
||||||
|
|
||||||
#include <ntstatus.h>
|
#include <ntstatus.h>
|
||||||
|
#include <winioctl.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -21,11 +22,9 @@
|
|||||||
#include "util/dump.h"
|
#include "util/dump.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
enum {
|
#define JVS_IOCTL_HELLO CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
JVS_IOCTL_HELLO = 0x80006004,
|
#define JVS_IOCTL_TRANSACT CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
||||||
JVS_IOCTL_SENSE = 0x8000600C,
|
#define JVS_IOCTL_SENSE CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
JVS_IOCTL_TRANSACT = 0x8000E008,
|
|
||||||
};
|
|
||||||
|
|
||||||
static HRESULT jvs_handle_irp(struct irp *irp);
|
static HRESULT jvs_handle_irp(struct irp *irp);
|
||||||
static HRESULT jvs_handle_open(struct irp *irp);
|
static HRESULT jvs_handle_open(struct irp *irp);
|
||||||
|
@ -2,7 +2,6 @@ amex_lib = static_library(
|
|||||||
'amex',
|
'amex',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
#endif
|
#endif
|
||||||
#include <devioctl.h>
|
#include <devioctl.h>
|
||||||
#include <ntdddisk.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@ -20,9 +20,7 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
enum {
|
#define SRAM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||||
SRAM_IOCTL_GET_ABI_VERSION = 0x80006000,
|
|
||||||
};
|
|
||||||
|
|
||||||
static HRESULT sram_handle_irp(struct irp *irp);
|
static HRESULT sram_handle_irp(struct irp *irp);
|
||||||
static HRESULT sram_handle_open(struct irp *irp);
|
static HRESULT sram_handle_open(struct irp *irp);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "board/io3.h"
|
#include "board/io3.h"
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* System buttons in button[0] */
|
/* System buttons in button[0] */
|
||||||
|
@ -2,7 +2,6 @@ board_lib = static_library(
|
|||||||
'board',
|
'board',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
|
@ -21,9 +21,18 @@ const struct dll_bind_sym carol_dll_syms[] = {
|
|||||||
}, {
|
}, {
|
||||||
.sym = "carol_io_touch_init",
|
.sym = "carol_io_touch_init",
|
||||||
.off = offsetof(struct carol_dll, touch_init),
|
.off = offsetof(struct carol_dll, touch_init),
|
||||||
|
}, {
|
||||||
|
.sym = "carol_io_ledbd_init",
|
||||||
|
.off = offsetof(struct carol_dll, ledbd_init),
|
||||||
}, {
|
}, {
|
||||||
.sym = "carol_io_controlbd_init",
|
.sym = "carol_io_controlbd_init",
|
||||||
.off = offsetof(struct carol_dll, controlbd_init),
|
.off = offsetof(struct carol_dll, controlbd_init),
|
||||||
|
}, {
|
||||||
|
.sym = "carol_io_touch_start",
|
||||||
|
.off = offsetof(struct carol_dll, touch_start),
|
||||||
|
}, {
|
||||||
|
.sym = "carol_io_touch_stop",
|
||||||
|
.off = offsetof(struct carol_dll, touch_stop),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,10 @@ struct carol_dll {
|
|||||||
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
|
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
|
||||||
void (*jvs_read_coin_counter)(uint16_t *total);
|
void (*jvs_read_coin_counter)(uint16_t *total);
|
||||||
HRESULT (*touch_init)();
|
HRESULT (*touch_init)();
|
||||||
|
HRESULT (*ledbd_init)();
|
||||||
HRESULT (*controlbd_init)();
|
HRESULT (*controlbd_init)();
|
||||||
|
void (*touch_start)(carol_io_touch_callback_t callback);
|
||||||
|
void (*touch_stop)();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct carol_dll_config {
|
struct carol_dll_config {
|
||||||
|
@ -16,4 +16,7 @@ EXPORTS
|
|||||||
carol_io_jvs_poll
|
carol_io_jvs_poll
|
||||||
carol_io_jvs_read_coin_counter
|
carol_io_jvs_read_coin_counter
|
||||||
carol_io_touch_init
|
carol_io_touch_init
|
||||||
|
carol_io_ledbd_init
|
||||||
carol_io_controlbd_init
|
carol_io_controlbd_init
|
||||||
|
carol_io_touch_start
|
||||||
|
carol_io_touch_stop
|
||||||
|
@ -58,6 +58,20 @@ void controlbd_config_load(
|
|||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ledbd_config_load(
|
||||||
|
struct ledbd_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
cfg->enable = GetPrivateProfileIntW(
|
||||||
|
L"ledbd",
|
||||||
|
L"enable",
|
||||||
|
1,
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void carol_hook_config_load(
|
void carol_hook_config_load(
|
||||||
struct carol_hook_config *cfg,
|
struct carol_hook_config *cfg,
|
||||||
@ -73,4 +87,5 @@ void carol_hook_config_load(
|
|||||||
gfx_config_load(&cfg->gfx, filename);
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
touch_config_load(&cfg->touch, filename);
|
touch_config_load(&cfg->touch, filename);
|
||||||
controlbd_config_load(&cfg->controlbd, filename);
|
controlbd_config_load(&cfg->controlbd, filename);
|
||||||
|
ledbd_config_load(&cfg->ledbd, filename);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "gfxhook/gfx.h"
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
#include "carolhook/touch.h"
|
#include "carolhook/touch.h"
|
||||||
|
#include "carolhook/ledbd.h"
|
||||||
#include "carolhook/controlbd.h"
|
#include "carolhook/controlbd.h"
|
||||||
|
|
||||||
struct carol_hook_config {
|
struct carol_hook_config {
|
||||||
@ -22,6 +23,7 @@ struct carol_hook_config {
|
|||||||
struct carol_dll_config dll;
|
struct carol_dll_config dll;
|
||||||
struct gfx_config gfx;
|
struct gfx_config gfx;
|
||||||
struct touch_config touch;
|
struct touch_config touch;
|
||||||
|
struct ledbd_config ledbd;
|
||||||
struct controlbd_config controlbd;
|
struct controlbd_config controlbd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,10 +18,18 @@
|
|||||||
|
|
||||||
static HRESULT controlbd_handle_irp(struct irp *irp);
|
static HRESULT controlbd_handle_irp(struct irp *irp);
|
||||||
static HRESULT controlbd_handle_irp_locked(struct irp *irp);
|
static HRESULT controlbd_handle_irp_locked(struct irp *irp);
|
||||||
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf);
|
static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src);
|
||||||
static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest);
|
static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len);
|
||||||
|
static uint8_t calc_checksum(void *data, size_t len);
|
||||||
|
|
||||||
static HRESULT controlbd_req_nop(uint8_t cmd);
|
static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req);
|
||||||
|
static HRESULT controlbd_req_ack_any(uint8_t cmd);
|
||||||
|
static HRESULT controlbd_req_reset(void);
|
||||||
|
static HRESULT controlbd_req_get_board_info(void);
|
||||||
|
static HRESULT controlbd_req_firmware_checksum(void);
|
||||||
|
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req);
|
||||||
|
|
||||||
|
const uint8_t CONTROLBD_SYNC_BYTE = 0xE0;
|
||||||
|
|
||||||
static CRITICAL_SECTION controlbd_lock;
|
static CRITICAL_SECTION controlbd_lock;
|
||||||
static struct uart controlbd_uart;
|
static struct uart controlbd_uart;
|
||||||
@ -36,7 +44,7 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
|
|||||||
|
|
||||||
InitializeCriticalSection(&controlbd_lock);
|
InitializeCriticalSection(&controlbd_lock);
|
||||||
|
|
||||||
uart_init(&controlbd_uart, 11);
|
uart_init(&controlbd_uart, 12);
|
||||||
controlbd_uart.written.bytes = controlbd_written_bytes;
|
controlbd_uart.written.bytes = controlbd_written_bytes;
|
||||||
controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes);
|
controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes);
|
||||||
controlbd_uart.readable.bytes = controlbd_readable_bytes;
|
controlbd_uart.readable.bytes = controlbd_readable_bytes;
|
||||||
@ -64,10 +72,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobuf *src)
|
||||||
|
{
|
||||||
|
uint8_t data_len = 0;
|
||||||
|
uint8_t checksum_pos = src->pos - 1;
|
||||||
|
uint8_t calculated_checksum = 0;
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
|
||||||
|
if (src->pos < 6) {
|
||||||
|
dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos);
|
||||||
|
return SEC_E_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->hdr.sync = src->bytes[0];
|
||||||
|
req->hdr.dest = src->bytes[1];
|
||||||
|
req->hdr.src = src->bytes[2];
|
||||||
|
req->hdr.len = src->bytes[3];
|
||||||
|
req->hdr.cmd = src->bytes[4];
|
||||||
|
data_len = req->hdr.len;
|
||||||
|
src->pos -= 5;
|
||||||
|
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
if (src->pos == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
req->bytes[i] = src->bytes[i + 5];
|
||||||
|
src->pos --;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum = src->bytes[checksum_pos];
|
||||||
|
calculated_checksum = calc_checksum(req, checksum_pos);
|
||||||
|
|
||||||
|
if (checksum != calculated_checksum) {
|
||||||
|
dprintf("Control Board: Decode Error, checksum failure (expected 0x%02X, got 0x%02X)\n", calculated_checksum, checksum);
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_CRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||||
{
|
{
|
||||||
struct controlbd_req req;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
struct controlbd_req_any req;
|
||||||
|
|
||||||
assert(carol_dll.controlbd_init != NULL);
|
assert(carol_dll.controlbd_init != NULL);
|
||||||
|
|
||||||
@ -76,7 +123,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||||||
hr = carol_dll.controlbd_init();
|
hr = carol_dll.controlbd_init();
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("Control Board: Backend DLL error: %x\n", (int) hr);
|
dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@ -89,90 +136,204 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
if (controlbd_uart.written.bytes[0] == 0xE0) {
|
||||||
#if 0
|
#if 0
|
||||||
dprintf("Control Board: TX Buffer:\n");
|
dprintf("Control Board: TX Buffer:\n");
|
||||||
dump_iobuf(&controlbd_uart.written);
|
dump_iobuf(&controlbd_uart.written);
|
||||||
#endif
|
#endif
|
||||||
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
||||||
|
if (FAILED(hr)) {
|
||||||
if (FAILED(hr)) {
|
dprintf("Control Board: Deframe error: %x\n", (int) hr);
|
||||||
dprintf("Control Board: Deframe Error: %x\n", (int) hr);
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = controlbd_req_dispatch(&req);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
dprintf("Control Board: RX Buffer:\n");
|
||||||
|
dump_iobuf(&controlbd_uart.readable);
|
||||||
|
#endif
|
||||||
|
controlbd_uart.written.pos = 0;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = controlbd_frame_dispatch(&req);
|
// The board has a LPC111x bootloader that gets ran over every boot
|
||||||
if (FAILED(hr)) {
|
// this is to account for that.
|
||||||
dprintf("Control Board: Dispatch Error: %x\n", (int) hr);
|
char cmd[255];
|
||||||
|
strcpy_s(cmd, 255, (char *)controlbd_uart.written.bytes);
|
||||||
|
cmd[controlbd_uart.written.pos] = '\0';
|
||||||
|
|
||||||
return hr;
|
if (!strcmp(cmd, "?")) {
|
||||||
|
dprintf("Control Board: Bootloader Hello\n");
|
||||||
|
}
|
||||||
|
else if (!strcmp(cmd, "Synchronized\r\n")) {
|
||||||
|
iobuf_write(&controlbd_uart.readable, "Synchronized\r\nNG\r\n", 19);
|
||||||
|
// Set this to OK instead of NG to do an update
|
||||||
|
}
|
||||||
|
else if (!strcmp(cmd, "12000\r\n")) {
|
||||||
|
iobuf_write(&controlbd_uart.readable, "12000\r\nOK\r\n", 12);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Everything other then the two commands above just want 0\r\n
|
||||||
|
// appended to the request as the response. Given that it only checks sometimes,
|
||||||
|
// it's safe to just run over the readable buffer every response.
|
||||||
|
controlbd_uart.readable.pos = 0;
|
||||||
|
cmd[controlbd_uart.written.pos] = '0';
|
||||||
|
cmd[controlbd_uart.written.pos + 1] = '\r';
|
||||||
|
cmd[controlbd_uart.written.pos + 2] = '\n';
|
||||||
|
cmd[controlbd_uart.written.pos + 3] = '\0';
|
||||||
|
// dprintf("Control Board: Return %s\n", cmd);
|
||||||
|
iobuf_write(&controlbd_uart.readable, cmd, controlbd_uart.written.pos + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controlbd_uart.written.pos = 0;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT controlbd_frame_dispatch(struct controlbd_req *req)
|
static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
|
||||||
{
|
{
|
||||||
switch (req->cmd) {
|
switch (req->hdr.cmd) {
|
||||||
case CONTROLBD_CMD_UNK_11:
|
case CONTROLBD_CMD_RESET:
|
||||||
return controlbd_req_nop(req->cmd);
|
return controlbd_req_reset();
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_BDINFO:
|
||||||
|
return controlbd_req_get_board_info();
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_FIRM_SUM:
|
||||||
|
return controlbd_req_firmware_checksum();
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_TIMEOUT:
|
||||||
|
dprintf("Control Board: Acknowledge Timeout\n");
|
||||||
|
return controlbd_req_ack_any(req->hdr.cmd);
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_PORT_SETTING:
|
||||||
|
dprintf("Control Board: Acknowledge Port Setting\n");
|
||||||
|
return controlbd_req_ack_any(req->hdr.cmd);
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_INITIALIZE:
|
||||||
|
dprintf("Control Board: Acknowledge Initialize\n");
|
||||||
|
return controlbd_req_ack_any(req->hdr.cmd);
|
||||||
|
|
||||||
|
case CONTROLBD_CMD_POLLING:
|
||||||
|
return controlbd_req_polling(req);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dprintf("Unhandled command %#02x\n", req->cmd);
|
dprintf("Unhandled command 0x%02x\n", req->hdr.cmd);
|
||||||
|
return controlbd_req_ack_any(req->hdr.cmd);
|
||||||
return S_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT controlbd_req_nop(uint8_t cmd)
|
static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len)
|
||||||
{
|
{
|
||||||
dprintf("Control Board: No-op cmd %#02x\n", cmd);
|
resp->sync = CONTROLBD_SYNC_BYTE;
|
||||||
|
resp->dest = 0x01;
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0xE0;
|
resp->src = 0x02;
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
resp->len = len;
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x11;
|
resp->report = 0x01;
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x03;
|
resp->cmd = cmd;
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x10;
|
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
|
||||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x27;
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decodes the response into a struct that's easier to work with. */
|
static uint8_t calc_checksum(void *data, size_t len)
|
||||||
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf)
|
|
||||||
{
|
{
|
||||||
int initial_pos = iobuf->pos;
|
uint8_t *stuff;
|
||||||
uint8_t check = 0;
|
stuff = data;
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
uint16_t tmp = 0;
|
||||||
|
|
||||||
dest->sync = iobuf->bytes[0];
|
for (int i = 1; i < len; i++) {
|
||||||
iobuf->pos--;
|
tmp = checksum + stuff[i];
|
||||||
|
checksum = tmp & 0xFF;
|
||||||
dest->cmd = iobuf->bytes[1];
|
|
||||||
iobuf->pos--;
|
|
||||||
check += dest->cmd;
|
|
||||||
|
|
||||||
dest->checksum = iobuf->bytes[initial_pos - 1];
|
|
||||||
iobuf->pos--;
|
|
||||||
|
|
||||||
dest->data_length = initial_pos - 3; // sync, cmd, checksum
|
|
||||||
if (dest->data_length > 0) {
|
|
||||||
for (int i = 0; i < dest->data_length; i++) {
|
|
||||||
dest->data[i] = iobuf->bytes[i+2];
|
|
||||||
check += dest->data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iobuf->pos -= dest->data_length;
|
|
||||||
|
|
||||||
if (dest->sync != 0xe0) {
|
|
||||||
dprintf("Control Board: Sync error, expected 0xe0, got %x\n", dest->sync);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
if (dest->checksum != check) {
|
|
||||||
dprintf("Control Board: Checksum error, expected %x, got %x\n", check, dest->checksum);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return S_OK;
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_req_reset(void)
|
||||||
|
{
|
||||||
|
struct controlbd_resp_reset resp;
|
||||||
|
|
||||||
|
dprintf("Control Board: Reset\n");
|
||||||
|
|
||||||
|
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_RESET, 2);
|
||||||
|
resp.checksum = 0;
|
||||||
|
|
||||||
|
// No data, just ack
|
||||||
|
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||||
|
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_req_get_board_info(void)
|
||||||
|
{
|
||||||
|
struct controlbd_resp_bdinfo resp;
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
dprintf("Control Board: Get Board Info\n");
|
||||||
|
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_BDINFO, 21);
|
||||||
|
|
||||||
|
resp.rev = 0x90;
|
||||||
|
resp.bfr_size = 0x0001;
|
||||||
|
resp.ack = 1;
|
||||||
|
|
||||||
|
strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 ");
|
||||||
|
strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 ");
|
||||||
|
resp.chip_no[5] = 0xFF;
|
||||||
|
resp.bd_no[8] = 0x0A;
|
||||||
|
|
||||||
|
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||||
|
|
||||||
|
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_req_firmware_checksum(void)
|
||||||
|
{
|
||||||
|
struct controlbd_resp_fw_checksum resp;
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
dprintf("Control Board: Get Firmware Checksum\n");
|
||||||
|
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_FIRM_SUM, 5);
|
||||||
|
|
||||||
|
resp.ack = 1;
|
||||||
|
resp.fw_checksum = 0x1b36; // This could change with an update... oh well
|
||||||
|
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||||
|
|
||||||
|
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
|
||||||
|
{
|
||||||
|
struct controlbd_req_polling req_struct;
|
||||||
|
memset(&req_struct, 0, sizeof(req_struct));
|
||||||
|
memcpy_s(&req_struct, sizeof(req_struct), req, sizeof(req_struct));
|
||||||
|
struct controlbd_resp_polling resp;
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_POLLING, 16);
|
||||||
|
// TODO: Figure out output (pen vibration, etc)
|
||||||
|
|
||||||
|
resp.ack = 1;
|
||||||
|
resp.unk7 = 3;
|
||||||
|
resp.unk8 = 1;
|
||||||
|
resp.unk9 = 1;
|
||||||
|
|
||||||
|
resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge
|
||||||
|
resp.coord_x = 0x0;
|
||||||
|
resp.coord_y = 0x0;
|
||||||
|
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||||
|
|
||||||
|
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT controlbd_req_ack_any(uint8_t cmd)
|
||||||
|
{
|
||||||
|
struct controlbd_resp_any_ack resp;
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
controlbd_set_header(&resp.hdr, cmd, 3);
|
||||||
|
|
||||||
|
resp.ack = 1;
|
||||||
|
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||||
|
|
||||||
|
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -7,15 +9,140 @@
|
|||||||
struct controlbd_config {
|
struct controlbd_config {
|
||||||
bool enable;
|
bool enable;
|
||||||
};
|
};
|
||||||
enum controlbd_cmd {
|
|
||||||
CONTROLBD_CMD_UNK_11 = 0x11
|
#pragma pack(push, 1)
|
||||||
};
|
struct controlbd_req_hdr {
|
||||||
struct controlbd_req {
|
uint8_t sync;
|
||||||
uint8_t sync; // First byte is the sync
|
uint8_t dest; // unsure
|
||||||
uint8_t cmd; // Command byte
|
uint8_t src; // unsure
|
||||||
uint8_t data[256]; // Request body goes here
|
uint8_t len; // length of the rest of the request minus checksum
|
||||||
uint8_t checksum; // Final byte is all bytes added, except the sync
|
uint8_t cmd;
|
||||||
uint8_t data_length; // Size of the data including command byte
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_any {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t bytes[255];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_reset {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t payload;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_bdinfo {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_fw_checksum {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_timeout {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t unknown;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_req_polling {
|
||||||
|
struct controlbd_req_hdr hdr;
|
||||||
|
uint8_t unknown[20];
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_hdr {
|
||||||
|
uint8_t sync;
|
||||||
|
uint8_t dest; // unsure
|
||||||
|
uint8_t src; // unsure
|
||||||
|
uint8_t len; // length of the rest of the request minus checksum
|
||||||
|
uint8_t report; // 0x01 for success, anything else for failure
|
||||||
|
uint8_t cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_any {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t bytes[255];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_any_ack {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t ack;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_reset {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_bdinfo {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t ack;
|
||||||
|
char bd_no[9];
|
||||||
|
char chip_no[6];
|
||||||
|
uint8_t rev;
|
||||||
|
uint16_t bfr_size;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_fw_checksum {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t ack;
|
||||||
|
uint16_t fw_checksum;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct controlbd_resp_polling {
|
||||||
|
struct controlbd_resp_hdr hdr;
|
||||||
|
uint8_t ack;
|
||||||
|
uint8_t unk7;
|
||||||
|
uint8_t unk8;
|
||||||
|
uint8_t unk9;
|
||||||
|
uint8_t btns_pressed;
|
||||||
|
uint8_t blob[7];
|
||||||
|
int8_t coord_x;
|
||||||
|
int8_t coord_y;
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PEN_BTN_PRESSED_BIT = 1,
|
||||||
|
DODGE_BTN_PRESSED_BIT = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CONTROLBD_CMD_RESET = 0x10,
|
||||||
|
CONTROLBD_CMD_TIMEOUT = 0x11,
|
||||||
|
CONTROLBD_CMD_RETRY = 0x12,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_GETIN = 0x20,
|
||||||
|
CONTROLBD_CMD_GETADI = 0x21,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_SETOUTPUT = 0x30,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_INITIALIZE = 0x80,
|
||||||
|
CONTROLBD_CMD_POLLING = 0x81,
|
||||||
|
CONTROLBD_CMD_CUSTOM_PATTERN = 0x82,
|
||||||
|
CONTROLBD_CMD_DEBUG_CAROL = 0x83,
|
||||||
|
CONTROLBD_CMD_POLLING_GENERAL = 0x84,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_CMD_STATUS = 0x90,
|
||||||
|
CONTROLBD_CMD_PORT_SETTING = 0x91,
|
||||||
|
CONTROLBD_CMD_PWM_DUTY = 0x92,
|
||||||
|
CONTROLBD_CMD_LED_SET = 0x93,
|
||||||
|
CONTROLBD_CMD_LED_REFRESH = 0x94,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_DEBUG_UART = 0xB0,
|
||||||
|
CONTROLBD_CMD_DEBUG_I2C = 0xB1,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_DEBUG_STATUS = 0xC0,
|
||||||
|
|
||||||
|
CONTROLBD_CMD_BDINFO = 0xF0,
|
||||||
|
CONTROLBD_CMD_FIRM_SUM = 0xF2,
|
||||||
|
CONTROLBD_CMD_PROTOCOL = 0xF3,
|
||||||
|
CONTROLBD_CMD_UPDATE = 0xFE,
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
HRESULT controlbd_hook_init(const struct controlbd_config *cfg);
|
HRESULT controlbd_hook_init(const struct controlbd_config *cfg);
|
@ -12,13 +12,15 @@
|
|||||||
#include "carolhook/carol-dll.h"
|
#include "carolhook/carol-dll.h"
|
||||||
#include "carolhook/jvs.h"
|
#include "carolhook/jvs.h"
|
||||||
#include "carolhook/touch.h"
|
#include "carolhook/touch.h"
|
||||||
|
#include "carolhook/ledbd.h"
|
||||||
#include "carolhook/controlbd.h"
|
#include "carolhook/controlbd.h"
|
||||||
#include "carolhook/serial.h"
|
|
||||||
|
|
||||||
#include "hook/process.h"
|
#include "hook/process.h"
|
||||||
|
|
||||||
#include "hooklib/serial.h"
|
#include "hooklib/serial.h"
|
||||||
#include "hooklib/spike.h"
|
#include "hooklib/spike.h"
|
||||||
|
#include "hooklib/createprocess.h"
|
||||||
|
#include "hooklib/cursor.h"
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
@ -30,17 +32,43 @@ static struct carol_hook_config carol_hook_cfg;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
COM Layout
|
COM Layout
|
||||||
01:(?) Touchscreen
|
01: Touchscreen
|
||||||
10: Aime reader
|
10: Aime reader
|
||||||
11: Control board
|
11: LED board
|
||||||
12(?): LED Board
|
12: Control Board
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static DWORD CALLBACK carol_pre_startup(void)
|
static DWORD CALLBACK carol_pre_startup(void)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
HMODULE d3dc;
|
||||||
|
HMODULE dbghelp;
|
||||||
|
|
||||||
dprintf("--- Begin carol_pre_startup ---\n");
|
dprintf("--- Begin carol_pre_startup ---\n");
|
||||||
|
if ( !SetProcessDPIAware() )
|
||||||
|
dprintf("Failed to set process DPI awareness level!\n");
|
||||||
|
|
||||||
|
/* Pin the D3D shader compiler. This makes startup much faster. */
|
||||||
|
|
||||||
|
d3dc = LoadLibraryW(L"D3DCompiler_43.dll");
|
||||||
|
|
||||||
|
if (d3dc != NULL) {
|
||||||
|
dprintf("Pinned shader compiler, hMod=%p\n", d3dc);
|
||||||
|
} else {
|
||||||
|
dprintf("Failed to load shader compiler!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pin dbghelp so the path hooks apply to it. */
|
||||||
|
|
||||||
|
dbghelp = LoadLibraryW(L"dbghelp.dll");
|
||||||
|
|
||||||
|
if (dbghelp != NULL) {
|
||||||
|
dprintf("Pinned debug helper library, hMod=%p\n", dbghelp);
|
||||||
|
} else {
|
||||||
|
dprintf("Failed to load debug helper library!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_hook_init();
|
||||||
|
|
||||||
/* Config load */
|
/* Config load */
|
||||||
|
|
||||||
@ -82,8 +110,6 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||||||
|
|
||||||
gfx_hook_init(&carol_hook_cfg.gfx);
|
gfx_hook_init(&carol_hook_cfg.gfx);
|
||||||
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
||||||
//serial_init();
|
|
||||||
|
|
||||||
|
|
||||||
hr = touch_hook_init(&carol_hook_cfg.touch);
|
hr = touch_hook_init(&carol_hook_cfg.touch);
|
||||||
|
|
||||||
@ -91,12 +117,23 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = ledbd_hook_init(&carol_hook_cfg.ledbd);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
hr = controlbd_hook_init(&carol_hook_cfg.controlbd);
|
hr = controlbd_hook_init(&carol_hook_cfg.controlbd);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL, false);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
spike_hook_init(L".\\segatools.ini");
|
spike_hook_init(L".\\segatools.ini");
|
||||||
|
168
carolhook/ledbd.c
Normal file
168
carolhook/ledbd.c
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
#include "hook/iohook.h"
|
||||||
|
|
||||||
|
#include "carolhook/carol-dll.h"
|
||||||
|
#include "carolhook/ledbd.h"
|
||||||
|
|
||||||
|
#include "hooklib/uart.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
#include "util/dump.h"
|
||||||
|
|
||||||
|
#include "board/slider-frame.h"
|
||||||
|
#include "board/slider-cmd.h"
|
||||||
|
|
||||||
|
static HRESULT ledbd_handle_irp(struct irp *irp);
|
||||||
|
static HRESULT ledbd_handle_irp_locked(struct irp *irp);
|
||||||
|
static HRESULT ledbd_frame_dispatch(const union slider_req_any *dest);
|
||||||
|
|
||||||
|
static HRESULT ledbd_req_noop(uint8_t cmd);
|
||||||
|
static HRESULT ledbd_req_unk7c(uint8_t cmd);
|
||||||
|
static HRESULT ledbd_req_unkF0(uint8_t cmd);
|
||||||
|
|
||||||
|
static CRITICAL_SECTION ledbd_lock;
|
||||||
|
static struct uart ledbd_uart;
|
||||||
|
static uint8_t ledbd_written_bytes[520];
|
||||||
|
static uint8_t ledbd_readable_bytes[520];
|
||||||
|
|
||||||
|
HRESULT ledbd_hook_init(const struct ledbd_config *cfg)
|
||||||
|
{
|
||||||
|
if (!cfg->enable) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeCriticalSection(&ledbd_lock);
|
||||||
|
|
||||||
|
uart_init(&ledbd_uart, 11);
|
||||||
|
ledbd_uart.written.bytes = ledbd_written_bytes;
|
||||||
|
ledbd_uart.written.nbytes = sizeof(ledbd_written_bytes);
|
||||||
|
ledbd_uart.readable.bytes = ledbd_readable_bytes;
|
||||||
|
ledbd_uart.readable.nbytes = sizeof(ledbd_readable_bytes);
|
||||||
|
|
||||||
|
dprintf("LED Board: Init\n");
|
||||||
|
|
||||||
|
return iohook_push_handler(ledbd_handle_irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_handle_irp(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(irp != NULL);
|
||||||
|
|
||||||
|
if (!uart_match_irp(&ledbd_uart, irp)) {
|
||||||
|
return iohook_invoke_next(irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection(&ledbd_lock);
|
||||||
|
hr = ledbd_handle_irp_locked(irp);
|
||||||
|
LeaveCriticalSection(&ledbd_lock);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_handle_irp_locked(struct irp *irp)
|
||||||
|
{
|
||||||
|
union slider_req_any req;
|
||||||
|
struct iobuf req_iobuf;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(carol_dll.ledbd_init != NULL);
|
||||||
|
|
||||||
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
|
dprintf("LED Board: Starting backend DLL\n");
|
||||||
|
hr = carol_dll.ledbd_init();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = uart_handle_irp(&ledbd_uart, irp);
|
||||||
|
|
||||||
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
#if 0
|
||||||
|
dprintf("LED Board: TX Buffer:\n");
|
||||||
|
dump_iobuf(&ledbd_uart.written);
|
||||||
|
#endif
|
||||||
|
req_iobuf.bytes = req.bytes;
|
||||||
|
req_iobuf.nbytes = sizeof(req.bytes);
|
||||||
|
req_iobuf.pos = 0;
|
||||||
|
|
||||||
|
hr = slider_frame_decode(&req_iobuf, &ledbd_uart.written);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = ledbd_frame_dispatch(&req);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_frame_dispatch(const union slider_req_any *req)
|
||||||
|
{
|
||||||
|
switch (req->hdr.cmd) {
|
||||||
|
case LEDBD_CMD_UNK_10:
|
||||||
|
return ledbd_req_noop(req->hdr.cmd);
|
||||||
|
case LEDBD_CMD_UNK_7C:
|
||||||
|
return ledbd_req_unk7c(req->hdr.cmd);
|
||||||
|
case LEDBD_CMD_UNK_F0:
|
||||||
|
return ledbd_req_unkF0(req->hdr.cmd);
|
||||||
|
case LEDBD_CMD_UNK_30:
|
||||||
|
return ledbd_req_noop(req->hdr.cmd);
|
||||||
|
default:
|
||||||
|
//dprintf("Unhandled command 0x%02X\n", req->cmd);
|
||||||
|
return ledbd_req_noop(req->hdr.cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_req_noop(uint8_t cmd)
|
||||||
|
{
|
||||||
|
//dprintf("LED Board: Noop cmd 0x%02X\n", cmd);
|
||||||
|
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 };
|
||||||
|
resp[5] = cmd;
|
||||||
|
resp[7] = 0x17 + cmd;
|
||||||
|
iobuf_write(&ledbd_uart.readable, resp, 8);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_req_unk7c(uint8_t cmd)
|
||||||
|
{
|
||||||
|
//dprintf("LED Board: Cmd 0x7C\n");
|
||||||
|
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B };
|
||||||
|
iobuf_write(&ledbd_uart.readable, resp, 9);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT ledbd_req_unkF0(uint8_t cmd)
|
||||||
|
{
|
||||||
|
//dprintf("LED Board: Cmd 0xF0\n");
|
||||||
|
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E };
|
||||||
|
iobuf_write(&ledbd_uart.readable, resp, 16);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
28
carolhook/ledbd.h
Normal file
28
carolhook/ledbd.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct ledbd_config {
|
||||||
|
bool enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ledbd_cmd {
|
||||||
|
LEDBD_CMD_UNK_10 = 0x10,
|
||||||
|
LEDBD_CMD_UNK_7C = 0x7C,
|
||||||
|
LEDBD_CMD_UNK_30 = 0x30,
|
||||||
|
LEDBD_CMD_UNK_F0 = 0xF0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ledbd_req {
|
||||||
|
uint8_t sync; // Sync byte, always 0xE0
|
||||||
|
uint8_t dest; // command destination id?
|
||||||
|
uint8_t src; // command source id?
|
||||||
|
uint8_t data_len; // length of the proceeding data bytes
|
||||||
|
uint8_t cmd; // might be the command byte?
|
||||||
|
uint8_t data[255]; // rest of the data, len = data_len - 1
|
||||||
|
uint8_t checksum; // final byte is all bytes (excluding sync) added
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT ledbd_hook_init(const struct ledbd_config *cfg);
|
@ -4,7 +4,6 @@ shared_library(
|
|||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'carolhook.def',
|
vs_module_defs : 'carolhook.def',
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
@ -32,7 +31,7 @@ shared_library(
|
|||||||
'touch.h',
|
'touch.h',
|
||||||
'controlbd.c',
|
'controlbd.c',
|
||||||
'controlbd.h',
|
'controlbd.h',
|
||||||
'serial.c',
|
'ledbd.c',
|
||||||
'serial.h',
|
'ledbd.h',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
#include <winbase.h>
|
|
||||||
|
|
||||||
#include "hook/table.h"
|
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
|
||||||
|
|
||||||
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB);
|
|
||||||
static BOOL (WINAPI *next_SetCommState)(HANDLE hFile, LPDCB lpDCB);
|
|
||||||
static void com_hook_insert_hooks(HMODULE target);
|
|
||||||
|
|
||||||
static const struct hook_symbol win32_hooks[] = {
|
|
||||||
{
|
|
||||||
.name = "SetCommState",
|
|
||||||
.patch = my_SetCommState,
|
|
||||||
.link = (void **) &next_SetCommState
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void serial_init()
|
|
||||||
{
|
|
||||||
com_hook_insert_hooks(NULL);
|
|
||||||
dprintf("Serial: Spy init\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void com_hook_insert_hooks(HMODULE target)
|
|
||||||
{
|
|
||||||
hook_table_apply(
|
|
||||||
target,
|
|
||||||
"kernel32.dll",
|
|
||||||
win32_hooks,
|
|
||||||
_countof(win32_hooks));
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB)
|
|
||||||
{
|
|
||||||
dprintf("Serial: my_SetCommState with baudrate %ld\n", lpDCB->BaudRate);
|
|
||||||
return next_SetCommState(hFile, lpDCB);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winbase.h>
|
|
||||||
|
|
||||||
void serial_init();
|
|
@ -8,19 +8,46 @@
|
|||||||
#include "carolhook/carol-dll.h"
|
#include "carolhook/carol-dll.h"
|
||||||
#include "carolhook/touch.h"
|
#include "carolhook/touch.h"
|
||||||
|
|
||||||
|
#include "hook/table.h"
|
||||||
|
|
||||||
#include "hooklib/uart.h"
|
#include "hooklib/uart.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/dump.h"
|
#include "util/dump.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CMDS for touch thing
|
||||||
|
* CX -> Calibrate Extend, preform callibration
|
||||||
|
* MS -> Mode Stream, enters stream mode
|
||||||
|
* R -> Reset, resets the device
|
||||||
|
* RD -> Reset Default, Resets the device to factory
|
||||||
|
* Z -> Null, keepalive command
|
||||||
|
* NM -> Name, return the name of the device (not documented?)
|
||||||
|
* OI -> Output Identity, output unique device identity, SC followed by 4 characters
|
||||||
|
* UT -> Unit Type, returns controller unit type + status
|
||||||
|
*/
|
||||||
|
|
||||||
static HRESULT touch_handle_irp(struct irp *irp);
|
static HRESULT touch_handle_irp(struct irp *irp);
|
||||||
static HRESULT touch_handle_irp_locked(struct irp *irp);
|
static HRESULT touch_handle_irp_locked(struct irp *irp);
|
||||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf);
|
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf);
|
||||||
|
|
||||||
|
static HRESULT handle_touch_ack_cmd(const struct touch_req *req);
|
||||||
|
static HRESULT handle_touch_name_cmd(const struct touch_req *req);
|
||||||
|
static HRESULT handle_touch_id_cmd(const struct touch_req *req);
|
||||||
|
static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req);
|
||||||
|
static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y);
|
||||||
|
|
||||||
static CRITICAL_SECTION touch_lock;
|
static CRITICAL_SECTION touch_lock;
|
||||||
static struct uart touch_uart;
|
static struct uart touch_uart;
|
||||||
static uint8_t touch_written_bytes[520];
|
static uint8_t touch_written_bytes[528];
|
||||||
static uint8_t touch_readable_bytes[520];
|
static uint8_t touch_readable_bytes[528];
|
||||||
|
static bool should_stream = false;
|
||||||
|
static bool last_pressed;
|
||||||
|
static uint8_t last_x1;
|
||||||
|
static uint8_t last_x2;
|
||||||
|
static uint8_t last_y1;
|
||||||
|
static uint8_t last_y2;
|
||||||
|
|
||||||
|
|
||||||
HRESULT touch_hook_init(const struct touch_config *cfg)
|
HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||||
{
|
{
|
||||||
@ -69,9 +96,10 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||||||
if (irp->op == IRP_OP_OPEN) {
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
dprintf("Touchscreen: Starting backend DLL\n");
|
dprintf("Touchscreen: Starting backend DLL\n");
|
||||||
hr = carol_dll.touch_init();
|
hr = carol_dll.touch_init();
|
||||||
|
carol_dll.touch_start(touch_scan_auto);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("Touchscreen: Backend DLL error: %x\n", (int) hr);
|
dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@ -84,35 +112,142 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
#if 1
|
#if 0
|
||||||
dprintf("Touchscreen: TX Buffer:\n");
|
dprintf("Touchscreen: TX Buffer:\n");
|
||||||
dump_iobuf(&touch_uart.written);
|
dump_iobuf(&touch_uart.written);
|
||||||
#endif
|
#endif
|
||||||
hr = touch_frame_decode(&req, &touch_uart.written);
|
hr = touch_frame_decode(&req, &touch_uart.written);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dprintf("Touchscreen: Deframe Error: %x\n", (int) hr);
|
dprintf("Touchscreen: Deframe Error: %X\n", (int) hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp("Z", (char *)req.cmd)) {
|
||||||
|
hr = handle_touch_ack_cmd(&req);
|
||||||
|
}
|
||||||
|
else if (!strcmp("OI", (char *)req.cmd)) {
|
||||||
|
hr = handle_touch_id_cmd(&req);
|
||||||
|
}
|
||||||
|
else if (!strcmp("UT", (char *)req.cmd)) {
|
||||||
|
hr = handle_touch_unit_type_cmd(&req);
|
||||||
|
}
|
||||||
|
else if (!strcmp("NM", (char *)req.cmd)) {
|
||||||
|
hr = handle_touch_name_cmd(&req);
|
||||||
|
}
|
||||||
|
else if (!strcmp("R", (char *)req.cmd)) {
|
||||||
|
carol_dll.touch_stop();
|
||||||
|
dprintf("Touch: Reset\n");
|
||||||
|
hr = handle_touch_ack_cmd(&req);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dprintf("Touchscreen: Unhandled cmd %s\n", (char *)req.cmd);
|
||||||
|
hr = handle_touch_ack_cmd(&req);
|
||||||
|
}
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT handle_touch_ack_cmd(const struct touch_req *req)
|
||||||
|
{
|
||||||
|
return iobuf_write(&touch_uart.readable, "\0010\015", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT handle_touch_name_cmd(const struct touch_req *req)
|
||||||
|
{
|
||||||
|
dprintf("Touch: Get Name\n");
|
||||||
|
return iobuf_write(&touch_uart.readable, "\001AD1000\015", 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT handle_touch_id_cmd(const struct touch_req *req)
|
||||||
|
{
|
||||||
|
dprintf("Touch: Get ID\n");
|
||||||
|
return iobuf_write(&touch_uart.readable, "\001AD1000\015", 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req)
|
||||||
|
{
|
||||||
|
dprintf("Touch: Get Unit Type\n");
|
||||||
|
return iobuf_write(&touch_uart.readable, "\001AD****00\015", 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y)
|
||||||
|
{
|
||||||
|
struct touch_auto_resp resp;
|
||||||
|
uint16_t tmp_x;
|
||||||
|
uint16_t tmp_y;
|
||||||
|
bool flg = false;
|
||||||
|
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
resp.touches[0].status |= 1 << 7;
|
||||||
|
|
||||||
|
if (is_pressed) {
|
||||||
|
resp.touches[0].status |= (1 << 7) | (1 << 6);
|
||||||
|
resp.touches[0].touch_id = 1;
|
||||||
|
tmp_x = mouse_x & 0x7FFF;
|
||||||
|
tmp_y = mouse_y & 0x7FFF;
|
||||||
|
|
||||||
|
resp.touches[0].x1 = tmp_x & 0x7F;
|
||||||
|
resp.touches[0].x2 = (tmp_x >> 7) & 0x7F;
|
||||||
|
resp.touches[0].y1 = tmp_y & 0x7F;
|
||||||
|
resp.touches[0].y2 = (tmp_y >> 7) & 0x7F;
|
||||||
|
|
||||||
|
flg = resp.touches[0].x1 != last_x1 || resp.touches[0].x2 != last_x2 || resp.touches[0].y1 != last_y1 || resp.touches[0].y2 != last_y2;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (flg)
|
||||||
|
dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
last_x1 = resp.touches[0].x1;
|
||||||
|
last_x2 = resp.touches[0].x2;
|
||||||
|
last_y1 = resp.touches[0].y1;
|
||||||
|
last_y2 = resp.touches[0].y2;
|
||||||
|
|
||||||
|
} else if (last_pressed) {
|
||||||
|
resp.touches[0].x1 = last_x1;
|
||||||
|
resp.touches[0].x2 = last_x2;
|
||||||
|
resp.touches[0].y1 = last_y1;
|
||||||
|
resp.touches[0].y2 = last_y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_pressed = is_pressed;
|
||||||
|
|
||||||
|
EnterCriticalSection(&touch_lock);
|
||||||
|
iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
|
||||||
|
LeaveCriticalSection(&touch_lock);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
|
||||||
|
dump_iobuf(&touch_uart.readable);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Decodes the response into a struct that's easier to work with. */
|
/* Decodes the response into a struct that's easier to work with. */
|
||||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
|
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
|
||||||
{
|
{
|
||||||
dest->cmd = iobuf->bytes[0];
|
dest->sync = iobuf->bytes[0];
|
||||||
iobuf->pos--;
|
memset(dest->cmd, 0, sizeof(dest->cmd));
|
||||||
dest->data_length = iobuf->pos;
|
size_t data_len = 0;
|
||||||
|
|
||||||
if (dest->data_length > 0) {
|
for (int i = 1; i < 255; i++) {
|
||||||
for (int i = 1; i < dest->data_length; i++) {
|
if (iobuf->bytes[i] == 0x0D) { break; }
|
||||||
dest->data[i-1] = iobuf->bytes[i];
|
dest->cmd[i - 1] = iobuf->bytes[i];
|
||||||
}
|
data_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->tail = iobuf->bytes[data_len + 1];
|
||||||
|
dest->data_len = data_len;
|
||||||
|
|
||||||
|
iobuf->pos = 0;
|
||||||
|
|
||||||
|
if (dest->sync != 1 || dest->tail != 0x0D) {
|
||||||
|
dprintf("Touch: Data recieve error, sync: 0x%02X (expected 0x01) tail: 0x%02X (expected 0x0D)", dest->sync, dest->tail);
|
||||||
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
iobuf->pos -= dest->data_length;
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
@ -4,14 +4,42 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct touch_config {
|
struct touch_config {
|
||||||
bool enable;
|
bool enable;
|
||||||
|
unsigned int port_no;
|
||||||
|
char board_id[7];
|
||||||
|
char unit_type[9];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Always starts with 0x01, always ends with 0x0D
|
||||||
struct touch_req {
|
struct touch_req {
|
||||||
uint8_t cmd; // First byte is the command byte
|
uint8_t sync; // Always 0x01
|
||||||
uint8_t data[256]; // rest of the data goes here
|
uint8_t cmd[256]; // rest of the data goes here
|
||||||
uint8_t data_length; // Size of the data including command byte
|
uint8_t tail; // Always 0x0D
|
||||||
|
size_t data_len; // length of data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct touch_report {
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t x1;
|
||||||
|
uint8_t x2;
|
||||||
|
uint8_t y1;
|
||||||
|
uint8_t y2;
|
||||||
|
uint8_t touch_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct touch_auto_resp {
|
||||||
|
struct touch_report touches[10];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TOUCH_MODE_STREAM = 0x01,
|
||||||
|
TOUCH_MODE_DOWN_UP = 0x02,
|
||||||
|
TOUCH_MODE_INACTIVE = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
HRESULT touch_hook_init(const struct touch_config *cfg);
|
HRESULT touch_hook_init(const struct touch_config *cfg);
|
@ -7,10 +7,16 @@
|
|||||||
|
|
||||||
#include "carolio/carolio.h"
|
#include "carolio/carolio.h"
|
||||||
#include "carolio/config.h"
|
#include "carolio/config.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx);
|
||||||
|
|
||||||
static bool carol_io_coin;
|
static bool carol_io_coin;
|
||||||
static uint16_t carol_io_coins;
|
static uint16_t carol_io_coins;
|
||||||
static struct carol_io_config carol_io_cfg;
|
static struct carol_io_config carol_io_cfg;
|
||||||
|
static bool carol_io_touch_stop_flag;
|
||||||
|
static HANDLE carol_io_touch_thread;
|
||||||
|
static bool carol_io_window_focus = false;
|
||||||
|
|
||||||
uint16_t carol_io_get_api_version(void)
|
uint16_t carol_io_get_api_version(void)
|
||||||
{
|
{
|
||||||
@ -73,7 +79,103 @@ HRESULT carol_io_touch_init()
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT carol_io_ledbd_init()
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT carol_io_controlbd_init()
|
HRESULT carol_io_controlbd_init()
|
||||||
{
|
{
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void carol_io_touch_start(carol_io_touch_callback_t callback)
|
||||||
|
{
|
||||||
|
if (carol_io_touch_thread != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
carol_io_touch_stop_flag = false;
|
||||||
|
|
||||||
|
carol_io_touch_thread = (HANDLE) _beginthreadex(
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
carol_io_touch_thread_proc,
|
||||||
|
callback,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void carol_io_touch_stop()
|
||||||
|
{
|
||||||
|
carol_io_touch_stop_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_fg_wind(void)
|
||||||
|
{
|
||||||
|
HWND hwnd = GetForegroundWindow();
|
||||||
|
wchar_t window_class[MAX_PATH];
|
||||||
|
|
||||||
|
/* Unlike every other game, we can't use GetWindowText here. Why?
|
||||||
|
|
||||||
|
From MSDN:
|
||||||
|
|
||||||
|
"If the window does not have a caption, the return value is a null
|
||||||
|
string. This behavior is by design. It allows applications to call
|
||||||
|
GetWindowText without becoming unresponsive if the process that owns
|
||||||
|
the target window is not responding. However, if the target window
|
||||||
|
is not responding and it belongs to the calling application,
|
||||||
|
GetWindowText will cause the calling application to become
|
||||||
|
unresponsive."
|
||||||
|
|
||||||
|
Great, thanks Microsoft, very cool. Luckily Carol sets its class
|
||||||
|
name to the window title too so we can use that. */
|
||||||
|
|
||||||
|
GetClassNameW(hwnd, window_class, MAX_PATH);
|
||||||
|
|
||||||
|
if (wcscmp(window_class, L"WONDER Master")) {
|
||||||
|
if (carol_io_window_focus) {
|
||||||
|
dprintf("Carol IO: Window focus lost\n");
|
||||||
|
carol_io_window_focus = false;
|
||||||
|
}
|
||||||
|
} else if (!carol_io_window_focus) {
|
||||||
|
dprintf("Carol IO: Window focus regained\n");
|
||||||
|
carol_io_window_focus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx)
|
||||||
|
{
|
||||||
|
carol_io_touch_callback_t callback;
|
||||||
|
bool mouse_is_down = false;
|
||||||
|
uint16_t mX = 0;
|
||||||
|
uint16_t mY = 0;
|
||||||
|
POINT lpPoint;
|
||||||
|
HWND hwnd;
|
||||||
|
|
||||||
|
callback = ctx;
|
||||||
|
|
||||||
|
while (!carol_io_touch_stop_flag) {
|
||||||
|
check_fg_wind();
|
||||||
|
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
|
||||||
|
mouse_is_down = true;
|
||||||
|
if (GetCursorPos(&lpPoint)) {
|
||||||
|
hwnd = GetForegroundWindow();
|
||||||
|
if (ScreenToClient(hwnd, &lpPoint)) {
|
||||||
|
if (lpPoint.x < 0) lpPoint.x = 0;
|
||||||
|
if (lpPoint.y < 0) lpPoint.y = 0;
|
||||||
|
mX = (uint16_t)lpPoint.x;
|
||||||
|
mY = (uint16_t)lpPoint.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mouse_is_down = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(mouse_is_down, mX, mY);
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -5,6 +5,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y);
|
||||||
|
|
||||||
/* Get the version of the Project carol IO API that this DLL supports. This
|
/* Get the version of the Project carol IO API that this DLL supports. This
|
||||||
function should return a positive 16-bit integer, where the high byte is
|
function should return a positive 16-bit integer, where the high byte is
|
||||||
the major version and the low byte is the minor version (as defined by the
|
the major version and the low byte is the minor version (as defined by the
|
||||||
@ -49,4 +51,10 @@ void carol_io_jvs_read_coin_counter(uint16_t *out);
|
|||||||
|
|
||||||
HRESULT carol_io_touch_init();
|
HRESULT carol_io_touch_init();
|
||||||
|
|
||||||
|
HRESULT carol_io_ledbd_init();
|
||||||
|
|
||||||
HRESULT carol_io_controlbd_init();
|
HRESULT carol_io_controlbd_init();
|
||||||
|
|
||||||
|
void carol_io_touch_start(carol_io_touch_callback_t callback);
|
||||||
|
|
||||||
|
void carol_io_touch_stop();
|
@ -3,7 +3,6 @@ carolio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
sources : [
|
sources : [
|
||||||
'carolio.c',
|
'carolio.c',
|
||||||
'carolio.h',
|
'carolio.h',
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "amex/amex.h"
|
#include "amex/amex.h"
|
||||||
#include "amex/config.h"
|
#include "amex/config.h"
|
||||||
|
@ -4,7 +4,6 @@ shared_library(
|
|||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'chunihook.def',
|
vs_module_defs : 'chunihook.def',
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "chuniio/chuniio.h"
|
#include "chuniio/chuniio.h"
|
||||||
#include "chuniio/config.h"
|
#include "chuniio/config.h"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -3,7 +3,6 @@ chuniio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
sources : [
|
sources : [
|
||||||
'chuniio.c',
|
'chuniio.c',
|
||||||
'chuniio.h',
|
'chuniio.h',
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "cxbhook/led.h"
|
#include "cxbhook/led.h"
|
||||||
#include "cxbhook/cxb-dll.h"
|
#include "cxbhook/cxb-dll.h"
|
||||||
|
|
||||||
#include "hooklib/procaddr.h"
|
#include "hook/procaddr.h"
|
||||||
|
|
||||||
#include "hook/table.h"
|
#include "hook/table.h"
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ static struct hook_symbol lamp_syms[] = {
|
|||||||
HRESULT led_hook_init(struct led_config *cfg)
|
HRESULT led_hook_init(struct led_config *cfg)
|
||||||
{
|
{
|
||||||
dprintf("LED: Init\n");
|
dprintf("LED: Init\n");
|
||||||
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int my_cCommLamp_Open(char *port)
|
static int my_cCommLamp_Open(char *port)
|
||||||
|
@ -4,7 +4,6 @@ shared_library(
|
|||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'cxbhook.def',
|
vs_module_defs : 'cxbhook.def',
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
struct network_config {
|
struct network_config {
|
||||||
bool enable;
|
bool enable;
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <winuser.h>
|
#include <winuser.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "cxbhook/revio.h"
|
#include "cxbhook/revio.h"
|
||||||
#include "cxbhook/cxb-dll.h"
|
#include "cxbhook/cxb-dll.h"
|
||||||
|
|
||||||
#include "hooklib/procaddr.h"
|
#include "hook/procaddr.h"
|
||||||
|
|
||||||
#include "hook/table.h"
|
#include "hook/table.h"
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ static struct hook_symbol revio_syms[] = {
|
|||||||
HRESULT revio_hook_init(struct revio_config *cfg)
|
HRESULT revio_hook_init(struct revio_config *cfg)
|
||||||
{
|
{
|
||||||
dprintf("Revio: Init\n");
|
dprintf("Revio: Init\n");
|
||||||
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
|
return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int my_cCommIo_Open(char *port)
|
static int my_cCommIo_Open(char *port)
|
||||||
|
@ -3,7 +3,6 @@ cxbio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
sources : [
|
sources : [
|
||||||
'cxbio.c',
|
'cxbio.c',
|
||||||
'cxbio.h',
|
'cxbio.h',
|
||||||
|
41
dist/hkb/segatools.ini
vendored
Normal file
41
dist/hkb/segatools.ini
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
[vfs]
|
||||||
|
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||||
|
amfs=amfs
|
||||||
|
; Create an empty directory somewhere and insert the path here.
|
||||||
|
; This directory may be shared between multiple SEGA games.
|
||||||
|
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||||
|
appdata=appdata
|
||||||
|
option=Option
|
||||||
|
|
||||||
|
[dns]
|
||||||
|
; Insert the hostname or IP address of the server you wish to use here.
|
||||||
|
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||||
|
default=127.0.0.1
|
||||||
|
|
||||||
|
[ds]
|
||||||
|
; Region code on the emulated AMEX board DS EEPROM.
|
||||||
|
; 1: Japan
|
||||||
|
; 4: Export (some UI elements in English)
|
||||||
|
;
|
||||||
|
; NOTE: Changing this setting causes a factory reset.
|
||||||
|
region=1
|
||||||
|
|
||||||
|
[netenv]
|
||||||
|
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||||
|
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||||
|
; setting enabled is recommended.
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[keychip]
|
||||||
|
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||||
|
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||||
|
; that subnet must start with 192.168.
|
||||||
|
subnet=192.168.155.0
|
||||||
|
|
||||||
|
[gfx]
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[io4]
|
||||||
|
test=0x31
|
||||||
|
service=0x32
|
||||||
|
coin=0x33
|
11
dist/hkb/start.bat
vendored
Normal file
11
dist/hkb/start.bat
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@echo off
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
|
start inject.exe -d -k hkbhook.dll amdaemon.exe -f -c common.json terminal.json satellite.json
|
||||||
|
inject.exe -d -k hkbhook.dll hkb.exe -screen-fullscreen 0 -screen-quality Fantastic -silent-crashes -logFile gameLog.txt
|
||||||
|
|
||||||
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
|
echo Game processes have terminated
|
44
dist/mai2/segatools.ini
vendored
Normal file
44
dist/mai2/segatools.ini
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
[vfs]
|
||||||
|
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||||
|
amfs=amfs
|
||||||
|
; Create an empty directory somewhere and insert the path here.
|
||||||
|
; This directory may be shared between multiple SEGA games.
|
||||||
|
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||||
|
appdata=appdata
|
||||||
|
option=option
|
||||||
|
|
||||||
|
[dns]
|
||||||
|
; Insert the hostname or IP address of the server you wish to use here.
|
||||||
|
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||||
|
default=127.0.0.1
|
||||||
|
|
||||||
|
[ds]
|
||||||
|
; Region code on the emulated AMEX board DS EEPROM.
|
||||||
|
; 1: Japan
|
||||||
|
; 4: Export (some UI elements in English)
|
||||||
|
;
|
||||||
|
; NOTE: Changing this setting causes a factory reset.
|
||||||
|
region=1
|
||||||
|
|
||||||
|
[netenv]
|
||||||
|
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||||
|
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||||
|
; setting enabled is recommended.
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[keychip]
|
||||||
|
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||||
|
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||||
|
; that subnet must start with 192.168.
|
||||||
|
subnet=192.168.172.0
|
||||||
|
|
||||||
|
[gfx]
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[io4]
|
||||||
|
; Delete
|
||||||
|
test=0x2E
|
||||||
|
; End
|
||||||
|
service=0x23
|
||||||
|
; Insert
|
||||||
|
coin=0x2D
|
11
dist/mai2/start.bat
vendored
Normal file
11
dist/mai2/start.bat
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@echo off
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
|
start inject -d -k mai2hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||||
|
inject.exe -d -k mai2hook.dll Sinmai.exe -screen-fullscreen 0 -screen-width 2160 -screen-height 1920
|
||||||
|
|
||||||
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
|
echo Game processes have terminated
|
2
dist/mu3/segatools.ini
vendored
2
dist/mu3/segatools.ini
vendored
@ -30,7 +30,7 @@ enable=1
|
|||||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||||
; that subnet must start with 192.168.
|
; that subnet must start with 192.168.
|
||||||
subnet=192.168.250.0
|
subnet=192.168.162.0
|
||||||
|
|
||||||
[gfx]
|
[gfx]
|
||||||
enable=1
|
enable=1
|
||||||
|
8
dist/mu3/start.bat
vendored
8
dist/mu3/start.bat
vendored
@ -3,12 +3,8 @@ pushd %~dp0
|
|||||||
|
|
||||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
REM USA
|
start inject -d -k mu3hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||||
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
|
inject -d -k mu3hook.dll mu3.exe
|
||||||
|
|
||||||
REM JP
|
|
||||||
start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
|
||||||
inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe
|
|
||||||
|
|
||||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ shared_library(
|
|||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'divahook.def',
|
vs_module_defs : 'divahook.def',
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
@ -3,7 +3,6 @@ divaio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
sources : [
|
sources : [
|
||||||
'divaio.c',
|
'divaio.c',
|
||||||
'divaio.h',
|
'divaio.h',
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
setlocal enabledelayedexpansion
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
:: Static Environment Variables
|
:: Static Environment Variables
|
||||||
set BUILD_OUTPUT_PATH=build\docker
|
|
||||||
set IMAGE_NAME=djhackers/segatools-build:latest
|
set IMAGE_NAME=djhackers/segatools-build:latest
|
||||||
set CONTAINER_NAME=segatools-build
|
set CONTAINER_NAME=segatools-build
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ gfxhook_lib = static_library(
|
|||||||
'gfxhook',
|
'gfxhook',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
dxguid_lib,
|
dxguid_lib,
|
||||||
|
53
hkbhook/config.c
Normal file
53
hkbhook/config.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
#include "gfxhook/config.h"
|
||||||
|
|
||||||
|
#include "hooklib/config.h"
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
|
||||||
|
#include "hkbhook/config.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
void hkb_dll_config_load(
|
||||||
|
struct hkb_dll_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"hkbio",
|
||||||
|
L"path",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkb_led_config_load(
|
||||||
|
struct hkb_led_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
cfg->enable = GetPrivateProfileIntW(L"led", L"enable", 1, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkb_hook_config_load(
|
||||||
|
struct hkb_hook_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
platform_config_load(&cfg->platform, filename);
|
||||||
|
aime_config_load(&cfg->aime, filename);
|
||||||
|
dvd_config_load(&cfg->dvd, filename);
|
||||||
|
io4_config_load(&cfg->io4, filename);
|
||||||
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
|
hkb_dll_config_load(&cfg->dll, filename);
|
||||||
|
hkb_led_config_load(&cfg->led, filename);
|
||||||
|
}
|
33
hkbhook/config.h
Normal file
33
hkbhook/config.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
|
||||||
|
#include "hkbhook/hkb-dll.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
#include "hkbhook/led.h"
|
||||||
|
|
||||||
|
struct hkb_hook_config {
|
||||||
|
struct platform_config platform;
|
||||||
|
struct aime_config aime;
|
||||||
|
struct dvd_config dvd;
|
||||||
|
struct io4_config io4;
|
||||||
|
struct gfx_config gfx;
|
||||||
|
struct hkb_dll_config dll;
|
||||||
|
struct hkb_led_config led;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hkb_dll_config_load(
|
||||||
|
struct hkb_dll_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
||||||
|
void hkb_hook_config_load(
|
||||||
|
struct hkb_hook_config *cfg,
|
||||||
|
const wchar_t *filename);
|
154
hkbhook/dllmain.c
Normal file
154
hkbhook/dllmain.c
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
#include "board/sg-reader.h"
|
||||||
|
#include "board/vfd.h"
|
||||||
|
|
||||||
|
#include "gfxhook/d3d9.h"
|
||||||
|
#include "gfxhook/d3d11.h"
|
||||||
|
#include "gfxhook/dxgi.h"
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
|
#include "hook/process.h"
|
||||||
|
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
#include "hooklib/spike.h"
|
||||||
|
#include "hooklib/cursor.h"
|
||||||
|
|
||||||
|
#include "hkbhook/config.h"
|
||||||
|
#include "hkbhook/io4.h"
|
||||||
|
#include "hkbhook/led.h"
|
||||||
|
#include "hkbhook/hkb-dll.h"
|
||||||
|
#include "hkbhook/unity.h"
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HMODULE hkb_hook_mod;
|
||||||
|
static process_entry_t hkb_startup;
|
||||||
|
static struct hkb_hook_config hkb_hook_cfg;
|
||||||
|
|
||||||
|
static DWORD CALLBACK hkb_pre_startup(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
dprintf("--- Begin hkb_pre_startup ---\n");
|
||||||
|
|
||||||
|
/* Load config */
|
||||||
|
|
||||||
|
hkb_hook_config_load(&hkb_hook_cfg, L".\\segatools.ini");
|
||||||
|
|
||||||
|
/* Hook Win32 APIs */
|
||||||
|
|
||||||
|
dvd_hook_init(&hkb_hook_cfg.dvd, hkb_hook_mod);
|
||||||
|
gfx_hook_init(&hkb_hook_cfg.gfx);
|
||||||
|
gfx_d3d9_hook_init(&hkb_hook_cfg.gfx, hkb_hook_mod);
|
||||||
|
gfx_d3d11_hook_init(&hkb_hook_cfg.gfx, hkb_hook_mod);
|
||||||
|
gfx_dxgi_hook_init(&hkb_hook_cfg.gfx, hkb_hook_mod);
|
||||||
|
serial_hook_init();
|
||||||
|
|
||||||
|
/* Initialize emulation hooks */
|
||||||
|
|
||||||
|
hr = platform_hook_init(
|
||||||
|
&hkb_hook_cfg.platform,
|
||||||
|
"SDEC",
|
||||||
|
"ACA2",
|
||||||
|
hkb_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_hook_init();
|
||||||
|
// COM1: Touch
|
||||||
|
// COM2: LED (Satalite)
|
||||||
|
// COM3: Reader (Satalite)
|
||||||
|
// COM3: LED (Terminal)
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hkb_hook_cfg.platform.nusec.platform_id[0] != '\0' && hkb_hook_cfg.platform.nusec.platform_id[3] == '4') {
|
||||||
|
hr = led_hook_init(&hkb_hook_cfg.led, 3);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hr = sg_reader_hook_init(&hkb_hook_cfg.aime, 1, hkb_hook_mod);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hr = vfd_hook_init(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
hr = led_hook_init(&hkb_hook_cfg.led, 2);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hr = sg_reader_hook_init(&hkb_hook_cfg.aime, 3, hkb_hook_mod);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hr = vfd_hook_init(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = hkb_dll_init(&hkb_hook_cfg.dll, hkb_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = hkb_io4_hook_init(&hkb_hook_cfg.io4);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize Unity native plugin DLL hooks
|
||||||
|
|
||||||
|
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||||
|
hooked earlier in the `hkbhook` initialization. */
|
||||||
|
|
||||||
|
unity_hook_init();
|
||||||
|
|
||||||
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
|
spike_hook_init(L".\\segatools.ini");
|
||||||
|
|
||||||
|
dprintf("--- End hkb_pre_startup ---\n");
|
||||||
|
|
||||||
|
/* Jump to EXE start address */
|
||||||
|
|
||||||
|
return hkb_startup();
|
||||||
|
|
||||||
|
fail:
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (cause != DLL_PROCESS_ATTACH) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hkb_hook_mod = mod;
|
||||||
|
|
||||||
|
hr = process_hijack_startup(hkb_pre_startup, &hkb_startup);
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
103
hkbhook/hkb-dll.c
Normal file
103
hkbhook/hkb-dll.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "hkbhook/hkb-dll.h"
|
||||||
|
|
||||||
|
#include "util/dll-bind.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
const struct dll_bind_sym hkb_dll_syms[] = {
|
||||||
|
{
|
||||||
|
.sym = "hkb_io_init",
|
||||||
|
.off = offsetof(struct hkb_dll, init),
|
||||||
|
}, {
|
||||||
|
.sym = "hkb_io_poll",
|
||||||
|
.off = offsetof(struct hkb_dll, poll),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hkb_dll hkb_dll;
|
||||||
|
|
||||||
|
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||||
|
// Not much of this lends itself to being easily factored out. Also there
|
||||||
|
// will be a lot of API-specific branching code here eventually as new API
|
||||||
|
// versions get defined, so even though these functions all look the same
|
||||||
|
// now this won't remain the case forever.
|
||||||
|
|
||||||
|
HRESULT hkb_dll_init(const struct hkb_dll_config *cfg, HINSTANCE self)
|
||||||
|
{
|
||||||
|
uint16_t (*get_api_version)(void);
|
||||||
|
const struct dll_bind_sym *sym;
|
||||||
|
HINSTANCE owned;
|
||||||
|
HINSTANCE src;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(self != NULL);
|
||||||
|
|
||||||
|
if (cfg->path[0] != L'\0') {
|
||||||
|
owned = LoadLibraryW(cfg->path);
|
||||||
|
|
||||||
|
if (owned == NULL) {
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
dprintf("Ongeki IO: Failed to load IO DLL: %lx: %S\n",
|
||||||
|
hr,
|
||||||
|
cfg->path);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Ongeki IO: Using custom IO DLL: %S\n", cfg->path);
|
||||||
|
src = owned;
|
||||||
|
} else {
|
||||||
|
owned = NULL;
|
||||||
|
src = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "hkb_io_get_api_version");
|
||||||
|
|
||||||
|
if (get_api_version != NULL) {
|
||||||
|
hkb_dll.api_version = get_api_version();
|
||||||
|
} else {
|
||||||
|
hkb_dll.api_version = 0x0100;
|
||||||
|
dprintf("Custom IO DLL does not expose hkb_io_get_api_version, "
|
||||||
|
"assuming API version 1.0.\n"
|
||||||
|
"Please ask the developer to update their DLL.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hkb_dll.api_version >= 0x0200) {
|
||||||
|
hr = E_NOTIMPL;
|
||||||
|
dprintf("Ongeki IO: Custom IO DLL implements an unsupported "
|
||||||
|
"API version (%#04x). Please update Segatools.\n",
|
||||||
|
hkb_dll.api_version);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = hkb_dll_syms;
|
||||||
|
hr = dll_bind(&hkb_dll, src, &sym, _countof(hkb_dll_syms));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (src != self) {
|
||||||
|
dprintf("Ongeki IO: Custom IO DLL does not provide function "
|
||||||
|
"\"%s\". Please contact your IO DLL's developer for "
|
||||||
|
"further assistance.\n",
|
||||||
|
sym->sym);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
owned = NULL;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (owned != NULL) {
|
||||||
|
FreeLibrary(owned);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
19
hkbhook/hkb-dll.h
Normal file
19
hkbhook/hkb-dll.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "hkbio/hkbio.h"
|
||||||
|
|
||||||
|
struct hkb_dll {
|
||||||
|
uint16_t api_version;
|
||||||
|
HRESULT (*init)(void);
|
||||||
|
HRESULT (*poll)(uint8_t *opbtn, uint8_t *gamebtn);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hkb_dll_config {
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct hkb_dll hkb_dll;
|
||||||
|
|
||||||
|
HRESULT hkb_dll_init(const struct hkb_dll_config *cfg, HINSTANCE self);
|
22
hkbhook/hkbhook.def
Normal file
22
hkbhook/hkbhook.def
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
LIBRARY hkbhook
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
CreateDXGIFactory
|
||||||
|
CreateDXGIFactory1
|
||||||
|
CreateDXGIFactory2
|
||||||
|
D3D11CreateDevice
|
||||||
|
D3D11CreateDeviceAndSwapChain
|
||||||
|
Direct3DCreate9
|
||||||
|
aime_io_get_api_version
|
||||||
|
aime_io_init
|
||||||
|
aime_io_led_set_color
|
||||||
|
aime_io_nfc_get_aime_id
|
||||||
|
aime_io_nfc_get_felica_id
|
||||||
|
aime_io_nfc_poll
|
||||||
|
amDllVideoClose @2
|
||||||
|
amDllVideoGetVBiosVersion @4
|
||||||
|
amDllVideoOpen @1
|
||||||
|
amDllVideoSetResolution @3
|
||||||
|
hkb_io_get_api_version
|
||||||
|
hkb_io_init
|
||||||
|
hkb_io_poll
|
109
hkbhook/io4.c
Normal file
109
hkbhook/io4.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
|
||||||
|
#include "hkbhook/hkb-dll.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
bool hkb_io_coin = false;
|
||||||
|
uint16_t hkb_io_coins = 0;
|
||||||
|
|
||||||
|
static HRESULT hkb_io4_poll(void *ctx, struct io4_state *state);
|
||||||
|
|
||||||
|
static const struct io4_ops hkb_io4_ops = {
|
||||||
|
.poll = hkb_io4_poll,
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT hkb_io4_hook_init(const struct io4_config *cfg)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(hkb_dll.init != NULL);
|
||||||
|
|
||||||
|
hr = io4_hook_init(cfg, &hkb_io4_ops, NULL);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hkb_dll.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT hkb_io4_poll(void *ctx, struct io4_state *state)
|
||||||
|
{
|
||||||
|
uint8_t opbtn;
|
||||||
|
uint8_t gamebtn;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(hkb_dll.poll != NULL);
|
||||||
|
|
||||||
|
memset(state, 0, sizeof(*state));
|
||||||
|
|
||||||
|
hr = hkb_dll.poll(&opbtn, &gamebtn);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & HKB_IO_OPBTN_TEST) {
|
||||||
|
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & HKB_IO_OPBTN_SERVICE) {
|
||||||
|
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & HKB_IO_OPBTN_COIN) {
|
||||||
|
if (!hkb_io_coin) {
|
||||||
|
hkb_io_coin = true;
|
||||||
|
hkb_io_coins++;
|
||||||
|
state->buttons[0] |= 1 << 25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hkb_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->chutes[0] = 128 + 256 * hkb_io_coins;
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_RIGHT) {
|
||||||
|
state->buttons[1] |= 1 << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_LEFT) {
|
||||||
|
state->buttons[1] |= 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_UP) {
|
||||||
|
state->buttons[1] |= 1 << 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_DOWN) {
|
||||||
|
state->buttons[1] |= 1 << 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_ENTER) {
|
||||||
|
state->buttons[1] |= 1 << 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_CANCEL) {
|
||||||
|
state->buttons[1] |= 1 << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_ARR_RIGHT) {
|
||||||
|
state->buttons[1] |= 1 << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & HKB_IO_GAMEBTN_ARR_LEFT) {
|
||||||
|
state->buttons[1] |= 1 << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
7
hkbhook/io4.h
Normal file
7
hkbhook/io4.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
|
||||||
|
HRESULT hkb_io4_hook_init(const struct io4_config *cfg);
|
99
hkbhook/led.c
Normal file
99
hkbhook/led.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "hook/iohook.h"
|
||||||
|
|
||||||
|
#include "hooklib/uart.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
#include "util/dump.h"
|
||||||
|
|
||||||
|
#include "hkbhook/led.h"
|
||||||
|
|
||||||
|
static HRESULT hkb_led_handle_irp(struct irp *irp);
|
||||||
|
static HRESULT hkb_led_handle_irp_locked(struct irp *irp);
|
||||||
|
|
||||||
|
static CRITICAL_SECTION hkb_led_lock;
|
||||||
|
static bool hkb_led_started;
|
||||||
|
static struct uart hkb_led_uart;
|
||||||
|
static uint8_t hkb_led_written_bytes[520];
|
||||||
|
static uint8_t hkb_led_readable_bytes[520];
|
||||||
|
|
||||||
|
HRESULT led_hook_init(const struct hkb_led_config *cfg, uint8_t port)
|
||||||
|
{
|
||||||
|
if (!cfg->enable) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeCriticalSection(&hkb_led_lock);
|
||||||
|
|
||||||
|
uart_init(&hkb_led_uart, port);
|
||||||
|
hkb_led_uart.written.bytes = hkb_led_written_bytes;
|
||||||
|
hkb_led_uart.written.nbytes = sizeof(hkb_led_written_bytes);
|
||||||
|
hkb_led_uart.readable.bytes = hkb_led_readable_bytes;
|
||||||
|
hkb_led_uart.readable.nbytes = sizeof(hkb_led_readable_bytes);
|
||||||
|
|
||||||
|
return iohook_push_handler(hkb_led_handle_irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT hkb_led_handle_irp(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(irp != NULL);
|
||||||
|
|
||||||
|
if (!uart_match_irp(&hkb_led_uart, irp)) {
|
||||||
|
return iohook_invoke_next(irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection(&hkb_led_lock);
|
||||||
|
hr = hkb_led_handle_irp_locked(irp);
|
||||||
|
LeaveCriticalSection(&hkb_led_lock);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT hkb_led_handle_irp_locked(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (irp->op == IRP_OP_WRITE) {
|
||||||
|
dprintf("WRITE:\n");
|
||||||
|
dump_const_iobuf(&irp->write);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (irp->op == IRP_OP_READ) {
|
||||||
|
dprintf("READ:\n");
|
||||||
|
dump_iobuf(&hkb_led_uart.readable);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
|
/* Unfortunately the card reader UART gets opened and closed
|
||||||
|
repeatedly */
|
||||||
|
|
||||||
|
if (!hkb_led_started) {
|
||||||
|
dprintf("Led: Open\n");
|
||||||
|
|
||||||
|
hkb_led_started = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = uart_handle_irp(&hkb_led_uart, irp);
|
||||||
|
|
||||||
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hkb_led_uart.written.pos = 0;
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
39
hkbhook/led.h
Normal file
39
hkbhook/led.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct hkb_led_config {
|
||||||
|
bool enable;
|
||||||
|
};
|
||||||
|
struct hbk_led_packet_head {
|
||||||
|
uint8_t sync;
|
||||||
|
uint8_t dst;
|
||||||
|
uint8_t src;
|
||||||
|
uint8_t len;
|
||||||
|
};
|
||||||
|
struct hbk_led_req_header {
|
||||||
|
struct hbk_led_packet_head head;
|
||||||
|
uint8_t cmd;
|
||||||
|
};
|
||||||
|
struct hbk_led_resp_header {
|
||||||
|
struct hbk_led_packet_head head;
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t report;
|
||||||
|
};
|
||||||
|
struct hbk_led_packet_tail {
|
||||||
|
uint8_t checksum;
|
||||||
|
};
|
||||||
|
struct hbk_led_req_any {
|
||||||
|
struct hbk_led_req_header header;
|
||||||
|
struct hbk_led_packet_tail tail;
|
||||||
|
};
|
||||||
|
struct hbk_led_resp_any {
|
||||||
|
struct hbk_led_resp_header header;
|
||||||
|
struct hbk_led_packet_tail tail;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
HRESULT led_hook_init(const struct hkb_led_config *cfg, uint8_t port);
|
34
hkbhook/meson.build
Normal file
34
hkbhook/meson.build
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
shared_library(
|
||||||
|
'hkbhook',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
vs_module_defs : 'hkbhook.def',
|
||||||
|
dependencies : [
|
||||||
|
capnhook.get_variable('hook_dep'),
|
||||||
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
xinput_lib,
|
||||||
|
],
|
||||||
|
link_with : [
|
||||||
|
aimeio_lib,
|
||||||
|
board_lib,
|
||||||
|
gfxhook_lib,
|
||||||
|
hooklib_lib,
|
||||||
|
hkbio_lib,
|
||||||
|
platform_lib,
|
||||||
|
util_lib,
|
||||||
|
],
|
||||||
|
sources : [
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
'dllmain.c',
|
||||||
|
'io4.c',
|
||||||
|
'io4.h',
|
||||||
|
'led.c',
|
||||||
|
'led.h',
|
||||||
|
'hkb-dll.c',
|
||||||
|
'hkb-dll.h',
|
||||||
|
'unity.h',
|
||||||
|
'unity.c',
|
||||||
|
],
|
||||||
|
)
|
108
hkbhook/unity.c
Normal file
108
hkbhook/unity.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "hook/table.h"
|
||||||
|
#include "hook/iohook.h"
|
||||||
|
|
||||||
|
#include "hooklib/dll.h"
|
||||||
|
#include "hooklib/path.h"
|
||||||
|
#include "hooklib/reg.h"
|
||||||
|
#include "hook/procaddr.h"
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
#include "platform/clock.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",
|
||||||
|
L"HKBSys_api.dll",
|
||||||
|
L"amdaemon_api.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);
|
||||||
|
reg_hook_insert_hooks(result);
|
||||||
|
proc_addr_insert_hooks(result);
|
||||||
|
clock_hook_insert_hooks(result);
|
||||||
|
serial_hook_apply_hooks(result);
|
||||||
|
iohook_apply_hooks(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
3
hkbhook/unity.h
Normal file
3
hkbhook/unity.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void unity_hook_init(void);
|
31
hkbio/config.c
Normal file
31
hkbio/config.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "hkbio/config.h"
|
||||||
|
|
||||||
|
void hkb_io_config_load(
|
||||||
|
struct hkb_io_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
wchar_t key[240];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||||
|
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||||
|
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||||
|
|
||||||
|
cfg->vk_up = GetPrivateProfileIntW(L"io4", L"up", VK_UP, filename);
|
||||||
|
cfg->vk_down = GetPrivateProfileIntW(L"io4", L"down", VK_DOWN, filename);
|
||||||
|
cfg->vk_left = GetPrivateProfileIntW(L"io4", L"left", VK_LEFT, filename);
|
||||||
|
cfg->vk_right = GetPrivateProfileIntW(L"io4", L"right", VK_RIGHT, filename);
|
||||||
|
cfg->vk_enter = GetPrivateProfileIntW(L"io4", L"enter", VK_SPACE, filename);
|
||||||
|
cfg->vk_cancel = GetPrivateProfileIntW(L"io4", L"cancel", VK_LSHIFT, filename);
|
||||||
|
cfg->vk_arr_right = GetPrivateProfileIntW(L"io4", L"right_arrow", 'A', filename);
|
||||||
|
cfg->vk_arr_left = GetPrivateProfileIntW(L"io4", L"left_arrow", 'D', filename);
|
||||||
|
}
|
24
hkbio/config.h
Normal file
24
hkbio/config.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct hkb_io_config {
|
||||||
|
uint8_t vk_test;
|
||||||
|
uint8_t vk_service;
|
||||||
|
uint8_t vk_coin;
|
||||||
|
uint8_t vk_up;
|
||||||
|
uint8_t vk_down;
|
||||||
|
uint8_t vk_left;
|
||||||
|
uint8_t vk_right;
|
||||||
|
uint8_t vk_enter;
|
||||||
|
uint8_t vk_cancel;
|
||||||
|
uint8_t vk_arr_right;
|
||||||
|
uint8_t vk_arr_left;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hkb_io_config_load(
|
||||||
|
struct hkb_io_config *cfg,
|
||||||
|
const wchar_t *filename);
|
74
hkbio/hkbio.c
Normal file
74
hkbio/hkbio.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hkbio/hkbio.h"
|
||||||
|
#include "hkbio/config.h"
|
||||||
|
|
||||||
|
static struct hkb_io_config cfg;
|
||||||
|
|
||||||
|
uint16_t hkb_io_get_api_version(void)
|
||||||
|
{
|
||||||
|
return 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hkb_io_init(void)
|
||||||
|
{
|
||||||
|
hkb_io_config_load(&cfg, L".\\segatools.ini");
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hkb_io_poll(uint8_t *opbtn, uint8_t *gamebtn)
|
||||||
|
{
|
||||||
|
|
||||||
|
*opbtn = 0;
|
||||||
|
*gamebtn = 0;
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_test) & 0x8000) {
|
||||||
|
*opbtn |= HKB_IO_OPBTN_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_service) & 0x8000) {
|
||||||
|
*opbtn |= HKB_IO_OPBTN_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_coin) & 0x8000) {
|
||||||
|
*opbtn |= HKB_IO_OPBTN_COIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_right) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_left) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_up) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_down) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_enter) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_ENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_cancel) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_arr_right) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_ARR_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(cfg.vk_arr_left) & 0x8000) {
|
||||||
|
*gamebtn |= HKB_IO_GAMEBTN_ARR_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
47
hkbio/hkbio.h
Normal file
47
hkbio/hkbio.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HKB_IO_OPBTN_TEST = 0x01,
|
||||||
|
HKB_IO_OPBTN_SERVICE = 0x02,
|
||||||
|
HKB_IO_OPBTN_COIN = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HKB_IO_GAMEBTN_RIGHT = 0x01,
|
||||||
|
HKB_IO_GAMEBTN_LEFT = 0x02,
|
||||||
|
HKB_IO_GAMEBTN_UP = 0x04,
|
||||||
|
HKB_IO_GAMEBTN_DOWN = 0x08,
|
||||||
|
HKB_IO_GAMEBTN_ENTER = 0x10,
|
||||||
|
HKB_IO_GAMEBTN_CANCEL = 0x20,
|
||||||
|
HKB_IO_GAMEBTN_ARR_RIGHT = 0x40,
|
||||||
|
HKB_IO_GAMEBTN_ARR_LEFT = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get the version of the Ongeki IO API that this DLL supports. This
|
||||||
|
function should return a positive 16-bit integer, where the high byte is
|
||||||
|
the major version and the low byte is the minor version (as defined by the
|
||||||
|
Semantic Versioning standard).
|
||||||
|
|
||||||
|
The latest API version as of this writing is 0x0100. */
|
||||||
|
|
||||||
|
uint16_t hkb_io_get_api_version(void);
|
||||||
|
|
||||||
|
/* Initialize the IO DLL. This is the second function that will be called on
|
||||||
|
your DLL, after hkb_io_get_api_version.
|
||||||
|
|
||||||
|
All subsequent calls to this API may originate from arbitrary threads.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT hkb_io_init(void);
|
||||||
|
|
||||||
|
/* Send any queued outputs (of which there are currently none, though this may
|
||||||
|
change in subsequent API versions) and retrieve any new inputs.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT hkb_io_poll(uint8_t *opbtn, uint8_t *gamebtn);
|
12
hkbio/meson.build
Normal file
12
hkbio/meson.build
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
hkbio_lib = static_library(
|
||||||
|
'hkbio',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
sources : [
|
||||||
|
'hkbio.c',
|
||||||
|
'hkbio.h',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
],
|
||||||
|
)
|
257
hooklib/createprocess.c
Normal file
257
hooklib/createprocess.c
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hook/table.h"
|
||||||
|
|
||||||
|
#include "hooklib/createprocess.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
void createprocess_hook_init();
|
||||||
|
static BOOL WINAPI my_CreateProcessA(
|
||||||
|
LPCSTR lpApplicationName,
|
||||||
|
LPSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOA lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
|
);
|
||||||
|
BOOL my_CreateProcessW(
|
||||||
|
LPCWSTR lpApplicationName,
|
||||||
|
LPWSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCWSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOW lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
|
);
|
||||||
|
|
||||||
|
static BOOL (WINAPI *next_CreateProcessA)(
|
||||||
|
LPCSTR lpApplicationName,
|
||||||
|
LPSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOA lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
|
);
|
||||||
|
|
||||||
|
static BOOL (WINAPI *next_CreateProcessW)(
|
||||||
|
LPCWSTR lpApplicationName,
|
||||||
|
LPWSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCWSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOW lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
|
);
|
||||||
|
|
||||||
|
static const struct hook_symbol win32_hooks[] = {
|
||||||
|
{
|
||||||
|
.name = "CreateProcessA",
|
||||||
|
.patch = my_CreateProcessA,
|
||||||
|
.link = (void **) &next_CreateProcessA
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "CreateProcessW",
|
||||||
|
.patch = my_CreateProcessW,
|
||||||
|
.link = (void **) &next_CreateProcessW
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool did_init = false;
|
||||||
|
|
||||||
|
static struct process_hook_sym_w *process_syms_w;
|
||||||
|
static struct process_hook_sym_a *process_syms_a;
|
||||||
|
|
||||||
|
static size_t process_nsyms_a = 0;
|
||||||
|
static size_t process_nsyms_w = 0;
|
||||||
|
|
||||||
|
static CRITICAL_SECTION createproc_lock;
|
||||||
|
|
||||||
|
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) {
|
||||||
|
struct process_hook_sym_w *new_mem;
|
||||||
|
struct process_hook_sym_w *new_proc;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(name != NULL);
|
||||||
|
assert(head != NULL);
|
||||||
|
|
||||||
|
createprocess_hook_init();
|
||||||
|
EnterCriticalSection(&createproc_lock);
|
||||||
|
|
||||||
|
new_mem = realloc(
|
||||||
|
process_syms_w,
|
||||||
|
(process_nsyms_w + 1) * sizeof(struct process_hook_sym_w));
|
||||||
|
|
||||||
|
if (new_mem == NULL) {
|
||||||
|
|
||||||
|
LeaveCriticalSection(&createproc_lock);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_proc = &new_mem[process_nsyms_w];
|
||||||
|
memset(new_proc, 0, sizeof(*new_proc));
|
||||||
|
new_proc->name = name;
|
||||||
|
new_proc->head = head;
|
||||||
|
new_proc->tail = tail;
|
||||||
|
new_proc->replace_all = replace_all;
|
||||||
|
|
||||||
|
process_syms_w = new_mem;
|
||||||
|
process_nsyms_w++;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&createproc_lock);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) {
|
||||||
|
struct process_hook_sym_a *new_mem;
|
||||||
|
struct process_hook_sym_a *new_proc;
|
||||||
|
|
||||||
|
assert(name != NULL);
|
||||||
|
assert(head != NULL);
|
||||||
|
|
||||||
|
createprocess_hook_init();
|
||||||
|
|
||||||
|
EnterCriticalSection(&createproc_lock);
|
||||||
|
|
||||||
|
new_mem = realloc(
|
||||||
|
process_syms_a,
|
||||||
|
(process_nsyms_a + 1) * sizeof(struct process_hook_sym_a));
|
||||||
|
|
||||||
|
if (new_mem == NULL) {
|
||||||
|
|
||||||
|
LeaveCriticalSection(&createproc_lock);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_proc = &new_mem[process_nsyms_a];
|
||||||
|
memset(new_proc, 0, sizeof(*new_proc));
|
||||||
|
new_proc->name = name;
|
||||||
|
new_proc->head = head;
|
||||||
|
new_proc->tail = tail;
|
||||||
|
new_proc->replace_all = replace_all;
|
||||||
|
|
||||||
|
process_syms_a = new_mem;
|
||||||
|
process_nsyms_a++;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&createproc_lock);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createprocess_hook_init() {
|
||||||
|
if (did_init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
did_init = true;
|
||||||
|
|
||||||
|
hook_table_apply(
|
||||||
|
NULL,
|
||||||
|
"kernel32.dll",
|
||||||
|
win32_hooks,
|
||||||
|
_countof(win32_hooks));
|
||||||
|
InitializeCriticalSection(&createproc_lock);
|
||||||
|
dprintf("CreateProcess: Init\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL WINAPI my_CreateProcessA(
|
||||||
|
LPCSTR lpApplicationName,
|
||||||
|
LPSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOA lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < process_nsyms_a; i++) {
|
||||||
|
if (strncmp(process_syms_a[i].name, lpCommandLine, strlen(process_syms_a[i].name))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine);
|
||||||
|
char new_cmd[MAX_PATH] = {0};
|
||||||
|
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].head);
|
||||||
|
|
||||||
|
if (!process_syms_a[i].replace_all) {
|
||||||
|
strcat_s(new_cmd, MAX_PATH, lpCommandLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_syms_a[i].tail != NULL) {
|
||||||
|
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd);
|
||||||
|
return next_CreateProcessA(
|
||||||
|
lpApplicationName,
|
||||||
|
new_cmd,
|
||||||
|
lpProcessAttributes,
|
||||||
|
lpThreadAttributes,
|
||||||
|
bInheritHandles,
|
||||||
|
dwCreationFlags,
|
||||||
|
lpEnvironment,
|
||||||
|
lpCurrentDirectory,
|
||||||
|
lpStartupInfo,
|
||||||
|
lpProcessInformation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return next_CreateProcessA(
|
||||||
|
lpApplicationName,
|
||||||
|
lpCommandLine,
|
||||||
|
lpProcessAttributes,
|
||||||
|
lpThreadAttributes,
|
||||||
|
bInheritHandles,
|
||||||
|
dwCreationFlags,
|
||||||
|
lpEnvironment,
|
||||||
|
lpCurrentDirectory,
|
||||||
|
lpStartupInfo,
|
||||||
|
lpProcessInformation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL my_CreateProcessW(
|
||||||
|
LPCWSTR lpApplicationName,
|
||||||
|
LPWSTR lpCommandLine,
|
||||||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
|
BOOL bInheritHandles,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPVOID lpEnvironment,
|
||||||
|
LPCWSTR lpCurrentDirectory,
|
||||||
|
LPSTARTUPINFOW lpStartupInfo,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation)
|
||||||
|
{
|
||||||
|
return next_CreateProcessW(
|
||||||
|
lpApplicationName,
|
||||||
|
lpCommandLine,
|
||||||
|
lpProcessAttributes,
|
||||||
|
lpThreadAttributes,
|
||||||
|
bInheritHandles,
|
||||||
|
dwCreationFlags,
|
||||||
|
lpEnvironment,
|
||||||
|
lpCurrentDirectory,
|
||||||
|
lpStartupInfo,
|
||||||
|
lpProcessInformation
|
||||||
|
);
|
||||||
|
}
|
21
hooklib/createprocess.h
Normal file
21
hooklib/createprocess.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all);
|
||||||
|
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all);
|
||||||
|
|
||||||
|
struct process_hook_sym_w {
|
||||||
|
const wchar_t *name;
|
||||||
|
const wchar_t *head;
|
||||||
|
const wchar_t *tail;
|
||||||
|
bool replace_all;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct process_hook_sym_a {
|
||||||
|
const char *name;
|
||||||
|
const char *head;
|
||||||
|
const char *tail;
|
||||||
|
bool replace_all;
|
||||||
|
};
|
71
hooklib/cursor.c
Normal file
71
hooklib/cursor.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hook/table.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HCURSOR my_SetCursor(HCURSOR hCursor);
|
||||||
|
static HCURSOR (*next_SetCursor)(HCURSOR hCursor);
|
||||||
|
static BOOL my_SetCursorPos(int x, int y);
|
||||||
|
static BOOL my_SetPhysicalCursorPos(int x, int y);
|
||||||
|
static int my_ShowCursor(BOOL bShow);
|
||||||
|
|
||||||
|
static const struct hook_symbol cursor_syms[] = {
|
||||||
|
{
|
||||||
|
.name = "SetCursor",
|
||||||
|
.patch = my_SetCursor,
|
||||||
|
.link = (void **) &next_SetCursor
|
||||||
|
},/*{
|
||||||
|
.name = "SetCursorPos",
|
||||||
|
.patch = my_SetCursorPos,
|
||||||
|
},*/ {
|
||||||
|
.name = "SetPhysicalCursorPos",
|
||||||
|
.patch = my_SetPhysicalCursorPos
|
||||||
|
}, {
|
||||||
|
.name = "ShowCursor",
|
||||||
|
.patch = my_ShowCursor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void cursor_hook_init()
|
||||||
|
{
|
||||||
|
hook_table_apply(
|
||||||
|
NULL,
|
||||||
|
"user32.dll",
|
||||||
|
cursor_syms,
|
||||||
|
_countof(cursor_syms));
|
||||||
|
|
||||||
|
dprintf("Cursor: Init\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL my_SetCursorPos(int x, int y)
|
||||||
|
{
|
||||||
|
dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL my_SetPhysicalCursorPos(int x, int y)
|
||||||
|
{
|
||||||
|
dprintf("my_SetPhysicalCursorPos Hit! x %d y %d\n", x, y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int my_ShowCursor(BOOL bShow)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HCURSOR my_SetCursor(HCURSOR hCursor)
|
||||||
|
{
|
||||||
|
HCURSOR fake_cursor;
|
||||||
|
|
||||||
|
if ( hCursor )
|
||||||
|
return next_SetCursor(hCursor);
|
||||||
|
fake_cursor = LoadCursorA(0, (LPCSTR)0x7F00);
|
||||||
|
next_SetCursor(fake_cursor);
|
||||||
|
return 0;
|
||||||
|
}
|
3
hooklib/cursor.h
Normal file
3
hooklib/cursor.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void cursor_hook_init();
|
@ -2,13 +2,16 @@ hooklib_lib = static_library(
|
|||||||
'hooklib',
|
'hooklib',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
|
'cursor.c',
|
||||||
|
'cursor.h',
|
||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
|
'createprocess.c',
|
||||||
|
'createprocess.h',
|
||||||
'dll.c',
|
'dll.c',
|
||||||
'dll.h',
|
'dll.h',
|
||||||
'dns.c',
|
'dns.c',
|
||||||
@ -19,8 +22,6 @@ hooklib_lib = static_library(
|
|||||||
'fdshark.h',
|
'fdshark.h',
|
||||||
'path.c',
|
'path.c',
|
||||||
'path.h',
|
'path.h',
|
||||||
'procaddr.c',
|
|
||||||
'procaddr.h',
|
|
||||||
'reg.c',
|
'reg.c',
|
||||||
'reg.h',
|
'reg.h',
|
||||||
'setupapi.c',
|
'setupapi.c',
|
||||||
|
@ -97,6 +97,10 @@ static BOOL WINAPI hook_RemoveDirectoryA(const char *lpFileName);
|
|||||||
|
|
||||||
static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName);
|
static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName);
|
||||||
|
|
||||||
|
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath);
|
||||||
|
|
||||||
|
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
|
||||||
|
|
||||||
/* Link pointers */
|
/* Link pointers */
|
||||||
|
|
||||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||||
@ -177,6 +181,10 @@ static BOOL (WINAPI *next_RemoveDirectoryA)(const char *lpFileName);
|
|||||||
|
|
||||||
static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName);
|
static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName);
|
||||||
|
|
||||||
|
static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
|
||||||
|
|
||||||
|
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
|
||||||
|
|
||||||
/* Hook table */
|
/* Hook table */
|
||||||
|
|
||||||
static const struct hook_symbol path_hook_syms[] = {
|
static const struct hook_symbol path_hook_syms[] = {
|
||||||
@ -244,6 +252,14 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||||||
.name = "RemoveDirectoryW",
|
.name = "RemoveDirectoryW",
|
||||||
.patch = hook_RemoveDirectoryW,
|
.patch = hook_RemoveDirectoryW,
|
||||||
.link = (void **) &next_RemoveDirectoryW,
|
.link = (void **) &next_RemoveDirectoryW,
|
||||||
|
}, {
|
||||||
|
.name = "PathFileExistsA",
|
||||||
|
.patch = hook_PathFileExistsA,
|
||||||
|
.link = (void **) &next_PathFileExistsA,
|
||||||
|
}, {
|
||||||
|
.name = "PathFileExistsW",
|
||||||
|
.patch = hook_PathFileExistsW,
|
||||||
|
.link = (void **) &next_PathFileExistsW,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -854,3 +870,39 @@ static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName)
|
|||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath)
|
||||||
|
{
|
||||||
|
char *trans;
|
||||||
|
BOOL ok;
|
||||||
|
|
||||||
|
ok = path_transform_a(&trans, pszPath);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = next_PathFileExistsA(trans ? trans : pszPath);
|
||||||
|
|
||||||
|
free(trans);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
|
||||||
|
{
|
||||||
|
wchar_t *trans;
|
||||||
|
BOOL ok;
|
||||||
|
|
||||||
|
ok = path_transform_w(&trans, pszPath);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = next_PathFileExistsW(trans ? trans : pszPath);
|
||||||
|
|
||||||
|
free(trans);
|
||||||
|
|
||||||
|
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 "hook/table.h"
|
||||||
|
|
||||||
#include "hooklib/reg.h"
|
#include "hooklib/reg.h"
|
||||||
|
#include "hook/procaddr.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
@ -99,6 +100,29 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
|||||||
uint32_t *numData
|
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 */
|
/* Link pointers */
|
||||||
|
|
||||||
static LSTATUS (WINAPI *next_RegOpenKeyExW)(
|
static LSTATUS (WINAPI *next_RegOpenKeyExW)(
|
||||||
@ -155,6 +179,30 @@ static LSTATUS (WINAPI *next_RegGetValueW)(
|
|||||||
uint32_t *numData
|
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[] = {
|
static const struct hook_symbol reg_hook_syms[] = {
|
||||||
{
|
{
|
||||||
.name = "RegOpenKeyExW",
|
.name = "RegOpenKeyExW",
|
||||||
@ -184,6 +232,14 @@ static const struct hook_symbol reg_hook_syms[] = {
|
|||||||
.name = "RegGetValueW",
|
.name = "RegGetValueW",
|
||||||
.patch = hook_RegGetValueW,
|
.patch = hook_RegGetValueW,
|
||||||
.link = (void **) &next_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);
|
InitializeCriticalSection(®_hook_lock);
|
||||||
dprintf("Reg hook init\n");
|
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(
|
hook_table_apply(
|
||||||
NULL,
|
target,
|
||||||
"advapi32.dll",
|
"advapi32.dll",
|
||||||
reg_hook_syms,
|
reg_hook_syms,
|
||||||
_countof(reg_hook_syms));
|
_countof(reg_hook_syms));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LRESULT reg_hook_propagate_hr(HRESULT hr)
|
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
|
/* Assume reg keys are referenced from a root key and not from some
|
||||||
intermediary key */
|
intermediary key */
|
||||||
key = ®_hook_keys[i];
|
key = ®_hook_keys[i];
|
||||||
|
//dprintf("Reg: %ls vs %ls\n", name, key->name);
|
||||||
|
|
||||||
if (key->root == parent && wstr_ieq(key->name, name)) {
|
if (key->root == parent && wstr_ieq(key->name, name)) {
|
||||||
break;
|
break;
|
||||||
@ -821,6 +891,99 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
|||||||
return err;
|
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(
|
HRESULT reg_hook_read_bin(
|
||||||
void *bytes,
|
void *bytes,
|
||||||
uint32_t *nbytes,
|
uint32_t *nbytes,
|
||||||
|
@ -12,6 +12,8 @@ struct reg_hook_val {
|
|||||||
uint32_t type;
|
uint32_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void reg_hook_insert_hooks(HMODULE target);
|
||||||
|
|
||||||
HRESULT reg_hook_push_key(
|
HRESULT reg_hook_push_key(
|
||||||
HKEY root,
|
HKEY root,
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "iccard/aime.h"
|
#include "iccard/aime.h"
|
||||||
#include "iccard/mifare.h"
|
#include "iccard/mifare.h"
|
||||||
|
#include "iccard/solitaire.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
@ -14,6 +17,9 @@ HRESULT aime_card_populate(
|
|||||||
{
|
{
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char accessCode[21];
|
||||||
|
char hashed_id_wrk[9];
|
||||||
|
char id_wrk[9];
|
||||||
|
|
||||||
assert(mifare != NULL);
|
assert(mifare != NULL);
|
||||||
assert(luid != NULL);
|
assert(luid != NULL);
|
||||||
@ -37,11 +43,29 @@ HRESULT aime_card_populate(
|
|||||||
mifare->sectors[0].blocks[2].bytes[6 + i] = b;
|
mifare->sectors[0].blocks[2].bytes[6 + i] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO An authentic Aime pass has a checksum of the LUID in the last few
|
// Set the card ID, nothing else matters in the first block
|
||||||
bytes of block 1. The output of this function fails authenticity check
|
mifare->sectors[0].blocks[0].bytes[0] = luid[0];
|
||||||
in its current form. */
|
mifare->sectors[0].blocks[0].bytes[1] = luid[1];
|
||||||
|
mifare->sectors[0].blocks[0].bytes[2] = luid[2];
|
||||||
|
mifare->sectors[0].blocks[0].bytes[3] = luid[3];
|
||||||
|
|
||||||
dprintf("AiMe IC: WARNING: Authenticity hash not yet implemented!\n");
|
sprintf_s(accessCode, sizeof accessCode, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
luid[0], luid[1], luid[2], luid[3], luid[4], luid[5], luid[6], luid[7], luid[8], luid[9]);
|
||||||
|
|
||||||
|
memcpy_s(hashed_id_wrk, sizeof(hashed_id_wrk), &accessCode[5],
|
||||||
|
8);
|
||||||
|
|
||||||
|
hashed_id_wrk[8] = '\0';
|
||||||
|
|
||||||
|
SolitaireCipherDecode(&accessCode[13], hashed_id_wrk, id_wrk);
|
||||||
|
|
||||||
|
|
||||||
|
DWORD nSerial = atoi(id_wrk);
|
||||||
|
|
||||||
|
mifare->sectors[0].blocks[1].bytes[12] = (nSerial >> 24) & 0xff;
|
||||||
|
mifare->sectors[0].blocks[1].bytes[13] = (nSerial >> 16) & 0xff;
|
||||||
|
mifare->sectors[0].blocks[1].bytes[14] = (nSerial >> 8) & 0xff;
|
||||||
|
mifare->sectors[0].blocks[1].bytes[15] = nSerial & 0xff;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ iccard_lib = static_library(
|
|||||||
'iccard',
|
'iccard',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
@ -12,5 +11,7 @@ iccard_lib = static_library(
|
|||||||
'felica.c',
|
'felica.c',
|
||||||
'felica.h',
|
'felica.h',
|
||||||
'mifare.h',
|
'mifare.h',
|
||||||
|
'solitaire.c',
|
||||||
|
'solitaire.h',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
143
iccard/solitaire.c
Normal file
143
iccard/solitaire.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include "solitaire.h"
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#define DECK_SIZE 22
|
||||||
|
#define JOKER_A 21
|
||||||
|
#define JOKER_B 22
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char m_Deck[DECK_SIZE];
|
||||||
|
} DECK, *PDECK;
|
||||||
|
|
||||||
|
static DECK SOL_INIT_DECK = {
|
||||||
|
.m_Deck = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define char2num(c) ((c) - '0' + 1)
|
||||||
|
static inline char num2char(char num) {
|
||||||
|
while (num < 1) num = num + 10;
|
||||||
|
return (num - 1) % 10 + '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolMoveCard(PDECK lpDeck, char card) {
|
||||||
|
int p = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < DECK_SIZE; i++) {
|
||||||
|
if (lpDeck->m_Deck[i] == card) {
|
||||||
|
p = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p < DECK_SIZE - 1) {
|
||||||
|
lpDeck->m_Deck[p] = lpDeck->m_Deck[p + 1];
|
||||||
|
lpDeck->m_Deck[p + 1] = card;
|
||||||
|
} else {
|
||||||
|
for (int i = DECK_SIZE - 1; i > 1; i--) lpDeck->m_Deck[i] = lpDeck->m_Deck[i - 1];
|
||||||
|
lpDeck->m_Deck[1] = card;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolCutDeck(PDECK lpDeck, char point) {
|
||||||
|
DECK tmp;
|
||||||
|
|
||||||
|
memcpy(tmp.m_Deck, &lpDeck->m_Deck[(size_t)point], DECK_SIZE - point - 1);
|
||||||
|
memcpy(&tmp.m_Deck[DECK_SIZE - point - 1], lpDeck->m_Deck, point);
|
||||||
|
memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolSwapOutsideJoker(PDECK lpDeck) {
|
||||||
|
int j1 = -1;
|
||||||
|
int j2 = -1;
|
||||||
|
DECK tmp;
|
||||||
|
|
||||||
|
for (int i = 0; i < DECK_SIZE; i++) {
|
||||||
|
if (lpDeck->m_Deck[i] == JOKER_A || lpDeck->m_Deck[i] == JOKER_B) {
|
||||||
|
if (j1 == -1) {
|
||||||
|
j1 = i;
|
||||||
|
} else {
|
||||||
|
j2 = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < DECK_SIZE - j2 - 1) memcpy(tmp.m_Deck, &lpDeck->m_Deck[j2 + 1], DECK_SIZE - j2 - 1);
|
||||||
|
tmp.m_Deck[DECK_SIZE - j2 - 1] = lpDeck->m_Deck[j1];
|
||||||
|
if (0 < j2 - j1 - 1) memcpy(&tmp.m_Deck[DECK_SIZE - j2], &lpDeck->m_Deck[j1 + 1], j2 - j1 - 1);
|
||||||
|
tmp.m_Deck[DECK_SIZE - j1 - 1] = lpDeck->m_Deck[j2];
|
||||||
|
if (0 < j1) memcpy(&tmp.m_Deck[DECK_SIZE - j1], lpDeck->m_Deck, j1);
|
||||||
|
memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolCutByBottomCard(PDECK lpDeck) {
|
||||||
|
char p = lpDeck->m_Deck[DECK_SIZE - 1];
|
||||||
|
if (p == JOKER_B) p = JOKER_A;
|
||||||
|
SolCutDeck(lpDeck, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char SolGetTopCardNum(PDECK lpDeck) {
|
||||||
|
char p = lpDeck->m_Deck[0];
|
||||||
|
if (p == JOKER_B) p = JOKER_A;
|
||||||
|
return lpDeck->m_Deck[(size_t)p];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolDeckHash(PDECK lpDeck) {
|
||||||
|
char p;
|
||||||
|
|
||||||
|
do {
|
||||||
|
SolMoveCard(lpDeck, JOKER_A);
|
||||||
|
SolMoveCard(lpDeck, JOKER_B);
|
||||||
|
SolMoveCard(lpDeck, JOKER_B);
|
||||||
|
SolSwapOutsideJoker(lpDeck);
|
||||||
|
SolCutByBottomCard(lpDeck);
|
||||||
|
|
||||||
|
p = SolGetTopCardNum(lpDeck);
|
||||||
|
} while (p == JOKER_A || p == JOKER_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SolCreateDeck(PDECK lpDeck, const char *key) {
|
||||||
|
memcpy_s(lpDeck, sizeof *lpDeck, &SOL_INIT_DECK, sizeof SOL_INIT_DECK);
|
||||||
|
int p = 0;
|
||||||
|
while (key[p] != '\0') {
|
||||||
|
SolDeckHash(lpDeck);
|
||||||
|
char c = char2num(key[p]);
|
||||||
|
SolCutDeck(lpDeck, c);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst) {
|
||||||
|
DECK deck;
|
||||||
|
SolCreateDeck(&deck, szKey);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (szSrc[i] != '\0') {
|
||||||
|
SolDeckHash(&deck);
|
||||||
|
char p = SolGetTopCardNum(&deck);
|
||||||
|
szDst[i] = num2char(char2num(szSrc[i]) + p);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
szDst[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst) {
|
||||||
|
DECK deck;
|
||||||
|
SolCreateDeck(&deck, szKey);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (szSrc[i] != '\0') {
|
||||||
|
SolDeckHash(&deck);
|
||||||
|
char p = SolGetTopCardNum(&deck);
|
||||||
|
szDst[i] = num2char(char2num(szSrc[i]) - p);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
szDst[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolitaireCipher(int nMode, const char *szKey, const char *szSrc, char *szDst) {
|
||||||
|
if (nMode == 0)
|
||||||
|
SolitaireCipherEncode(szKey, szSrc, szDst);
|
||||||
|
else if (nMode == 1)
|
||||||
|
SolitaireCipherDecode(szKey, szSrc, szDst);
|
||||||
|
}
|
3
iccard/solitaire.h
Normal file
3
iccard/solitaire.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst);
|
||||||
|
void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst);
|
||||||
|
void SolitaireCipher(int mode, const char *key, const char *src_str, char *dest_str);
|
@ -1,5 +1,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "amex/amex.h"
|
#include "amex/amex.h"
|
||||||
#include "amex/config.h"
|
#include "amex/config.h"
|
||||||
|
@ -4,7 +4,6 @@ shared_library(
|
|||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
vs_module_defs : 'idzhook.def',
|
vs_module_defs : 'idzhook.def',
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
capnhook.get_variable('hooklib_dep'),
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "idzhook/config.h"
|
#include "idzhook/config.h"
|
||||||
#include "idzhook/zinput.h"
|
#include "idzhook/zinput.h"
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "idzio/backend.h"
|
#include "idzio/backend.h"
|
||||||
#include "idzio/config.h"
|
#include "idzio/config.h"
|
||||||
|
@ -3,7 +3,6 @@ idzio_lib = static_library(
|
|||||||
name_prefix : '',
|
name_prefix : '',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
dinput8_lib,
|
dinput8_lib,
|
||||||
dxguid_lib,
|
dxguid_lib,
|
||||||
|
@ -2,7 +2,6 @@ jvs_lib = static_library(
|
|||||||
'jvs',
|
'jvs',
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
|
||||||
dependencies : [
|
dependencies : [
|
||||||
capnhook.get_variable('hook_dep'),
|
capnhook.get_variable('hook_dep'),
|
||||||
],
|
],
|
||||||
|
67
mai2hook/config.c
Normal file
67
mai2hook/config.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
#include "gfxhook/config.h"
|
||||||
|
|
||||||
|
#include "hooklib/config.h"
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
|
||||||
|
#include "mai2hook/config.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
void mai2_dll_config_load(
|
||||||
|
struct mai2_dll_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"mai2io",
|
||||||
|
L"path",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void touch_config_load(
|
||||||
|
struct touch_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void 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 mai2_hook_config_load(
|
||||||
|
struct mai2_hook_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
platform_config_load(&cfg->platform, filename);
|
||||||
|
aime_config_load(&cfg->aime, filename);
|
||||||
|
dvd_config_load(&cfg->dvd, filename);
|
||||||
|
io4_config_load(&cfg->io4, filename);
|
||||||
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
|
mai2_dll_config_load(&cfg->dll, filename);
|
||||||
|
touch_config_load(&cfg->touch, filename);
|
||||||
|
led_config_load(&cfg->led, filename);
|
||||||
|
}
|
34
mai2hook/config.h
Normal file
34
mai2hook/config.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
|
||||||
|
#include "mai2hook/mai2-dll.h"
|
||||||
|
#include "mai2hook/touch.h"
|
||||||
|
#include "mai2hook/led.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
struct mai2_hook_config {
|
||||||
|
struct platform_config platform;
|
||||||
|
struct aime_config aime;
|
||||||
|
struct dvd_config dvd;
|
||||||
|
struct io4_config io4;
|
||||||
|
struct gfx_config gfx;
|
||||||
|
struct mai2_dll_config dll;
|
||||||
|
struct touch_config touch;
|
||||||
|
struct led_config led;
|
||||||
|
};
|
||||||
|
|
||||||
|
void mai2_dll_config_load(
|
||||||
|
struct mai2_dll_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
||||||
|
void mai2_hook_config_load(
|
||||||
|
struct mai2_hook_config *cfg,
|
||||||
|
const wchar_t *filename);
|
148
mai2hook/dllmain.c
Normal file
148
mai2hook/dllmain.c
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
#include "board/sg-reader.h"
|
||||||
|
#include "board/vfd.h"
|
||||||
|
|
||||||
|
#include "gfxhook/d3d9.h"
|
||||||
|
#include "gfxhook/d3d11.h"
|
||||||
|
#include "gfxhook/dxgi.h"
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
|
#include "hook/process.h"
|
||||||
|
#include "hook/table.h"
|
||||||
|
|
||||||
|
#include "hooklib/dvd.h"
|
||||||
|
#include "hooklib/spike.h"
|
||||||
|
#include "hooklib/path.h"
|
||||||
|
#include "hooklib/reg.h"
|
||||||
|
#include "hook/procaddr.h"
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
|
||||||
|
#include "mai2hook/config.h"
|
||||||
|
#include "mai2hook/io4.h"
|
||||||
|
#include "mai2hook/mai2-dll.h"
|
||||||
|
#include "mai2hook/unity.h"
|
||||||
|
#include "mai2hook/touch.h"
|
||||||
|
#include "mai2hook/led.h"
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HMODULE mai2_hook_mod;
|
||||||
|
static process_entry_t mai2_startup;
|
||||||
|
static struct mai2_hook_config mai2_hook_cfg;
|
||||||
|
|
||||||
|
static DWORD CALLBACK mai2_pre_startup(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
dprintf("--- Begin mai2_pre_startup ---\n");
|
||||||
|
|
||||||
|
/* Load config */
|
||||||
|
|
||||||
|
mai2_hook_config_load(&mai2_hook_cfg, L".\\segatools.ini");
|
||||||
|
|
||||||
|
/* Hook Win32 APIs */
|
||||||
|
|
||||||
|
dvd_hook_init(&mai2_hook_cfg.dvd, mai2_hook_mod);
|
||||||
|
gfx_hook_init(&mai2_hook_cfg.gfx);
|
||||||
|
gfx_d3d9_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||||
|
gfx_d3d11_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||||
|
gfx_dxgi_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||||
|
serial_hook_init();
|
||||||
|
|
||||||
|
/* Initialize emulation hooks */
|
||||||
|
|
||||||
|
hr = platform_hook_init(
|
||||||
|
&mai2_hook_cfg.platform,
|
||||||
|
"SDEZ",
|
||||||
|
"ACA1",
|
||||||
|
mai2_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, mai2_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = vfd_hook_init(2);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = mai2_io4_hook_init(&mai2_hook_cfg.io4);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The handling of the fake registry COM values is extraordinarly lazy
|
||||||
|
// and I need to make a better method for tacking fake values onto common keys
|
||||||
|
// that multiple modules may try to use.
|
||||||
|
hr = led_hook_init(&mai2_hook_cfg.led);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = touch_hook_init(&mai2_hook_cfg.touch);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize Unity native plugin DLL hooks
|
||||||
|
|
||||||
|
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||||
|
hooked earlier in the `mai2hook` initialization. */
|
||||||
|
|
||||||
|
unity_hook_init();
|
||||||
|
|
||||||
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
|
spike_hook_init(L".\\segatools.ini");
|
||||||
|
|
||||||
|
dprintf("--- End mai2_pre_startup ---\n");
|
||||||
|
|
||||||
|
/* Jump to EXE start address */
|
||||||
|
|
||||||
|
return mai2_startup();
|
||||||
|
|
||||||
|
fail:
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (cause != DLL_PROCESS_ATTACH) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mai2_hook_mod = mod;
|
||||||
|
|
||||||
|
hr = process_hijack_startup(mai2_pre_startup, &mai2_startup);
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
147
mai2hook/io4.c
Normal file
147
mai2hook/io4.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
|
||||||
|
#include "mai2hook/mai2-dll.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
bool mai2_io_coin = false;
|
||||||
|
uint16_t mai2_io_coins = 0;
|
||||||
|
|
||||||
|
static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state);
|
||||||
|
|
||||||
|
static const struct io4_ops mai2_io4_ops = {
|
||||||
|
.poll = mai2_io4_poll,
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT mai2_io4_hook_init(const struct io4_config *cfg)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(mai2_dll.init != NULL);
|
||||||
|
|
||||||
|
hr = io4_hook_init(cfg, &mai2_io4_ops, NULL);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mai2_dll.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state)
|
||||||
|
{
|
||||||
|
uint8_t opbtn = 0;
|
||||||
|
uint8_t player1 = 0;
|
||||||
|
uint8_t player2 = 0;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(mai2_dll.poll != NULL);
|
||||||
|
|
||||||
|
hr = mai2_dll.poll(&opbtn, &player1, &player2);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & MAI2_IO_OPBTN_TEST) {
|
||||||
|
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & MAI2_IO_OPBTN_SERVICE) {
|
||||||
|
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & MAI2_IO_P1_START) {
|
||||||
|
state->buttons[0] |= 1 << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & MAI2_IO_P2_START) {
|
||||||
|
state->buttons[1] |= 1 << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_1)) {
|
||||||
|
state->buttons[0] |= 1 << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_2)) {
|
||||||
|
state->buttons[0] |= 1 << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_3)) {
|
||||||
|
state->buttons[0] |= 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_4)) {
|
||||||
|
state->buttons[0] |= 1 << 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_5)) {
|
||||||
|
state->buttons[0] |= 1 << 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_6)) {
|
||||||
|
state->buttons[0] |= 1 << 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_7)) {
|
||||||
|
state->buttons[0] |= 1 << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player1 & MAI2_IO_GAMEBTN_8)) {
|
||||||
|
state->buttons[0] |= 1 << 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_1)) {
|
||||||
|
state->buttons[1] |= 1 << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_2)) {
|
||||||
|
state->buttons[1] |= 1 << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_3)) {
|
||||||
|
state->buttons[1] |= 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_4)) {
|
||||||
|
state->buttons[1] |= 1 << 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_5)) {
|
||||||
|
state->buttons[1] |= 1 << 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_6)) {
|
||||||
|
state->buttons[1] |= 1 << 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_7)) {
|
||||||
|
state->buttons[1] |= 1 << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(player2 & MAI2_IO_GAMEBTN_8)) {
|
||||||
|
state->buttons[1] |= 1 << 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (opbtn & MAI2_IO_OPBTN_COIN) {
|
||||||
|
if (!mai2_io_coin) {
|
||||||
|
mai2_io_coin = true;
|
||||||
|
mai2_io_coins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mai2_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->chutes[0] = 128 + 256 * mai2_io_coins;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
7
mai2hook/io4.h
Normal file
7
mai2hook/io4.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "board/io4.h"
|
||||||
|
|
||||||
|
HRESULT mai2_io4_hook_init(const struct io4_config *cfg);
|
212
mai2hook/led.c
Normal file
212
mai2hook/led.c
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "hooklib/reg.h"
|
||||||
|
#include "hooklib/uart.h"
|
||||||
|
#include "hooklib/fdshark.h"
|
||||||
|
|
||||||
|
#include "mai2hook/led.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes);
|
||||||
|
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes);
|
||||||
|
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes);
|
||||||
|
static HRESULT led_handle_irp(struct irp *irp);
|
||||||
|
static HRESULT led0_handle_irp_locked(struct irp *irp);
|
||||||
|
static HRESULT led1_handle_irp_locked(struct irp *irp);
|
||||||
|
|
||||||
|
static CRITICAL_SECTION led0_lock;
|
||||||
|
static struct uart led0_uart;
|
||||||
|
static uint8_t led0_written_bytes[520];
|
||||||
|
static uint8_t led0_readable_bytes[520];
|
||||||
|
|
||||||
|
static CRITICAL_SECTION led1_lock;
|
||||||
|
static struct uart led1_uart;
|
||||||
|
static uint8_t led1_written_bytes[520];
|
||||||
|
static uint8_t led1_readable_bytes[520];
|
||||||
|
|
||||||
|
static const struct reg_hook_val fake_com_keys[] = {
|
||||||
|
{
|
||||||
|
.name = L"\\Device\\RealTouchBoard0",
|
||||||
|
.read = read_fake_com0,
|
||||||
|
.type = REG_SZ,
|
||||||
|
},{
|
||||||
|
.name = L"\\Device\\RealTouchBoard1",
|
||||||
|
.read = read_fake_com1,
|
||||||
|
.type = REG_SZ,
|
||||||
|
},{
|
||||||
|
.name = L"\\Device\\RealLedBoard0",
|
||||||
|
.read = read_fake_com2,
|
||||||
|
.type = REG_SZ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT led_hook_init(const struct led_config *cfg)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
if (!cfg->enable) {
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Mai2 LED: Init\n");
|
||||||
|
InitializeCriticalSection(&led0_lock);
|
||||||
|
InitializeCriticalSection(&led1_lock);
|
||||||
|
|
||||||
|
hr = reg_hook_push_key(
|
||||||
|
HKEY_LOCAL_MACHINE,
|
||||||
|
L"HARDWARE\\DEVICEMAP\\SERIALCOMM",
|
||||||
|
fake_com_keys,
|
||||||
|
_countof(fake_com_keys));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_init(&led0_uart, 21);
|
||||||
|
led0_uart.written.bytes = led0_written_bytes;
|
||||||
|
led0_uart.written.nbytes = sizeof(led0_written_bytes);
|
||||||
|
led0_uart.readable.bytes = led0_readable_bytes;
|
||||||
|
led0_uart.readable.nbytes = sizeof(led0_readable_bytes);
|
||||||
|
|
||||||
|
uart_init(&led1_uart, 23);
|
||||||
|
led1_uart.written.bytes = led1_written_bytes;
|
||||||
|
led1_uart.written.nbytes = sizeof(led1_written_bytes);
|
||||||
|
led1_uart.readable.bytes = led1_readable_bytes;
|
||||||
|
led1_uart.readable.nbytes = sizeof(led1_readable_bytes);
|
||||||
|
|
||||||
|
return iohook_push_handler(led_handle_irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes)
|
||||||
|
{
|
||||||
|
//dprintf("Mai2 Touch: Read COM3 reg val\n");
|
||||||
|
return reg_hook_read_wstr(bytes, nbytes, L"COM3");
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes)
|
||||||
|
{
|
||||||
|
//dprintf("Mai2 Touch: Read COM4 reg val\n");
|
||||||
|
return reg_hook_read_wstr(bytes, nbytes, L"COM4");
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes)
|
||||||
|
{
|
||||||
|
//dprintf("Mai2 LED: Read COM20 reg val\n");
|
||||||
|
return reg_hook_read_wstr(bytes, nbytes, L"COM20");
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT led_handle_irp(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(irp != NULL);
|
||||||
|
|
||||||
|
if (uart_match_irp(&led0_uart, irp)) {
|
||||||
|
EnterCriticalSection(&led0_lock);
|
||||||
|
hr = led0_handle_irp_locked(irp);
|
||||||
|
LeaveCriticalSection(&led0_lock);
|
||||||
|
}
|
||||||
|
else if (uart_match_irp(&led1_uart, irp)) {
|
||||||
|
EnterCriticalSection(&led1_lock);
|
||||||
|
hr = led1_handle_irp_locked(irp);
|
||||||
|
LeaveCriticalSection(&led1_lock);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return iohook_invoke_next(irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
static HRESULT led0_handle_irp_locked(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
|
dprintf("Mai2 led0: Starting backend\n");
|
||||||
|
//hr = mai2_dll.led_init();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Backend error: %x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = uart_handle_irp(&led0_uart, irp);
|
||||||
|
|
||||||
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
#if 0
|
||||||
|
dprintf("TX0 Buffer:\n");
|
||||||
|
dump_iobuf(&led0_uart.written);
|
||||||
|
#endif
|
||||||
|
//hr = led_frame_decode(&req, &led0_uart.written, 0);
|
||||||
|
|
||||||
|
if (hr != S_OK) {
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Deframe error: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//hr = led_req_dispatch(&req);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Processing error: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT led1_handle_irp_locked(struct irp *irp)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
|
dprintf("Mai2 led1: Starting backend\n");
|
||||||
|
//hr = mai2_dll.led_init();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Backend error: %x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = uart_handle_irp(&led0_uart, irp);
|
||||||
|
|
||||||
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
#if 0
|
||||||
|
dprintf("TX0 Buffer:\n");
|
||||||
|
dump_iobuf(&led0_uart.written);
|
||||||
|
#endif
|
||||||
|
//hr = led_frame_decode(&req, &led0_uart.written, 0);
|
||||||
|
|
||||||
|
if (hr != S_OK) {
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Deframe error: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//hr = led_req_dispatch(&req);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Mai2 led: Processing error: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
9
mai2hook/led.h
Normal file
9
mai2hook/led.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct led_config {
|
||||||
|
bool enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT led_hook_init(const struct led_config *cfg);
|
103
mai2hook/mai2-dll.c
Normal file
103
mai2hook/mai2-dll.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mai2hook/mai2-dll.h"
|
||||||
|
|
||||||
|
#include "util/dll-bind.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
const struct dll_bind_sym mai2_dll_syms[] = {
|
||||||
|
{
|
||||||
|
.sym = "mai2_io_init",
|
||||||
|
.off = offsetof(struct mai2_dll, init),
|
||||||
|
}, {
|
||||||
|
.sym = "mai2_io_poll",
|
||||||
|
.off = offsetof(struct mai2_dll, poll),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mai2_dll mai2_dll;
|
||||||
|
|
||||||
|
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||||
|
// Not much of this lends itself to being easily factored out. Also there
|
||||||
|
// will be a lot of API-specific branching code here eventually as new API
|
||||||
|
// versions get defined, so even though these functions all look the same
|
||||||
|
// now this won't remain the case forever.
|
||||||
|
|
||||||
|
HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self)
|
||||||
|
{
|
||||||
|
uint16_t (*get_api_version)(void);
|
||||||
|
const struct dll_bind_sym *sym;
|
||||||
|
HINSTANCE owned;
|
||||||
|
HINSTANCE src;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(self != NULL);
|
||||||
|
|
||||||
|
if (cfg->path[0] != L'\0') {
|
||||||
|
owned = LoadLibraryW(cfg->path);
|
||||||
|
|
||||||
|
if (owned == NULL) {
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
dprintf("Mai2 IO: Failed to load IO DLL: %lx: %S\n",
|
||||||
|
hr,
|
||||||
|
cfg->path);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Mai2 IO: Using custom IO DLL: %S\n", cfg->path);
|
||||||
|
src = owned;
|
||||||
|
} else {
|
||||||
|
owned = NULL;
|
||||||
|
src = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "mai2_io_get_api_version");
|
||||||
|
|
||||||
|
if (get_api_version != NULL) {
|
||||||
|
mai2_dll.api_version = get_api_version();
|
||||||
|
} else {
|
||||||
|
mai2_dll.api_version = 0x0100;
|
||||||
|
dprintf("Custom IO DLL does not expose mai2_io_get_api_version, "
|
||||||
|
"assuming API version 1.0.\n"
|
||||||
|
"Please ask the developer to update their DLL.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mai2_dll.api_version >= 0x0200) {
|
||||||
|
hr = E_NOTIMPL;
|
||||||
|
dprintf("Mai2 IO: Custom IO DLL implements an unsupported "
|
||||||
|
"API version (%#04x). Please update Segatools.\n",
|
||||||
|
mai2_dll.api_version);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = mai2_dll_syms;
|
||||||
|
hr = dll_bind(&mai2_dll, src, &sym, _countof(mai2_dll_syms));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (src != self) {
|
||||||
|
dprintf("Mai2 IO: Custom IO DLL does not provide function "
|
||||||
|
"\"%s\". Please contact your IO DLL's developer for "
|
||||||
|
"further assistance.\n",
|
||||||
|
sym->sym);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
owned = NULL;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (owned != NULL) {
|
||||||
|
FreeLibrary(owned);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user