add exvs2hook
This commit is contained in:
parent
f3171fbdfc
commit
97b17a0844
13
Package.mk
13
Package.mk
@ -20,9 +20,21 @@ $(BUILD_DIR_ZIP)/taiko.zip:
|
|||||||
$(V)strip $(BUILD_DIR_ZIP)/taiko/*.{exe,dll}
|
$(V)strip $(BUILD_DIR_ZIP)/taiko/*.{exe,dll}
|
||||||
$(V)cd $(BUILD_DIR_ZIP)/taiko ; zip -r ../taiko.zip *
|
$(V)cd $(BUILD_DIR_ZIP)/taiko ; zip -r ../taiko.zip *
|
||||||
|
|
||||||
|
$(BUILD_DIR_ZIP)/exvs2.zip:
|
||||||
|
$(V)echo ... $@
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/exvs2
|
||||||
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
|
$(BUILD_DIR_64)/exvs2hook/exvs2hook.dll \
|
||||||
|
$(DIST_DIR)/exvs2/bananatools.ini \
|
||||||
|
$(DIST_DIR)/exvs2/start.bat \
|
||||||
|
$(BUILD_DIR_ZIP)/exvs2
|
||||||
|
$(V)strip $(BUILD_DIR_ZIP)/exvs2/*.{exe,dll}
|
||||||
|
$(V)cd $(BUILD_DIR_ZIP)/exvs2 ; zip -r ../exvs2.zip *
|
||||||
|
|
||||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||||
$(DOC_DIR)/ferrumhook.md \
|
$(DOC_DIR)/ferrumhook.md \
|
||||||
$(DOC_DIR)/taikohook.md \
|
$(DOC_DIR)/taikohook.md \
|
||||||
|
$(DOC_DIR)/exvs2hook.md \
|
||||||
| $(zipdir)/
|
| $(zipdir)/
|
||||||
$(V)echo ... $@
|
$(V)echo ... $@
|
||||||
$(V)zip -r $@ $^
|
$(V)zip -r $@ $^
|
||||||
@ -30,6 +42,7 @@ $(BUILD_DIR_ZIP)/doc.zip: \
|
|||||||
$(BUILD_DIR_ZIP)/bananatools.zip: \
|
$(BUILD_DIR_ZIP)/bananatools.zip: \
|
||||||
$(BUILD_DIR_ZIP)/ferrum.zip \
|
$(BUILD_DIR_ZIP)/ferrum.zip \
|
||||||
$(BUILD_DIR_ZIP)/taiko.zip \
|
$(BUILD_DIR_ZIP)/taiko.zip \
|
||||||
|
$(BUILD_DIR_ZIP)/exvs2.zip \
|
||||||
$(BUILD_DIR_ZIP)/doc.zip \
|
$(BUILD_DIR_ZIP)/doc.zip \
|
||||||
README.md \
|
README.md \
|
||||||
|
|
||||||
|
86
dist/exvs2/bananatools.ini
vendored
Normal file
86
dist/exvs2/bananatools.ini
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
; Controls the virtual file system hooks. These redirect file i/o
|
||||||
|
; requests to a folder specified below, instead of the drive.
|
||||||
|
; These are all required, even if the game doesn't use one of them.
|
||||||
|
[vfs]
|
||||||
|
path=
|
||||||
|
|
||||||
|
[dns]
|
||||||
|
default=localhost
|
||||||
|
|
||||||
|
; Security dongle emulation, disable if you have a
|
||||||
|
; real dongle connected that you want to use
|
||||||
|
[dongle]
|
||||||
|
enable=1
|
||||||
|
; XBoost
|
||||||
|
serial=284313110001
|
||||||
|
; EXVS2
|
||||||
|
; serial=281131010001
|
||||||
|
; For LM, change the 5th digit to a 1
|
||||||
|
|
||||||
|
; Set the network environment. Most games seem to want 192.168.123.X
|
||||||
|
[netenv]
|
||||||
|
enable=1
|
||||||
|
subnet=192.168.85.0
|
||||||
|
|
||||||
|
[misc]
|
||||||
|
systemVersion=GX2100-1-NA-SYS0-A06
|
||||||
|
|
||||||
|
; Graphics hook, may cause crashes in some games
|
||||||
|
[gfx]
|
||||||
|
enable=1
|
||||||
|
windowed=1
|
||||||
|
framed=0
|
||||||
|
monitor=0
|
||||||
|
|
||||||
|
; Control the AMCUS replacement class
|
||||||
|
[amcus]
|
||||||
|
enable=1
|
||||||
|
game_id=SBUZ
|
||||||
|
game_cd=GX21
|
||||||
|
am_game_ver=4.00
|
||||||
|
cacfg_game_ver=29.31
|
||||||
|
server_uri=localhost
|
||||||
|
server_host=localhost
|
||||||
|
|
||||||
|
; Controlls the xinput hooks
|
||||||
|
[xinput]
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[reader]
|
||||||
|
enable=1
|
||||||
|
; "Enter" key
|
||||||
|
insert_card=0x0D
|
||||||
|
access_code=00000000000000000000
|
||||||
|
|
||||||
|
; JVS config
|
||||||
|
[jvs]
|
||||||
|
enable=1
|
||||||
|
port=3
|
||||||
|
|
||||||
|
; Mappings for the najv4 IO board. To disable JVS emulation and use
|
||||||
|
; a real board, set enable to 0 in the "jvs" section.
|
||||||
|
[najv4]
|
||||||
|
; "Home" key
|
||||||
|
test=0x24
|
||||||
|
; "Insert" key
|
||||||
|
coin=0x2D
|
||||||
|
; "Delete" key
|
||||||
|
service=0x2E
|
||||||
|
; Up arrow
|
||||||
|
up=0x26
|
||||||
|
; Down arrow
|
||||||
|
down=0x28
|
||||||
|
; Left arrow
|
||||||
|
left=0x25
|
||||||
|
; Right arrow
|
||||||
|
right=0x27
|
||||||
|
; Spacebar
|
||||||
|
start=0x20
|
||||||
|
; 1
|
||||||
|
btn1=0x31
|
||||||
|
; 2
|
||||||
|
btn2=0x32
|
||||||
|
; 3
|
||||||
|
btn3=0x33
|
||||||
|
; 4
|
||||||
|
btn4=0x34
|
11
dist/exvs2/start.bat
vendored
Normal file
11
dist/exvs2/start.bat
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Comment out this line if you intend to use the AMCUS emulator
|
||||||
|
start inject.exe -d -k exvs2hook.dll AMCUS\AMAuthd.exe
|
||||||
|
inject.exe -d -k exvs2hook.dll exvs2_exe_Release.exe
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo The game process has terminated
|
||||||
|
pause
|
2
dist/ferrum/bananatools.ini
vendored
2
dist/ferrum/bananatools.ini
vendored
@ -20,7 +20,7 @@ subnet=192.168.123.0
|
|||||||
|
|
||||||
; Graphics hook, may cause crashes in some games
|
; Graphics hook, may cause crashes in some games
|
||||||
[gfx]
|
[gfx]
|
||||||
enable=1
|
enable=0
|
||||||
windowed=1
|
windowed=1
|
||||||
framed=0
|
framed=0
|
||||||
monitor=0
|
monitor=0
|
||||||
|
13
doc/exvs2hook.md
Normal file
13
doc/exvs2hook.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# exvs2hook
|
||||||
|
|
||||||
|
# Supported games
|
||||||
|
|
||||||
|
* Extreme Vs 2 (all versions)
|
||||||
|
* Extreme Vs 2 XBoost (All Versions)
|
||||||
|
|
||||||
|
## General remarks
|
||||||
|
* Game requires both at least 1 game clinet and a "Live Monitor" server
|
||||||
|
* 2 game clients are required for the Live Monitor to function properly. 1 will still work for the game client, but the LM will throw an error.
|
||||||
|
* AMCUS hook is required to run on Windows 11 from my testing.
|
||||||
|
* XBoost requires the final octet of it's IP to be between 64 and 90 inclusive.
|
||||||
|
* Any XInput controller should work, but is untested with these tools.
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Supported games
|
# Supported games
|
||||||
|
|
||||||
* Pokken Tournamen A**
|
* Pokken Tournamen (All versions)
|
||||||
|
|
||||||
## General remarks
|
## General remarks
|
||||||
|
|
||||||
@ -14,4 +14,3 @@
|
|||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
* gfxhook doesn't work as the dxgi/dx11 hooks are currently non-functional.
|
* gfxhook doesn't work as the dxgi/dx11 hooks are currently non-functional.
|
||||||
* Networking functionality is untested
|
|
0
exvs2hook/bngrw.c
Normal file
0
exvs2hook/bngrw.c
Normal file
0
exvs2hook/bngrw.h
Normal file
0
exvs2hook/bngrw.h
Normal file
36
exvs2hook/config.c
Normal file
36
exvs2hook/config.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "exvs2hook/config.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
void exvs2_dll_config_load(
|
||||||
|
struct exvs2_dll_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"exvs2io",
|
||||||
|
L"path",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exvs2_hook_config_load(
|
||||||
|
struct exvs2_hook_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
platform_config_load(&cfg->platform, filename);
|
||||||
|
exvs2_dll_config_load(&cfg->dll, filename);
|
||||||
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
|
qr_config_load(&cfg->qr, filename);
|
||||||
|
bpreader_config_load(&cfg->reader, filename);
|
||||||
|
}
|
28
exvs2hook/config.h
Normal file
28
exvs2hook/config.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "exvs2hook/exvs2-dll.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
#include "gfxhook/config.h"
|
||||||
|
#include "amcus/config.h"
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
struct exvs2_hook_config {
|
||||||
|
struct platform_config platform;
|
||||||
|
struct exvs2_dll_config dll;
|
||||||
|
struct gfx_config gfx;
|
||||||
|
struct amcus_config amcus;
|
||||||
|
struct qr_config qr;
|
||||||
|
struct bpreader_config reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
void exvs2_dll_config_load(
|
||||||
|
struct exvs2_dll_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
||||||
|
void exvs2_hook_config_load(
|
||||||
|
struct exvs2_hook_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
93
exvs2hook/dllmain.c
Normal file
93
exvs2hook/dllmain.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "exvs2hook/config.h"
|
||||||
|
#include "exvs2hook/exvs2-dll.h"
|
||||||
|
#include "exvs2hook/jvs.h"
|
||||||
|
|
||||||
|
#include "amcus/amcus.h"
|
||||||
|
|
||||||
|
#include "hook/process.h"
|
||||||
|
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
|
||||||
|
#include "board/bpreader.h"
|
||||||
|
#include "board/qr.h"
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
#include "gfxhook/dxgi.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HMODULE exvs2_hook_mod;
|
||||||
|
static process_entry_t exvs2_startup;
|
||||||
|
static struct exvs2_hook_config exvs2_hook_cfg;
|
||||||
|
|
||||||
|
static DWORD CALLBACK exvs2_pre_startup(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
dprintf("--- Begin exvs2_pre_startup ---\n");
|
||||||
|
|
||||||
|
exvs2_hook_config_load(&exvs2_hook_cfg, L".\\bananatools.ini");
|
||||||
|
|
||||||
|
serial_hook_init();
|
||||||
|
|
||||||
|
struct dongle_info dinfo;
|
||||||
|
dinfo.vid = 0x0B9A;
|
||||||
|
dinfo.pid = 0x0C20;
|
||||||
|
wcscpy_s(dinfo.manufacturer, _countof(dinfo.manufacturer), L"UFD 3.0");
|
||||||
|
wcscpy_s(dinfo.product, _countof(dinfo.product), L"Silicon-Power8G");
|
||||||
|
|
||||||
|
hr = platform_hook_init(&exvs2_hook_cfg.platform, PLATFORM_BNA1, exvs2_jvs_init, exvs2_hook_mod, dinfo);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = exvs2_dll_init(&exvs2_hook_cfg.dll, exvs2_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = bpreader_init(&exvs2_hook_cfg.reader, 4);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = amcus_hook_init(&exvs2_hook_cfg.amcus);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_hook_init(&exvs2_hook_cfg.gfx);
|
||||||
|
gfx_dxgi_hook_init(&exvs2_hook_cfg.gfx, exvs2_hook_mod);
|
||||||
|
|
||||||
|
dprintf("--- End exvs2_pre_startup ---\n");
|
||||||
|
|
||||||
|
return exvs2_startup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (cause != DLL_PROCESS_ATTACH) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
exvs2_hook_mod = mod;
|
||||||
|
|
||||||
|
hr = process_hijack_startup(exvs2_pre_startup, &exvs2_startup);
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
100
exvs2hook/exvs2-dll.c
Normal file
100
exvs2hook/exvs2-dll.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "exvs2hook/exvs2-dll.h"
|
||||||
|
|
||||||
|
#include "util/dll-bind.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
const struct dll_bind_sym exvs2_dll_syms[] = {
|
||||||
|
{
|
||||||
|
.sym = "exvs2_io_jvs_init",
|
||||||
|
.off = offsetof(struct exvs2_dll, jvs_init),
|
||||||
|
}, {
|
||||||
|
.sym = "exvs2_io_jvs_poll",
|
||||||
|
.off = offsetof(struct exvs2_dll, jvs_poll),
|
||||||
|
}, {
|
||||||
|
.sym = "exvs2_io_jvs_read_coin_counter",
|
||||||
|
.off = offsetof(struct exvs2_dll, jvs_read_coin_counter),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exvs2_dll exvs2_dll;
|
||||||
|
|
||||||
|
HRESULT exvs2_dll_init(const struct exvs2_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("exvs2 IO: Failed to load IO DLL: %lx: %S\n",
|
||||||
|
hr,
|
||||||
|
cfg->path);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("exvs2 IO: Using custom IO DLL: %S\n", cfg->path);
|
||||||
|
src = owned;
|
||||||
|
} else {
|
||||||
|
owned = NULL;
|
||||||
|
src = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "exvs2_io_get_api_version");
|
||||||
|
|
||||||
|
if (get_api_version != NULL) {
|
||||||
|
exvs2_dll.api_version = get_api_version();
|
||||||
|
} else {
|
||||||
|
exvs2_dll.api_version = 0x0100;
|
||||||
|
dprintf("Custom IO DLL does not expose exvs2_io_get_api_version, "
|
||||||
|
"assuming API version 1.0.\n"
|
||||||
|
"Please ask the developer to update their DLL.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exvs2_dll.api_version >= 0x0200) {
|
||||||
|
hr = E_NOTIMPL;
|
||||||
|
dprintf("exvs2 IO: Custom IO DLL implements an unsupported "
|
||||||
|
"API version (%#04x). Please update Segatools.\n",
|
||||||
|
exvs2_dll.api_version);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = exvs2_dll_syms;
|
||||||
|
hr = dll_bind(&exvs2_dll, src, &sym, _countof(exvs2_dll_syms));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (src != self) {
|
||||||
|
dprintf("exvs2 IO: Custom IO DLL does not provide function "
|
||||||
|
"\"%s\". Please contact your IO DLL's developer for "
|
||||||
|
"further assistance.\n",
|
||||||
|
sym->sym);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
owned = NULL;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (owned != NULL) {
|
||||||
|
FreeLibrary(owned);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
20
exvs2hook/exvs2-dll.h
Normal file
20
exvs2hook/exvs2-dll.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "exvs2io/exvs2io.h"
|
||||||
|
|
||||||
|
struct exvs2_dll {
|
||||||
|
uint16_t api_version;
|
||||||
|
HRESULT (*jvs_init)(void);
|
||||||
|
HRESULT (*jvs_poll)(uint8_t *opbtn, uint16_t *gamepad);
|
||||||
|
void (*jvs_read_coin_counter)(uint16_t *coins);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exvs2_dll_config {
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct exvs2_dll exvs2_dll;
|
||||||
|
|
||||||
|
HRESULT exvs2_dll_init(const struct exvs2_dll_config *cfg, HINSTANCE self);
|
7
exvs2hook/exvs2hook.def
Normal file
7
exvs2hook/exvs2hook.def
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
LIBRARY exvs2hook
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
exvs2_io_get_api_version
|
||||||
|
exvs2_io_jvs_init
|
||||||
|
exvs2_io_jvs_poll
|
||||||
|
exvs2_io_jvs_read_coin_counter
|
125
exvs2hook/jvs.c
Normal file
125
exvs2hook/jvs.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
#include "hook/iohook.h"
|
||||||
|
|
||||||
|
#include "hooklib/uart.h"
|
||||||
|
#include "hooklib/fdshark.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
#include "util/dump.h"
|
||||||
|
|
||||||
|
#include "board/najv4.h"
|
||||||
|
|
||||||
|
#include "exvs2hook/jvs.h"
|
||||||
|
#include "exvs2hook/exvs2-dll.h"
|
||||||
|
|
||||||
|
static void exvs2_jvs_read_switches(void *ctx, struct najv4_switch_state *out);
|
||||||
|
static void exvs2_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out);
|
||||||
|
|
||||||
|
static const struct najv4_ops exvs2_jvs_najv4_ops = {
|
||||||
|
.read_switches = exvs2_jvs_read_switches,
|
||||||
|
.read_coin_counter = exvs2_jvs_read_coin_counter,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct najv4 exvs2_jvs_najv4;
|
||||||
|
|
||||||
|
HRESULT exvs2_jvs_init(struct jvs_node **out)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(exvs2_dll.jvs_init != NULL);
|
||||||
|
|
||||||
|
dprintf("exvs2 JVS: Starting IO backend\n");
|
||||||
|
hr = exvs2_dll.jvs_init();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("exvs2 JVS: Backend error, I/O disconnected: %x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
najv4_init(&exvs2_jvs_najv4, NULL, &exvs2_jvs_najv4_ops, NULL);
|
||||||
|
*out = najv4_to_jvs_node(&exvs2_jvs_najv4);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exvs2_jvs_read_switches(void *ctx, struct najv4_switch_state *out)
|
||||||
|
{
|
||||||
|
uint8_t opbtn = 0;
|
||||||
|
uint16_t gamebtn = 0;
|
||||||
|
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(exvs2_dll.jvs_poll != NULL);
|
||||||
|
|
||||||
|
exvs2_dll.jvs_poll(&opbtn, &gamebtn);
|
||||||
|
|
||||||
|
out->system = 0;
|
||||||
|
out->p1 = 0;
|
||||||
|
out->p2 = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (opbtn & EXVS2_IO_OPBTN_TEST) { // Test
|
||||||
|
out->system = 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_4) { // Btn4
|
||||||
|
out->p1 |= 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_3) { // Btn3
|
||||||
|
out->p1 |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_2) { // Btn2
|
||||||
|
out->p1 |= 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_1) { // Btn1
|
||||||
|
out->p1 |= 0x200;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_RIGHT) { // Right
|
||||||
|
out->p1 |= 0x400;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_LEFT) { // Left
|
||||||
|
out->p1 |= 0x800;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_DOWN) { // Down
|
||||||
|
out->p1 |= 0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_UP) { // Up
|
||||||
|
out->p1 |= 0x2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & EXVS2_IO_OPBTN_SERVICE) { // Service
|
||||||
|
out->p1 |= 0x4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamebtn & EXVS2_IO_GAMEBTN_START) { // Start
|
||||||
|
out->p1 = 0x8000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exvs2_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out)
|
||||||
|
{
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(exvs2_dll.jvs_read_coin_counter != NULL);
|
||||||
|
|
||||||
|
if (slot_no > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exvs2_dll.jvs_read_coin_counter(out);
|
||||||
|
}
|
8
exvs2hook/jvs.h
Normal file
8
exvs2hook/jvs.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "jvs/jvs-bus.h"
|
||||||
|
|
||||||
|
HRESULT exvs2_jvs_init(struct jvs_node **root);
|
33
exvs2hook/meson.build
Normal file
33
exvs2hook/meson.build
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
shared_library(
|
||||||
|
'exvs2hook',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
vs_module_defs : 'exvs2hook.def',
|
||||||
|
c_pch : '../precompiled.h',
|
||||||
|
dependencies : [
|
||||||
|
capnhook.get_variable('hook_dep'),
|
||||||
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
],
|
||||||
|
link_with : [
|
||||||
|
exvs2io_lib,
|
||||||
|
amcus_lib,
|
||||||
|
platform_lib,
|
||||||
|
util_lib,
|
||||||
|
hooklib_lib,
|
||||||
|
gfxhook_lib,
|
||||||
|
jvs_lib,
|
||||||
|
board_lib
|
||||||
|
],
|
||||||
|
sources : [
|
||||||
|
'dllmain.c',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
'exvs2-dll.c',
|
||||||
|
'exvs2-dll.h',
|
||||||
|
'jvs.c',
|
||||||
|
'jvs.h',
|
||||||
|
'bngrw.c',
|
||||||
|
'bngrw.h',
|
||||||
|
],
|
||||||
|
)
|
23
exvs2io/config.c
Normal file
23
exvs2io/config.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "exvs2io/config.h"
|
||||||
|
|
||||||
|
void exvs2_io_najv4_config_load(struct exvs2_najv4_config *cfg, const wchar_t *filename)
|
||||||
|
{
|
||||||
|
cfg->test = GetPrivateProfileIntW(L"najv4", L"test", VK_HOME, filename);
|
||||||
|
cfg->service = GetPrivateProfileIntW(L"najv4", L"service", VK_DELETE, filename);
|
||||||
|
cfg->coin = GetPrivateProfileIntW(L"najv4", L"coin", VK_INSERT, filename);
|
||||||
|
cfg->up = GetPrivateProfileIntW(L"najv4", L"up", VK_UP, filename);
|
||||||
|
cfg->down = GetPrivateProfileIntW(L"najv4", L"down", VK_DOWN, filename);
|
||||||
|
cfg->left = GetPrivateProfileIntW(L"najv4", L"left", VK_LEFT, filename);
|
||||||
|
cfg->right = GetPrivateProfileIntW(L"najv4", L"right", VK_RIGHT, filename);
|
||||||
|
cfg->start = GetPrivateProfileIntW(L"najv4", L"start", VK_SPACE, filename);
|
||||||
|
cfg->btn1 = GetPrivateProfileIntW(L"najv4", L"btn1", '1', filename);
|
||||||
|
cfg->btn2 = GetPrivateProfileIntW(L"najv4", L"btn2", '2', filename);
|
||||||
|
cfg->btn3 = GetPrivateProfileIntW(L"najv4", L"btn3", '3', filename);
|
||||||
|
cfg->btn4 = GetPrivateProfileIntW(L"najv4", L"btn4", '4', filename);
|
||||||
|
}
|
21
exvs2io/config.h
Normal file
21
exvs2io/config.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct exvs2_najv4_config {
|
||||||
|
uint8_t test;
|
||||||
|
uint8_t service;
|
||||||
|
uint8_t coin;
|
||||||
|
uint8_t up;
|
||||||
|
uint8_t down;
|
||||||
|
uint8_t left;
|
||||||
|
uint8_t right;
|
||||||
|
uint8_t start;
|
||||||
|
uint8_t btn1;
|
||||||
|
uint8_t btn2;
|
||||||
|
uint8_t btn3;
|
||||||
|
uint8_t btn4;
|
||||||
|
};
|
||||||
|
|
||||||
|
void exvs2_io_najv4_config_load(struct exvs2_najv4_config *cfg, const wchar_t *filename);
|
93
exvs2io/exvs2io.c
Normal file
93
exvs2io/exvs2io.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "exvs2io/exvs2io.h"
|
||||||
|
#include "exvs2io/config.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static bool exvs2_io_coin = false;
|
||||||
|
static uint16_t exvs2_coin_ct = 0;
|
||||||
|
static struct exvs2_najv4_config najv4_cfg;
|
||||||
|
|
||||||
|
uint16_t exvs2_io_get_api_version(void)
|
||||||
|
{
|
||||||
|
return 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT exvs2_io_jvs_init(void)
|
||||||
|
{
|
||||||
|
dprintf("exvs2 IO: JVS Init\n");
|
||||||
|
exvs2_io_najv4_config_load(&najv4_cfg, L".\\bananatools.ini");
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT exvs2_io_jvs_poll(uint8_t *opbtn, uint16_t *gamepad)
|
||||||
|
{
|
||||||
|
*opbtn = 0;
|
||||||
|
*gamepad = 0;
|
||||||
|
|
||||||
|
if ((GetAsyncKeyState(najv4_cfg.test) & 0x8000)) {
|
||||||
|
*opbtn |= EXVS2_IO_OPBTN_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.service) & 0x8000) {
|
||||||
|
*opbtn |= EXVS2_IO_OPBTN_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.up) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.down) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.left) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.right) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.start) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.btn1) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.btn2) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.btn3) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.btn4) & 0x8000) {
|
||||||
|
*gamepad |= EXVS2_IO_GAMEBTN_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exvs2_io_jvs_read_coin_counter(uint16_t *coins)
|
||||||
|
{
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.coin) & 0x8000) {
|
||||||
|
if (!exvs2_io_coin) {
|
||||||
|
exvs2_io_coin = true;
|
||||||
|
exvs2_coin_ct++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exvs2_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*coins = exvs2_coin_ct;
|
||||||
|
}
|
7
exvs2io/exvs2io.def
Normal file
7
exvs2io/exvs2io.def
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
LIBRARY exvs2hook
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
exvs2_io_get_api_version
|
||||||
|
exvs2_io_jvs_init
|
||||||
|
exvs2_io_jvs_poll
|
||||||
|
exvs2_io_read_coin_counter
|
51
exvs2io/exvs2io.h
Normal file
51
exvs2io/exvs2io.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "exvs2io/config.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXVS2_IO_OPBTN_TEST = 0x01,
|
||||||
|
EXVS2_IO_OPBTN_SERVICE = 0x02,
|
||||||
|
EXVS2_IO_OPBTN_COIN = 0x20,
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
EXVS2_IO_GAMEBTN_1 = 0x1,
|
||||||
|
EXVS2_IO_GAMEBTN_2 = 0x2,
|
||||||
|
EXVS2_IO_GAMEBTN_3 = 0x4,
|
||||||
|
EXVS2_IO_GAMEBTN_4 = 0x8,
|
||||||
|
EXVS2_IO_GAMEBTN_UP = 0x10,
|
||||||
|
EXVS2_IO_GAMEBTN_DOWN = 0x20,
|
||||||
|
EXVS2_IO_GAMEBTN_LEFT = 0x40,
|
||||||
|
EXVS2_IO_GAMEBTN_RIGHT = 0x80,
|
||||||
|
EXVS2_IO_GAMEBTN_START = 0x100,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get the version of the Pokken 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 exvs2_io_get_api_version(void);
|
||||||
|
|
||||||
|
/* Initialize the IO DLL. This is the second function that will be called on
|
||||||
|
your DLL, after exvs2_io_get_api_version.
|
||||||
|
|
||||||
|
All subsequent calls to this API may originate from arbitrary threads.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT exvs2_io_jvs_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 exvs2_io_jvs_poll(uint8_t *opbtn, uint16_t *gamepad);
|
||||||
|
|
||||||
|
void exvs2_io_jvs_read_coin_counter(uint16_t *coins);
|
16
exvs2io/meson.build
Normal file
16
exvs2io/meson.build
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
exvs2io_lib = static_library(
|
||||||
|
'exvs2io',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
c_pch : '../precompiled.h',
|
||||||
|
dependencies : [
|
||||||
|
xinput_lib,
|
||||||
|
],
|
||||||
|
sources : [
|
||||||
|
'exvs2io.c',
|
||||||
|
'exvs2io.h',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
],
|
||||||
|
)
|
@ -73,6 +73,7 @@ void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self)
|
|||||||
|
|
||||||
memcpy(&gfx_config, cfg, sizeof(*cfg));
|
memcpy(&gfx_config, cfg, sizeof(*cfg));
|
||||||
hook_table_apply(NULL, "dxgi.dll", dxgi_hooks, _countof(dxgi_hooks));
|
hook_table_apply(NULL, "dxgi.dll", dxgi_hooks, _countof(dxgi_hooks));
|
||||||
|
hook_table_apply(NULL, "dxgi", dxgi_hooks, _countof(dxgi_hooks));
|
||||||
|
|
||||||
if (next_CreateDXGIFactory == NULL || next_CreateDXGIFactory1 == NULL) {
|
if (next_CreateDXGIFactory == NULL || next_CreateDXGIFactory1 == NULL) {
|
||||||
dxgi = LoadLibraryW(L"dxgi.dll");
|
dxgi = LoadLibraryW(L"dxgi.dll");
|
||||||
@ -110,14 +111,15 @@ void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `CreateDXGIFactory2` was introduced in Windows 8.1 and the original
|
|
||||||
* Nu runs Windows 8, so do not require it to exist */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self != NULL) {
|
if (self != NULL) {
|
||||||
dll_hook_push(self, L"dxgi.dll");
|
dll_hook_push(self, L"dxgi.dll");
|
||||||
|
dll_hook_push(self, L"dxgi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dprintf("DXGI: init\n");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -192,7 +194,7 @@ HRESULT WINAPI CreateDXGIFactory2(UINT flags, REFIID riid, void **factory)
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//hr = hook_factory(riid, factory);
|
hr = hook_factory(riid, factory);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
return hr;
|
return hr;
|
||||||
@ -206,8 +208,10 @@ static HRESULT hook_factory(REFIID riid, void **factory)
|
|||||||
struct com_proxy *proxy;
|
struct com_proxy *proxy;
|
||||||
IDXGIFactory *api_0;
|
IDXGIFactory *api_0;
|
||||||
IDXGIFactory1 *api_1;
|
IDXGIFactory1 *api_1;
|
||||||
|
IDXGIFactory2 *api_2;
|
||||||
IDXGIFactoryVtbl *vtbl_0;
|
IDXGIFactoryVtbl *vtbl_0;
|
||||||
IDXGIFactory1Vtbl *vtbl_1;
|
IDXGIFactory1Vtbl *vtbl_1;
|
||||||
|
IDXGIFactory2Vtbl *vtbl_2;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
api_0 = NULL;
|
api_0 = NULL;
|
||||||
@ -242,6 +246,20 @@ static HRESULT hook_factory(REFIID riid, void **factory)
|
|||||||
vtbl_1 = proxy->vptr;
|
vtbl_1 = proxy->vptr;
|
||||||
vtbl_1->CreateSwapChain = my_IDXGIFactory1_CreateSwapChain;
|
vtbl_1->CreateSwapChain = my_IDXGIFactory1_CreateSwapChain;
|
||||||
|
|
||||||
|
*factory = proxy;
|
||||||
|
} else if (memcmp(riid, &IID_IDXGIFactory2, sizeof(*riid)) == 0) {
|
||||||
|
api_2 = *factory;
|
||||||
|
hr = com_proxy_wrap(&proxy, api_2, sizeof(*api_2->lpVtbl));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("DXGI: com_proxy_wrap returned %x\n", (int) hr);
|
||||||
|
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtbl_2 = proxy->vptr;
|
||||||
|
vtbl_2->CreateSwapChain = my_IDXGIFactory2_CreateSwapChain;
|
||||||
|
|
||||||
*factory = proxy;
|
*factory = proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +273,9 @@ fail:
|
|||||||
if (api_1 != NULL) {
|
if (api_1 != NULL) {
|
||||||
IDXGIFactory1_Release(api_1);
|
IDXGIFactory1_Release(api_1);
|
||||||
}
|
}
|
||||||
|
if (api_2 != NULL) {
|
||||||
|
IDXGIFactory2_Release(api_2);
|
||||||
|
}
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,8 @@ subdir('amcus')
|
|||||||
|
|
||||||
subdir('ferrumio')
|
subdir('ferrumio')
|
||||||
subdir('taikoio')
|
subdir('taikoio')
|
||||||
|
subdir('exvs2io')
|
||||||
|
|
||||||
subdir('taikohook')
|
subdir('taikohook')
|
||||||
subdir('ferrumhook')
|
subdir('ferrumhook')
|
||||||
|
subdir('exvs2hook')
|
||||||
|
Loading…
Reference in New Issue
Block a user