mirror of
https://gitea.tendokyu.moe/TeamTofuShop/segatools.git
synced 2026-09-22 22:37:59 +03:00
Add support for Sangokushi Taisen and Eiketsu Taisen (#85)
This adds full support for the Taisen series of games, namely Sangokushi Taisen and Eiketsu Taisen. Games added: * Sangokushi Taisen (SDDD) * Eiketsu Taisen (SDGY) Devices added: * CHC-320 printer (SGT) * "Printer camera" (SGT, unsure what this actually really is) * CX-7000 printer (EKT) * Y3CR BD SIE F720MM (SGT, EKT) Notable changes in the codebase: * Renamed everything printer specific to seperate between CHC and CX. * Many new function and registry hooks were added across the board. * An error is now logged when segatools.ini (or the path in `SEGATOOLS_CONFIG_PATH`) cannot be found. * Netenv now redirects UDP broadcasts targeted at the subnet that is specified in the keychip configuration. The terminal announces it's presence by broadcasting UDP to 192.168.189.255, this will be redirected to 255.255.255.255. * Vfs now seperates between absolute and relative paths in `vfs_fixup_path` via an environment variable called `SEGATOOLS_VFS_RELATIVE_PATH`. This is needed because amcapture accesses files as workingdirectory-relative. * The Y3 board emulation has support for external Y3 I/O dlls. The default implementation (y3ws) that comes with this is a websocket implementation. The docs are available under `doc\y3ws.txt` and a sample card player .html file is under `dist\ekt\card_player.html`. I already know one person that is hosting a massively improved version of it. * For websockets, my own websocket implementation is used as a subproject (MIT license): https://github.com/akechi-haruka/cwinwebsocket * For JSON, cJSON was embedded (MIT license): https://github.com/DaveGamble/cJSON * y3ws reads all printed cards from `DEVICE\print` by default including card back sides. It's up to the client to merge or skip them. Remarks: * SGT takes ~8 minutes to load. This seems to be intentional. * SGT uses some weird TCP network implementation like IDZ. I have not bothered reversing that yet and I have confirmed everything working from the test menu. * EKT will throw a network error if no terminal is found. You must run the terminal on another computer to be able to launch the satellite. * EKT has a very bizzare speed glitch that will speed up the ingame unit movement by several 1000% and also slows down cutscene animations by 90%. When this effect is active, you also take a ton more damage than usual. I do not know what causes this and it seems PC specific. * EKT is very stutter sensitive and will throw error 6401 (I/O timeout) at random when trying to alt+tab or have other things running. * EKT features a livestream system called Enbu (or "Dojo Upload"). While you are in a match, regardless of vs. AI or another player, the game will record your screen and live-stream it to the Enbu server as defined by the game server's startup response. The application responsible for that, "AM Capture" will not limit it's recording to the game window, but also anything that overlays the game window (notifications, popups, alt+tabbed windows, web browsers, etc). Since this is live-streamed, killing the process will have no effect afterwards, as the frames showing unwanted things will already have been transmitted. To make people aware of this, a one-time dialog message will pop up when starting EKT. The flag for that is stored in the DEVICE folder. Closes #25. Co-authored-by: Dniel97 <Dniel97@noreply.gitea.tendokyu.moe> Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/85 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com>
This commit is contained in:
committed by
Dniel97
co-authored by
Dniel97
parent
b9e714dd1d
commit
9c67f53902
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ static DWORD CALLBACK carol_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL, false);
|
||||
hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL, false, false);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
|
||||
@@ -40,7 +40,7 @@ void cm_hook_config_load(
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
touch_screen_config_load(&cfg->touch, filename);
|
||||
printer_config_load(&cfg->printer, filename);
|
||||
printer_chc_config_load(&cfg->printer, filename);
|
||||
cm_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include "cmhook/cm-dll.h"
|
||||
|
||||
@@ -22,7 +22,7 @@ struct cm_hook_config {
|
||||
struct vfd_config vfd;
|
||||
struct cm_dll_config dll;
|
||||
struct touch_screen_config touch;
|
||||
struct printer_config printer;
|
||||
struct printer_chc_config printer;
|
||||
struct unity_config unity;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ static DWORD CALLBACK cm_pre_startup(void)
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
|
||||
printer_chc_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "ekthook/config.h"
|
||||
#include "ekthook/ekt-dll.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
|
||||
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
|
||||
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
|
||||
cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
|
||||
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
|
||||
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"boardNumber",
|
||||
L"15093-06",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
|
||||
for (int i = n; i < sizeof(cfg->board_number); i++)
|
||||
{
|
||||
cfg->board_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"chipNumber",
|
||||
L"6710A",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
|
||||
for (int i = n; i < sizeof(cfg->chip_number); i++)
|
||||
{
|
||||
cfg->chip_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"bootChipNumber",
|
||||
L"6709 ",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
|
||||
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
|
||||
{
|
||||
cfg->boot_chip_number[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void ekt_dll_config_load(
|
||||
struct ekt_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"ektio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
|
||||
void ekt_hook_config_load(
|
||||
struct ekt_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);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
y3_config_load(&cfg->y3, filename);
|
||||
printer_cx_config_load(&cfg->printer, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
ekt_dll_config_load(&cfg->dll, filename);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/config.h"
|
||||
#include "board/led15093.h"
|
||||
|
||||
#include "ekthook/ekt-dll.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
#include "unityhook/config.h"
|
||||
|
||||
struct ekt_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct io4_config io4;
|
||||
struct dvd_config dvd;
|
||||
struct led15093_config led15093;
|
||||
struct y3_config y3;
|
||||
struct ekt_dll_config dll;
|
||||
struct unity_config unity;
|
||||
struct printer_cx_config printer;
|
||||
};
|
||||
|
||||
void ekt_dll_config_load(
|
||||
struct ekt_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void ekt_hook_config_load(
|
||||
struct ekt_hook_config *cfg,
|
||||
const wchar_t *filename);
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
"Eiketsu Taisen" (ekt) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-15257-01 "Type 4" I/O Board
|
||||
|
||||
[Satellite]
|
||||
|
||||
USB: 630-00011 G-Printec CX-7000 Printer
|
||||
COM2: 837-15093-06 LED Controller Board
|
||||
COM3: 837-15396 "Gen 3" Aime Reader
|
||||
COM4: 601-13160-01 "Flat Panel Reader" Y3CR BD SIE F720MM Board
|
||||
|
||||
[Terminal]
|
||||
|
||||
COM1: 837-15396 "Gen 3" Aime Reader
|
||||
COM3: 837-15093-06 LED Controller Board
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ekt-dll.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/led15093.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "ekthook/config.h"
|
||||
#include "ekthook/io4.h"
|
||||
#include "hooklib/createprocess.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "unityhook/hook.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "hooklib/y3-dll.h"
|
||||
#include "hooklib/y3.h"
|
||||
#include "util/lib.h"
|
||||
|
||||
static HMODULE ekt_hook_mod;
|
||||
static process_entry_t ekt_startup;
|
||||
static struct ekt_hook_config ekt_hook_cfg;
|
||||
|
||||
static void unity_hook_callback(HMODULE hmodule, const wchar_t* p) {
|
||||
netenv_hook_apply_hooks(hmodule);
|
||||
createprocess_hook_apply_hooks(hmodule);
|
||||
}
|
||||
|
||||
static void check_and_display_warning(void) {
|
||||
wchar_t* module_path;
|
||||
wchar_t* file_name;
|
||||
|
||||
module_path = module_file_name(NULL);
|
||||
|
||||
if (module_path != NULL) {
|
||||
file_name = PathFindFileNameW(module_path);
|
||||
|
||||
free(module_path);
|
||||
module_path = NULL;
|
||||
|
||||
_wcslwr(file_name);
|
||||
|
||||
if (wcsstr(file_name, L"ekt.exe") != NULL) {
|
||||
wchar_t recording_flag_path[MAX_PATH];
|
||||
PathCombineW(recording_flag_path, ekt_hook_cfg.platform.vfs.appdata, L"recording_warning_seen");
|
||||
if (!PathFileExistsW(recording_flag_path)) {
|
||||
if (MessageBoxW(
|
||||
NULL,
|
||||
L"This game has an ability during battle to record and upload your entire desktop content (including other windows, task bar, browsers, etc.)\n\nMake sure you trust the server you are playing on.\n\nThis message will not be shown again.",
|
||||
L"Segatools Privacy Warning", MB_ICONWARNING | MB_OKCANCEL) != IDOK) {
|
||||
ExitProcess(0);
|
||||
}
|
||||
CreateFileW(recording_flag_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ekt_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
bool is_terminal;
|
||||
|
||||
dprintf("--- Begin ekt_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
ekt_hook_config_load(&ekt_hook_cfg, get_config_path());
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&ekt_hook_cfg.dvd, ekt_hook_mod);
|
||||
serial_hook_init();
|
||||
|
||||
createprocess_push_hook_w(L"fsutil", L"", L"", true, true);
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
hr = y3_hook_init(&ekt_hook_cfg.y3, ekt_hook_mod, get_config_path());
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printer_cx_hook_init(&ekt_hook_cfg.printer, ekt_hook_mod);
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&ekt_hook_cfg.platform,
|
||||
"SDGY",
|
||||
"ACA1",
|
||||
ekt_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize Terminal/Satellite hooks */
|
||||
if (strncmp(ekt_hook_cfg.platform.nusec.platform_id, "ACA1", 4) == 0) {
|
||||
// Terminal
|
||||
is_terminal = true;
|
||||
} else if (strncmp(ekt_hook_cfg.platform.nusec.platform_id, "ACA2", 4) == 0) {
|
||||
// Satellite
|
||||
is_terminal = false;
|
||||
} else {
|
||||
// Unknown
|
||||
dprintf("Unknown platform ID: %s\n", ekt_hook_cfg.platform.nusec.platform_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dprintf("System: Cabinet Type: %s\n", is_terminal ? "Terminal" : "Satellite");
|
||||
|
||||
// LED: terminal uses COM 3 and satellite use COM 2
|
||||
unsigned int led_port_no[2] = {is_terminal ? 3 : 2, 0};
|
||||
|
||||
// AIME: terminal uses COM 1 and satellite use COM 3
|
||||
unsigned int aime_port_no = is_terminal ? 1 : 3;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = ekt_dll_init(&ekt_hook_cfg.dll, ekt_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = ekt_io4_hook_init(&ekt_hook_cfg.io4, is_terminal);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15093_hook_init(&ekt_hook_cfg.led15093,
|
||||
ekt_dll.led_init, ekt_dll.led_set_leds, led_port_no);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&ekt_hook_cfg.aime, aime_port_no, 3,
|
||||
ekt_hook_mod);
|
||||
|
||||
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 `ekthook` initialization. */
|
||||
|
||||
unity_hook_init(&ekt_hook_cfg.unity, ekt_hook_mod, unity_hook_callback);
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(get_config_path());
|
||||
|
||||
dprintf("--- End ekt_pre_startup ---\n");
|
||||
|
||||
/* Recording warning */
|
||||
check_and_display_warning();
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return ekt_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ekt_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(ekt_pre_startup, &ekt_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ekthook/ekt-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym ekt_dll_syms[] = {
|
||||
{
|
||||
.sym = "ekt_io_init",
|
||||
.off = offsetof(struct ekt_dll, init),
|
||||
}, {
|
||||
.sym = "ekt_io_poll",
|
||||
.off = offsetof(struct ekt_dll, poll),
|
||||
}, {
|
||||
.sym = "ekt_io_get_opbtns",
|
||||
.off = offsetof(struct ekt_dll, get_opbtns),
|
||||
}, {
|
||||
.sym = "ekt_io_get_gamebtns",
|
||||
.off = offsetof(struct ekt_dll, get_gamebtns),
|
||||
}, {
|
||||
.sym = "ekt_io_get_trackball_position",
|
||||
.off = offsetof(struct ekt_dll, get_trackball_position),
|
||||
}, {
|
||||
.sym = "ekt_io_led_init",
|
||||
.off = offsetof(struct ekt_dll, led_init),
|
||||
}, {
|
||||
.sym = "ekt_io_led_set_colors",
|
||||
.off = offsetof(struct ekt_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
struct ekt_dll ekt_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 ekt_dll_init(const struct ekt_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("EKT IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("EKT IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "ekt_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
ekt_dll.api_version = get_api_version();
|
||||
} else {
|
||||
ekt_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose ekt_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (ekt_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("EKT IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
ekt_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = ekt_dll_syms;
|
||||
hr = dll_bind(&ekt_dll, src, &sym, _countof(ekt_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("EKT 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;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "ektio/ektio.h"
|
||||
|
||||
struct ekt_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint32_t *gamebtn);
|
||||
void (*get_trackball_position)(uint16_t *x, uint16_t *y);
|
||||
HRESULT (*led_init)(void);
|
||||
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||
};
|
||||
|
||||
struct ekt_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct ekt_dll ekt_dll;
|
||||
|
||||
HRESULT ekt_dll_init(const struct ekt_dll_config *cfg, HINSTANCE self);
|
||||
@@ -0,0 +1,73 @@
|
||||
LIBRARY ekthook
|
||||
|
||||
EXPORTS
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_vfd_set_text
|
||||
aime_io_vfd_set_state
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
aime_io_nfc_get_mifare_uid
|
||||
aime_io_nfc_mifare_select
|
||||
aime_io_nfc_mifare_set_key
|
||||
aime_io_nfc_mifare_authenticate
|
||||
aime_io_nfc_mifare_read_block
|
||||
aime_io_nfc_felica_transact
|
||||
aime_io_nfc_radio_on
|
||||
aime_io_nfc_radio_off
|
||||
aime_io_nfc_to_update_mode
|
||||
aime_io_nfc_send_hex_data
|
||||
ekt_io_get_api_version
|
||||
ekt_io_get_gamebtns
|
||||
ekt_io_get_opbtns
|
||||
ekt_io_get_trackball_position
|
||||
ekt_io_init
|
||||
ekt_io_poll
|
||||
ekt_io_led_init
|
||||
ekt_io_led_set_colors
|
||||
y3_io_get_api_version
|
||||
y3_io_init
|
||||
y3_io_close
|
||||
y3_io_get_cards
|
||||
API_DLLVersion @1
|
||||
API_GetLastError @2
|
||||
API_GetErrorMessage @3
|
||||
API_Connect @4
|
||||
API_Close @5
|
||||
API_Start @6
|
||||
API_Stop @7
|
||||
API_GetFirmVersion @8
|
||||
API_GetFirmName @9
|
||||
API_GetTargetCode @10
|
||||
API_GetStatus @11
|
||||
API_GetCounter @12
|
||||
API_ClearError @13
|
||||
API_Reset @14
|
||||
API_GetCardInfo @15
|
||||
API_GetCardInfoCharSize @16
|
||||
API_SetDevice @17
|
||||
API_SetCommand @18
|
||||
API_FirmwareUpdate @19
|
||||
API_Calibration @20
|
||||
API_GetCalibrationResult @21
|
||||
API_GetProcTime @22
|
||||
API_GetMemStatus @23
|
||||
API_GetMemCounter @24
|
||||
API_SetSysControl @25
|
||||
API_GetSysControl @26
|
||||
API_SetParameter @27
|
||||
API_GetParameter @28
|
||||
API_TestReset @29
|
||||
API_DebugReset @30
|
||||
API_GetBoardType @31
|
||||
API_GetCardDataSize @32
|
||||
API_GetFirmDate @33
|
||||
API_SystemCommand @34
|
||||
API_CalcCheckSum @35
|
||||
API_GetCheckSumResult @36
|
||||
API_BlockRead @37
|
||||
API_GetBlockReadResult @38
|
||||
API_BlockWrite @39
|
||||
API_GetDebugParam @40
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "io4.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "ekthook/ekt-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT ekt_io4_poll(void *ctx, struct io4_state *state);
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops ekt_io4_ops = {
|
||||
.poll = ekt_io4_poll,
|
||||
};
|
||||
|
||||
static bool io_is_terminal;
|
||||
|
||||
HRESULT ekt_io4_hook_init(const struct io4_config *cfg, bool is_terminal)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(ekt_dll.init != NULL);
|
||||
|
||||
hr = io4_hook_init(cfg, &ekt_io4_ops, NULL, L"ekt", false);
|
||||
|
||||
io_is_terminal = is_terminal;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ekt_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT ekt_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
uint8_t opbtn;
|
||||
uint16_t x, y;
|
||||
uint32_t gamebtn;
|
||||
HRESULT hr;
|
||||
|
||||
assert(ekt_dll.poll != NULL);
|
||||
assert(ekt_dll.get_opbtns != NULL);
|
||||
assert(ekt_dll.get_gamebtns != NULL);
|
||||
assert(ekt_dll.get_trackball_position != NULL);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
hr = ekt_dll.poll();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
opbtn = 0;
|
||||
gamebtn = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
ekt_dll.get_opbtns(&opbtn);
|
||||
ekt_dll.get_gamebtns(&gamebtn);
|
||||
ekt_dll.get_trackball_position(&x, &y);
|
||||
|
||||
if (opbtn & EKT_IO_OPBTN_TEST) {
|
||||
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||
}
|
||||
|
||||
if (opbtn & EKT_IO_OPBTN_SERVICE) {
|
||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||
}
|
||||
|
||||
if (opbtn & EKT_IO_OPBTN_SW1) {
|
||||
state->buttons[0] |= 1 << 2;
|
||||
}
|
||||
|
||||
if (opbtn & EKT_IO_OPBTN_SW2) {
|
||||
state->buttons[0] |= 1 << 3;
|
||||
}
|
||||
|
||||
if (opbtn & EKT_IO_OPBTN_COIN) {
|
||||
coins++;
|
||||
}
|
||||
state->chutes[0] = coins << 8;
|
||||
|
||||
if (!io_is_terminal) {
|
||||
if (gamebtn & EKT_IO_GAMEBTN_HOUGU) {
|
||||
state->buttons[1] |= 1 << 14;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_RYUUHA) {
|
||||
state->buttons[1] |= 1 << 12;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_MENU) {
|
||||
state->buttons[0] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_START) {
|
||||
state->buttons[0] |= 1 << 7;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_STRATAGEM) {
|
||||
state->buttons[1] |= 1 << 15;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_STRATAGEM_LOCK) {
|
||||
state->buttons[1] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_VOL_DOWN) {
|
||||
state->buttons[1] |= 1 << 10;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_VOL_UP) {
|
||||
state->buttons[1] |= 1 << 11;
|
||||
}
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_0) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C2 : EKT_NUMPAD_TERM_C2;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R4 : EKT_NUMPAD_TERM_R4;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_1) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C1 : EKT_NUMPAD_TERM_C1;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R1 : EKT_NUMPAD_TERM_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_2) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C2 : EKT_NUMPAD_TERM_C2;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R1 : EKT_NUMPAD_TERM_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_3) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C3 : EKT_NUMPAD_TERM_C3;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R1 : EKT_NUMPAD_TERM_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_4) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C1 : EKT_NUMPAD_TERM_C1;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R2 : EKT_NUMPAD_TERM_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_5) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C2 : EKT_NUMPAD_TERM_C2;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R2 : EKT_NUMPAD_TERM_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_6) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C3 : EKT_NUMPAD_TERM_C3;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R2 : EKT_NUMPAD_TERM_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_7) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C1 : EKT_NUMPAD_TERM_C1;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R3 : EKT_NUMPAD_TERM_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_8) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C2 : EKT_NUMPAD_TERM_C2;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R3 : EKT_NUMPAD_TERM_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_9) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C3 : EKT_NUMPAD_TERM_C3;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R3 : EKT_NUMPAD_TERM_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_CLEAR) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C1 : EKT_NUMPAD_TERM_C1;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R4 : EKT_NUMPAD_TERM_R4;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_NUMPAD_ENTER) {
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_C3 : EKT_NUMPAD_TERM_C3;
|
||||
state->buttons[0] |= !io_is_terminal ? EKT_NUMPAD_SATE_R4 : EKT_NUMPAD_TERM_R4;
|
||||
}
|
||||
|
||||
if (io_is_terminal) {
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_CANCEL) {
|
||||
state->buttons[1] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_DECIDE) {
|
||||
state->buttons[1] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_LEFT) {
|
||||
state->buttons[0] |= 1 << 3;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_UP) {
|
||||
state->buttons[0] |= 1 << 5;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_RIGHT) {
|
||||
state->buttons[0] |= 1 << 2;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_DOWN) {
|
||||
state->buttons[0] |= 1 << 4;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_LEFT_2) {
|
||||
state->buttons[1] |= 1 << 3;
|
||||
}
|
||||
|
||||
if (gamebtn & EKT_IO_GAMEBTN_TERMINAL_RIGHT_2) {
|
||||
state->buttons[1] |= 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
state->spinners[2] = x;
|
||||
state->spinners[3] = y;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
enum {
|
||||
EKT_NUMPAD_SATE_R1 = 1 << 1,
|
||||
EKT_NUMPAD_SATE_R2 = 1 << 0,
|
||||
EKT_NUMPAD_SATE_R3 = 1 << 15,
|
||||
EKT_NUMPAD_SATE_R4 = 1 << 14,
|
||||
EKT_NUMPAD_SATE_C1 = 1 << 12,
|
||||
EKT_NUMPAD_SATE_C2 = 1 << 11,
|
||||
EKT_NUMPAD_SATE_C3 = 1 << 10,
|
||||
EKT_NUMPAD_TERM_R1 = 1 << 1,
|
||||
EKT_NUMPAD_TERM_R2 = 1 << 0,
|
||||
EKT_NUMPAD_TERM_R3 = 1 << 15,
|
||||
EKT_NUMPAD_TERM_R4 = 1 << 14,
|
||||
EKT_NUMPAD_TERM_C1 = 1 << 13,
|
||||
EKT_NUMPAD_TERM_C2 = 1 << 12,
|
||||
EKT_NUMPAD_TERM_C3 = 1 << 11,
|
||||
};
|
||||
|
||||
HRESULT ekt_io4_hook_init(const struct io4_config *cfg, bool is_terminal);
|
||||
@@ -0,0 +1,31 @@
|
||||
shared_library(
|
||||
'ekthook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'ekthook.def',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep')
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
board_lib,
|
||||
ektio_lib,
|
||||
hooklib_lib,
|
||||
jvs_lib,
|
||||
platform_lib,
|
||||
unityhook_lib,
|
||||
util_lib,
|
||||
y3io_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'ekt-dll.c',
|
||||
'ekt-dll.h',
|
||||
'io4.c',
|
||||
'io4.h',
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ektio/ektio.h"
|
||||
|
||||
struct ekt_io_backend {
|
||||
void (*get_gamebtns)(uint32_t *gamebtn);
|
||||
void (*get_trackball)(uint16_t *x, uint16_t *y);
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ektio/config.h"
|
||||
|
||||
#include <xinput.h>
|
||||
|
||||
|
||||
void ekt_kb_config_load(
|
||||
struct ekt_kb_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
|
||||
cfg->vk_menu = GetPrivateProfileIntW(L"keyboard", L"menu", 'A', filename);
|
||||
cfg->vk_start = GetPrivateProfileIntW(L"keyboard", L"start", 'S', filename);
|
||||
cfg->vk_stratagem = GetPrivateProfileIntW(L"keyboard", L"stratagem", 'D', filename);
|
||||
cfg->vk_stratagem_lock = GetPrivateProfileIntW(L"keyboard", L"stratagem_lock", 'F', filename);
|
||||
cfg->vk_hougu = GetPrivateProfileIntW(L"keyboard", L"hougu", 'G', filename);
|
||||
cfg->vk_ryuuha = GetPrivateProfileIntW(L"keyboard", L"ryuuha", 'H', filename);
|
||||
|
||||
cfg->vk_tenkey_0 = GetPrivateProfileIntW(L"keyboard", L"tenkey_0", VK_NUMPAD0, filename);
|
||||
cfg->vk_tenkey_1 = GetPrivateProfileIntW(L"keyboard", L"tenkey_1", VK_NUMPAD1, filename);
|
||||
cfg->vk_tenkey_2 = GetPrivateProfileIntW(L"keyboard", L"tenkey_2", VK_NUMPAD2, filename);
|
||||
cfg->vk_tenkey_3 = GetPrivateProfileIntW(L"keyboard", L"tenkey_3", VK_NUMPAD3, filename);
|
||||
cfg->vk_tenkey_4 = GetPrivateProfileIntW(L"keyboard", L"tenkey_4", VK_NUMPAD4, filename);
|
||||
cfg->vk_tenkey_5 = GetPrivateProfileIntW(L"keyboard", L"tenkey_5", VK_NUMPAD5, filename);
|
||||
cfg->vk_tenkey_6 = GetPrivateProfileIntW(L"keyboard", L"tenkey_6", VK_NUMPAD6, filename);
|
||||
cfg->vk_tenkey_7 = GetPrivateProfileIntW(L"keyboard", L"tenkey_7", VK_NUMPAD7, filename);
|
||||
cfg->vk_tenkey_8 = GetPrivateProfileIntW(L"keyboard", L"tenkey_8", VK_NUMPAD8, filename);
|
||||
cfg->vk_tenkey_9 = GetPrivateProfileIntW(L"keyboard", L"tenkey_9", VK_NUMPAD9, filename);
|
||||
cfg->vk_tenkey_clear = GetPrivateProfileIntW(L"keyboard", L"tenkey_clear", VK_DECIMAL, filename);
|
||||
cfg->vk_tenkey_enter = GetPrivateProfileIntW(L"keyboard", L"tenkey_enter", VK_RETURN, filename);
|
||||
|
||||
cfg->vk_vol_down = GetPrivateProfileIntW(L"keyboard", L"vol_down", VK_NEXT, filename);
|
||||
cfg->vk_vol_up = GetPrivateProfileIntW(L"keyboard", L"vol_up", VK_PRIOR, filename);
|
||||
|
||||
cfg->vk_terminal_decide = GetPrivateProfileIntW(L"keyboard", L"decide", 'A', filename);
|
||||
cfg->vk_terminal_cancel = GetPrivateProfileIntW(L"keyboard", L"cancel", 'S', filename);
|
||||
cfg->vk_terminal_up = GetPrivateProfileIntW(L"keyboard", L"up", VK_UP, filename);
|
||||
cfg->vk_terminal_right = GetPrivateProfileIntW(L"keyboard", L"right", VK_RIGHT, filename);
|
||||
cfg->vk_terminal_down = GetPrivateProfileIntW(L"keyboard", L"down", VK_DOWN, filename);
|
||||
cfg->vk_terminal_left = GetPrivateProfileIntW(L"keyboard", L"left", VK_LEFT, filename);
|
||||
cfg->vk_terminal_left_2 = GetPrivateProfileIntW(L"keyboard", L"left2", 'Q', filename);
|
||||
cfg->vk_terminal_right_2 = GetPrivateProfileIntW(L"keyboard", L"right2", 'W', filename);
|
||||
|
||||
cfg->x_down = GetPrivateProfileIntW(L"keyboard", L"trackball_left", VK_LEFT, filename);
|
||||
cfg->x_up = GetPrivateProfileIntW(L"keyboard", L"trackball_right", VK_RIGHT, filename);
|
||||
cfg->y_down = GetPrivateProfileIntW(L"keyboard", L"trackball_up", VK_UP, filename);
|
||||
cfg->y_up = GetPrivateProfileIntW(L"keyboard", L"trackball_down", VK_DOWN, filename);
|
||||
cfg->speed = GetPrivateProfileIntW(L"keyboard", L"speed_modifier", 1, filename);
|
||||
}
|
||||
|
||||
void ekt_io_config_load(
|
||||
struct ekt_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||
cfg->vk_sw1 = GetPrivateProfileIntW(L"io4", L"sw1", '4', filename);
|
||||
cfg->vk_sw2 = GetPrivateProfileIntW(L"io4", L"sw2", '5', filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"io4",
|
||||
L"mode",
|
||||
L"keyboard",
|
||||
cfg->mode,
|
||||
_countof(cfg->mode),
|
||||
filename);
|
||||
|
||||
ekt_kb_config_load(&cfg->kb, filename);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct ekt_kb_config {
|
||||
uint8_t vk_menu;
|
||||
uint8_t vk_start;
|
||||
uint8_t vk_stratagem;
|
||||
uint8_t vk_stratagem_lock;
|
||||
uint8_t vk_hougu;
|
||||
uint8_t vk_ryuuha;
|
||||
|
||||
uint8_t vk_tenkey_0;
|
||||
uint8_t vk_tenkey_1;
|
||||
uint8_t vk_tenkey_2;
|
||||
uint8_t vk_tenkey_3;
|
||||
uint8_t vk_tenkey_4;
|
||||
uint8_t vk_tenkey_5;
|
||||
uint8_t vk_tenkey_6;
|
||||
uint8_t vk_tenkey_7;
|
||||
uint8_t vk_tenkey_8;
|
||||
uint8_t vk_tenkey_9;
|
||||
uint8_t vk_tenkey_clear;
|
||||
uint8_t vk_tenkey_enter;
|
||||
|
||||
uint8_t vk_vol_down;
|
||||
uint8_t vk_vol_up;
|
||||
|
||||
uint8_t vk_terminal_up;
|
||||
uint8_t vk_terminal_right;
|
||||
uint8_t vk_terminal_down;
|
||||
uint8_t vk_terminal_left;
|
||||
uint8_t vk_terminal_left_2;
|
||||
uint8_t vk_terminal_right_2;
|
||||
uint8_t vk_terminal_cancel;
|
||||
uint8_t vk_terminal_decide;
|
||||
|
||||
uint8_t x_down;
|
||||
uint8_t x_up;
|
||||
uint8_t y_down;
|
||||
uint8_t y_up;
|
||||
uint8_t speed;
|
||||
};
|
||||
|
||||
struct ekt_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
uint8_t vk_sw1;
|
||||
uint8_t vk_sw2;
|
||||
|
||||
wchar_t mode[12];
|
||||
struct ekt_kb_config kb;
|
||||
};
|
||||
|
||||
void ekt_kb_config_load(struct ekt_kb_config *cfg, const wchar_t *filename);
|
||||
void ekt_io_config_load(
|
||||
struct ekt_io_config *cfg,
|
||||
const wchar_t *filename);
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ektio/ektio.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "ektio/config.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static uint8_t ekt_opbtn;
|
||||
static uint32_t ekt_gamebtn;
|
||||
static uint8_t ekt_stick_x;
|
||||
static uint8_t ekt_stick_y;
|
||||
static struct ekt_io_config ekt_io_cfg;
|
||||
static const struct ekt_io_backend* ekt_io_backend;
|
||||
static bool ekt_io_coin;
|
||||
|
||||
uint16_t ekt_io_get_api_version(void) {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT ekt_io_init(void) {
|
||||
ekt_io_config_load(&ekt_io_cfg, get_config_path());
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if (wstr_ieq(ekt_io_cfg.mode, L"keyboard")) {
|
||||
hr = ekt_kb_init(&ekt_io_cfg.kb, &ekt_io_backend);
|
||||
} else {
|
||||
hr = E_INVALIDARG;
|
||||
dprintf("EKT IO: Invalid IO mode \"%S\", use keyboard\n",
|
||||
ekt_io_cfg.mode);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT ekt_io_poll(void) {
|
||||
assert(ekt_io_backend != NULL);
|
||||
|
||||
ekt_opbtn = 0;
|
||||
ekt_gamebtn = 0;
|
||||
ekt_stick_x = 0;
|
||||
ekt_stick_y = 0;
|
||||
|
||||
if (GetAsyncKeyState(ekt_io_cfg.vk_test) & 0x8000) {
|
||||
ekt_opbtn |= EKT_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(ekt_io_cfg.vk_service) & 0x8000) {
|
||||
ekt_opbtn |= EKT_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(ekt_io_cfg.vk_sw1) & 0x8000) {
|
||||
ekt_opbtn |= EKT_IO_OPBTN_SW1;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(ekt_io_cfg.vk_sw2) & 0x8000) {
|
||||
ekt_opbtn |= EKT_IO_OPBTN_SW2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(ekt_io_cfg.vk_coin) & 0x8000) {
|
||||
if (!ekt_io_coin) {
|
||||
ekt_io_coin = true;
|
||||
ekt_opbtn |= EKT_IO_OPBTN_COIN;
|
||||
}
|
||||
} else {
|
||||
ekt_io_coin = false;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void ekt_io_get_opbtns(uint8_t* opbtn) {
|
||||
if (opbtn != NULL) {
|
||||
*opbtn = ekt_opbtn;
|
||||
}
|
||||
}
|
||||
|
||||
void ekt_io_get_gamebtns(uint32_t* btn) {
|
||||
assert(ekt_io_backend != NULL);
|
||||
assert(btn != NULL);
|
||||
|
||||
ekt_io_backend->get_gamebtns(btn);
|
||||
}
|
||||
|
||||
void ekt_io_get_trackball_position(uint16_t* stick_x, uint16_t* stick_y) {
|
||||
assert(ekt_io_backend != NULL);
|
||||
assert(stick_x != NULL);
|
||||
assert(stick_y != NULL);
|
||||
|
||||
ekt_io_backend->get_trackball(stick_x, stick_y);
|
||||
}
|
||||
|
||||
HRESULT ekt_io_led_init(void) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void ekt_io_led_set_colors(uint8_t board, uint8_t* rgb) {
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
EKT_IO_OPBTN_TEST = 0x01,
|
||||
EKT_IO_OPBTN_SERVICE = 0x02,
|
||||
EKT_IO_OPBTN_COIN = 0x04,
|
||||
EKT_IO_OPBTN_SW1 = 0x08,
|
||||
EKT_IO_OPBTN_SW2 = 0x10,
|
||||
};
|
||||
|
||||
enum {
|
||||
EKT_IO_GAMEBTN_MENU = 0x01,
|
||||
EKT_IO_GAMEBTN_START = 0x02,
|
||||
EKT_IO_GAMEBTN_STRATAGEM = 0x04,
|
||||
EKT_IO_GAMEBTN_STRATAGEM_LOCK = 0x08,
|
||||
EKT_IO_GAMEBTN_HOUGU = 0x10,
|
||||
EKT_IO_GAMEBTN_RYUUHA = 0x20,
|
||||
EKT_IO_GAMEBTN_NUMPAD_0 = 0x100,
|
||||
EKT_IO_GAMEBTN_NUMPAD_1 = 0x200,
|
||||
EKT_IO_GAMEBTN_NUMPAD_2 = 0x400,
|
||||
EKT_IO_GAMEBTN_NUMPAD_3 = 0x800,
|
||||
EKT_IO_GAMEBTN_NUMPAD_4 = 0x1000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_5 = 0x2000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_6 = 0x4000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_7 = 0x8000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_8 = 0x10000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_9 = 0x20000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_CLEAR = 0x40000,
|
||||
EKT_IO_GAMEBTN_NUMPAD_ENTER = 0x80000,
|
||||
EKT_IO_GAMEBTN_VOL_UP = 0x100000,
|
||||
EKT_IO_GAMEBTN_VOL_DOWN = 0x200000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_LEFT = 0x400000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_UP = 0x800000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_RIGHT = 0x1000000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_DOWN = 0x2000000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_LEFT_2 = 0x4000000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_RIGHT_2 = 0x8000000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_DECIDE = 0x10000000,
|
||||
EKT_IO_GAMEBTN_TERMINAL_CANCEL = 0x20000000,
|
||||
};
|
||||
|
||||
/* Get the version of the Eiketsu Taisen 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 ekt_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after ekt_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT ekt_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 ekt_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
EKT_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *opbtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void ekt_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
EKT_IO_GAMEBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *gamebtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void ekt_io_get_gamebtns(uint32_t *gamebtn);
|
||||
|
||||
/* Get the position of the trackball as of the last poll.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void ekt_io_get_trackball_position(uint16_t *stick_x, uint16_t *stick_y);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other ekt_io_led_*() function calls.
|
||||
|
||||
All subsequent calls may originate from arbitrary threads and some may
|
||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||
your responsibility. */
|
||||
|
||||
HRESULT ekt_io_led_init(void);
|
||||
|
||||
/* Update the RGB LEDs.
|
||||
|
||||
Exact layout is TBD. */
|
||||
|
||||
void ekt_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||
@@ -0,0 +1,176 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ektio/backend.h"
|
||||
#include "ektio/config.h"
|
||||
#include "ektio/ektio.h"
|
||||
#include "ektio/keyboard.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void ekt_kb_get_gamebtns(uint32_t* gamebtn_out);
|
||||
static void ekt_kb_get_trackball(uint16_t* x, uint16_t* y);
|
||||
|
||||
static const struct ekt_io_backend ekt_kb_backend = {
|
||||
.get_gamebtns = ekt_kb_get_gamebtns,
|
||||
.get_trackball = ekt_kb_get_trackball
|
||||
};
|
||||
|
||||
static uint16_t current_x;
|
||||
static uint16_t current_y;
|
||||
|
||||
static struct ekt_kb_config config;
|
||||
|
||||
HRESULT ekt_kb_init(const struct ekt_kb_config* cfg, const struct ekt_io_backend** backend) {
|
||||
assert(cfg != NULL);
|
||||
assert(backend != NULL);
|
||||
|
||||
dprintf("Keyboard: Using keyboard input\n");
|
||||
*backend = &ekt_kb_backend;
|
||||
config = *cfg;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void ekt_kb_get_gamebtns(uint32_t* gamebtn_out) {
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
uint32_t gamebtn = 0;
|
||||
|
||||
if (GetAsyncKeyState(config.vk_hougu) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_HOUGU;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_menu) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_MENU;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_start) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_START;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_stratagem) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_STRATAGEM;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_stratagem_lock) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_STRATAGEM_LOCK;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_ryuuha) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_RYUUHA;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_0) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_0;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_1) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_1;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_2) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_3) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_3;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_4) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_4;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_5) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_5;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_6) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_6;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_7) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_7;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_8) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_8;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_9) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_9;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_clear) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_CLEAR;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_enter) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_NUMPAD_ENTER;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_vol_down) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_VOL_DOWN;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_vol_up) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_VOL_UP;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_cancel) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_CANCEL;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_decide) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_DECIDE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_up) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_UP;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_right) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_RIGHT;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_down) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_DOWN;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_left) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_LEFT;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_left_2) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_LEFT_2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_right_2) & 0x8000) {
|
||||
gamebtn |= EKT_IO_GAMEBTN_TERMINAL_RIGHT_2;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void ekt_kb_get_trackball(uint16_t* x, uint16_t* y) {
|
||||
assert(x != NULL);
|
||||
assert(y != NULL);
|
||||
|
||||
if (GetAsyncKeyState(config.x_down) & 0x8000) {
|
||||
current_x -= config.speed;
|
||||
} else if (GetAsyncKeyState(config.x_up) & 0x8000) {
|
||||
current_x += config.speed;
|
||||
}
|
||||
if (GetAsyncKeyState(config.y_down) & 0x8000) {
|
||||
current_y += config.speed;
|
||||
} else if (GetAsyncKeyState(config.y_up) & 0x8000) {
|
||||
current_y -= config.speed;
|
||||
}
|
||||
|
||||
*x = current_x;
|
||||
*y = current_y;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "ektio/backend.h"
|
||||
#include "ektio/config.h"
|
||||
|
||||
HRESULT ekt_kb_init(const struct ekt_kb_config *cfg, const struct ekt_io_backend **backend);
|
||||
@@ -0,0 +1,18 @@
|
||||
ektio_lib = static_library(
|
||||
'ektio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
dependencies : [
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'ektio.c',
|
||||
'ektio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'backend.h',
|
||||
'keyboard.c',
|
||||
'keyboard.h',
|
||||
],
|
||||
)
|
||||
@@ -120,7 +120,7 @@ void fgo_hook_config_load(
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
touch_screen_config_load(&cfg->touch, filename);
|
||||
printer_config_load(&cfg->printer, filename);
|
||||
printer_chc_config_load(&cfg->printer, filename);
|
||||
fgo_deck_config_load(&cfg->deck, filename);
|
||||
ftdi_config_load(&cfg->ftdi, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
@@ -24,7 +24,7 @@ struct fgo_hook_config {
|
||||
struct io4_config io4;
|
||||
struct vfd_config vfd;
|
||||
struct touch_screen_config touch;
|
||||
struct printer_config printer;
|
||||
struct printer_chc_config printer;
|
||||
struct deck_config deck;
|
||||
struct ftdi_config ftdi;
|
||||
struct led15093_config led15093;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/createprocess.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
@@ -81,7 +81,7 @@ static DWORD CALLBACK fgo_pre_startup(void)
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod);
|
||||
printer_chc_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod);
|
||||
if (fgo_hook_cfg.printer.enable) {
|
||||
dll_hook_push(fgo_hook_mod, L"C330Ausb.dll");
|
||||
dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll");
|
||||
@@ -143,7 +143,7 @@ static DWORD CALLBACK fgo_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = createprocess_push_hook_a("am/amdaemon.exe", "inject -d -k fgohook.dll ", "", false);
|
||||
hr = createprocess_push_hook_a("am/amdaemon.exe", "inject -d -k fgohook.dll ", "", false, false);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
|
||||
@@ -56,7 +56,7 @@ EXPORTS
|
||||
chcusb_selectPrinter
|
||||
chcusb_selectPrinterSN
|
||||
chcusb_getPrinterInfo
|
||||
chcusb_imageformat=chcusb_imageformat_330
|
||||
chcusb_imageformat
|
||||
chcusb_setmtf
|
||||
chcusb_makeGamma
|
||||
chcusb_setIcctable
|
||||
|
||||
@@ -126,7 +126,7 @@ void kemono_hook_config_load(
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
kemono_dll_config_load(&cfg->dll, filename);
|
||||
unity_config_load(&cfg->unity, filename);
|
||||
printer_config_load(&cfg->printer, filename);
|
||||
printer_chc_config_load(&cfg->printer, filename);
|
||||
amex_config_load(&cfg->amex, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct kemono_hook_config {
|
||||
struct vfd_config vfd;
|
||||
struct kemono_dll_config dll;
|
||||
struct unity_config unity;
|
||||
struct printer_config printer;
|
||||
struct printer_chc_config printer;
|
||||
struct amex_config amex;
|
||||
struct led15093_config led15093;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "hook/iohook.h"
|
||||
#include "hook/process.h"
|
||||
#include "hook/table.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
#include "kemonohook/config.h"
|
||||
@@ -66,7 +66,7 @@ static DWORD CALLBACK kemono_pre_startup(void) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod);
|
||||
printer_chc_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod);
|
||||
printer_set_dimensions(720, 1028); // printer doesn't call setimageformat
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "amex/config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
#include "sekitohook/config.h"
|
||||
#include "sekitohook/sekito-dll.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
|
||||
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
|
||||
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
|
||||
cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
|
||||
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
|
||||
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
|
||||
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"boardNumber",
|
||||
L"15093-06",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
|
||||
for (int i = n; i < sizeof(cfg->board_number); i++)
|
||||
{
|
||||
cfg->board_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"chipNumber",
|
||||
L"6710A",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
|
||||
for (int i = n; i < sizeof(cfg->chip_number); i++)
|
||||
{
|
||||
cfg->chip_number[i] = ' ';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led15093",
|
||||
L"bootChipNumber",
|
||||
L"6709 ",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
|
||||
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
|
||||
{
|
||||
cfg->boot_chip_number[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void sekito_dll_config_load(
|
||||
struct sekito_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"sekitoio",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
|
||||
void sekito_hook_config_load(
|
||||
struct sekito_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);
|
||||
aime_config_load_bykey(&cfg->aime_queue, filename, L"aime2");
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
led15093_config_load(&cfg->led15093, filename);
|
||||
y3_config_load(&cfg->y3, filename);
|
||||
printer_chc_config_load(&cfg->printer, filename);
|
||||
sekito_dll_config_load(&cfg->dll, filename);
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
amex_config_load(&cfg->amex, filename);
|
||||
amvideo_config_load(&cfg->amvideo, filename);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "amex/amex.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/config.h"
|
||||
#include "board/led15093.h"
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "sekitohook/sekito-dll.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
|
||||
struct sekito_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct aime_config aime_queue;
|
||||
struct io4_config io4;
|
||||
struct dvd_config dvd;
|
||||
struct led15093_config led15093;
|
||||
struct y3_config y3;
|
||||
struct sekito_dll_config dll;
|
||||
struct printer_chc_config printer;
|
||||
struct gfx_config gfx;
|
||||
struct amex_config amex;
|
||||
struct amvideo_config amvideo;
|
||||
};
|
||||
|
||||
void sekito_dll_config_load(
|
||||
struct sekito_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void sekito_hook_config_load(
|
||||
struct sekito_hook_config *cfg,
|
||||
const wchar_t *filename);
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
"Sangokushi Taisen" (sekito) hook
|
||||
|
||||
Devices
|
||||
|
||||
USB: 837-14572 "Type 3" I/O Board
|
||||
COM12: 837-15084 "Gen 2" Aime Reader
|
||||
|
||||
[Satellite]
|
||||
|
||||
USB: Sinfonia CHC-C320 Printer
|
||||
COM1: 837-15093-06 LED Controller Board
|
||||
COM10: 601-13160-01 "Flat Panel Reader" Y3CR BD SIE F720MM Board
|
||||
COM11: Printer Camera
|
||||
|
||||
[Terminal]
|
||||
|
||||
COM1: 837-15084 "Gen 2" Aime Reader
|
||||
COM11: 837-15093-06 LED Controller Board
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "amex/amex.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/led15093.h"
|
||||
#include "board/sg-reader-queue.h"
|
||||
|
||||
#include "gfxhook/d3d9.h"
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
#include "sekitohook/config.h"
|
||||
#include "sekitohook/jvs.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "util/fg-detect.h"
|
||||
|
||||
static HMODULE sekito_hook_mod;
|
||||
static process_entry_t sekito_startup;
|
||||
static struct sekito_hook_config sekito_hook_cfg;
|
||||
|
||||
static DWORD CALLBACK sekito_pre_startup(void)
|
||||
{
|
||||
HMODULE dbghelp;
|
||||
HRESULT hr;
|
||||
bool is_terminal;
|
||||
|
||||
dprintf("--- Begin sekito_pre_startup ---\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");
|
||||
}
|
||||
|
||||
/* Load config */
|
||||
|
||||
sekito_hook_config_load(&sekito_hook_cfg, get_config_path());
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&sekito_hook_cfg.dvd, sekito_hook_mod);
|
||||
gfx_hook_init(&sekito_hook_cfg.gfx);
|
||||
gfx_d3d9_hook_init(&sekito_hook_cfg.gfx, sekito_hook_mod);
|
||||
serial_hook_init();
|
||||
sekito_io_init();
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
hr = y3_hook_init(&sekito_hook_cfg.y3, sekito_hook_mod, get_config_path());
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printer_chc_hook_init(&sekito_hook_cfg.printer, 0, sekito_hook_mod);
|
||||
if (sekito_hook_cfg.printer.enable) {
|
||||
dll_hook_push(sekito_hook_mod, L"C320Ausb.dll");
|
||||
dll_hook_push(sekito_hook_mod, L"C320AFWDLusb.dll");
|
||||
}
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&sekito_hook_cfg.platform,
|
||||
"SDDD",
|
||||
"AAV2",
|
||||
sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize Terminal/Satellite hooks */
|
||||
if (strncmp(sekito_hook_cfg.platform.nusec.platform_id, "AAV1", 4) == 0) {
|
||||
// Terminal
|
||||
is_terminal = true;
|
||||
} else if (strncmp(sekito_hook_cfg.platform.nusec.platform_id, "AAV2", 4) == 0) {
|
||||
// Satellite
|
||||
is_terminal = false;
|
||||
} else {
|
||||
// Unknown
|
||||
dprintf("Unknown platform ID: %s\n", sekito_hook_cfg.platform.nusec.platform_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dprintf("System: Cabinet Type: %s\n", is_terminal ? "Terminal" : "Satellite");
|
||||
|
||||
// LED: terminal uses COM 11 and satellite use COM 1
|
||||
unsigned int led_port_no[2] = {is_terminal ? 11 : 1, 0};
|
||||
|
||||
hr = sekito_dll_init(&sekito_hook_cfg.dll, sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = led15093_hook_init(&sekito_hook_cfg.led15093,
|
||||
sekito_dll.led_init, sekito_dll.led_set_leds, led_port_no);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (is_terminal) {
|
||||
hr = sg_reader_queue_hook_init(&sekito_hook_cfg.aime_queue, 12, 2,
|
||||
sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&sekito_hook_cfg.aime, 1, 2,
|
||||
sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
hr = sg_reader_hook_init(&sekito_hook_cfg.aime, 12, 2,
|
||||
sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
sekito_jvs_set_terminal(is_terminal);
|
||||
hr = amex_hook_init(&sekito_hook_cfg.amex, sekito_jvs_init);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sekito_hook_cfg.amex.jvs.enable && sekito_hook_cfg.amex.jvs.foreground) {
|
||||
fgdet_init(L"teaGfx DirectX Release", false);
|
||||
}
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(get_config_path());
|
||||
|
||||
dprintf("--- End sekito_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return sekito_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
sekito_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(sekito_pre_startup, &sekito_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
#include "jvs.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "amex/jvs.h"
|
||||
|
||||
#include "board/io3.h"
|
||||
|
||||
#include "sekitohook/config.h"
|
||||
|
||||
#include "jvs/jvs-bus.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void sekito_jvs_read_switches(void* ctx, struct io3_switch_state* out);
|
||||
|
||||
static void sekito_jvs_read_coin_counter(
|
||||
void* ctx,
|
||||
uint8_t slot_no,
|
||||
uint16_t* out);
|
||||
|
||||
static void sekito_jvs_read_rotary(
|
||||
void* ctx,
|
||||
uint16_t* rotary,
|
||||
uint8_t nrotary);
|
||||
|
||||
static const struct io3_ops sekito_jvs_io3_ops = {
|
||||
.read_switches = sekito_jvs_read_switches,
|
||||
.read_rotarys = sekito_jvs_read_rotary,
|
||||
.read_coin_counter = sekito_jvs_read_coin_counter,
|
||||
};
|
||||
|
||||
static struct io3 sekito_jvs_io3;
|
||||
|
||||
static bool io_is_terminal;
|
||||
|
||||
HRESULT sekito_jvs_init(struct jvs_node** out) {
|
||||
assert(out != NULL);
|
||||
|
||||
dprintf("JVS I/O: Starting JVS\n");
|
||||
|
||||
io3_init(&sekito_jvs_io3, NULL, &sekito_jvs_io3_ops, NULL);
|
||||
*out = io3_to_jvs_node(&sekito_jvs_io3);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void sekito_jvs_set_terminal(bool is_terminal) {
|
||||
dprintf("JVS I/O: Terminal: %d\n", is_terminal);
|
||||
io_is_terminal = is_terminal;
|
||||
}
|
||||
|
||||
static void sekito_jvs_read_switches(void* ctx, struct io3_switch_state* out) {
|
||||
assert(out != NULL);
|
||||
|
||||
uint8_t opbtn;
|
||||
uint32_t gamebtn;
|
||||
|
||||
assert(sekito_dll.poll != NULL);
|
||||
assert(sekito_dll.get_opbtns != NULL);
|
||||
assert(sekito_dll.get_gamebtns != NULL);
|
||||
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
sekito_dll.poll();
|
||||
|
||||
opbtn = 0;
|
||||
gamebtn = 0;
|
||||
|
||||
sekito_dll.get_opbtns(&opbtn);
|
||||
sekito_dll.get_gamebtns(&gamebtn);
|
||||
|
||||
if (opbtn & SEKITO_IO_OPBTN_TEST) {
|
||||
out->system = 0x80;
|
||||
} else {
|
||||
out->system = 0;
|
||||
}
|
||||
|
||||
if (opbtn & SEKITO_IO_OPBTN_SERVICE) {
|
||||
out->p1 |= 1 << 1;
|
||||
}
|
||||
|
||||
if (opbtn & SEKITO_IO_OPBTN_SW1) {
|
||||
out->p1 |= 1 << 10;
|
||||
}
|
||||
|
||||
if (opbtn & SEKITO_IO_OPBTN_SW2) {
|
||||
out->p1 |= 1 << 11;
|
||||
}
|
||||
|
||||
if (opbtn & SEKITO_IO_OPBTN_COIN) {
|
||||
out->p1 |= 1 << 14;
|
||||
}
|
||||
|
||||
|
||||
if (!io_is_terminal) {
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_HOUGU) {
|
||||
out->p2 |= 1 << 6;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_MENU) {
|
||||
out->p2 |= 1 << 4;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_START) {
|
||||
out->p1 |= 1 << 15;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_STRATAGEM) {
|
||||
out->p2 |= 1 << 7;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_STRATAGEM_LOCK) {
|
||||
out->p2 |= 1 << 5;
|
||||
}
|
||||
|
||||
out->p1 |= 0 << 2; // card_sensor
|
||||
out->p2 |= 1 << 2; // open_sensor
|
||||
out->p2 |= 1 << 3; // lock
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_0) {
|
||||
out->p1 |= SEKITO_NUMPAD_C2;
|
||||
out->p1 |= SEKITO_NUMPAD_R4;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_1) {
|
||||
out->p1 |= SEKITO_NUMPAD_C1;
|
||||
out->p1 |= SEKITO_NUMPAD_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_2) {
|
||||
out->p1 |= SEKITO_NUMPAD_C2;
|
||||
out->p1 |= SEKITO_NUMPAD_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_3) {
|
||||
out->p1 |= SEKITO_NUMPAD_C3;
|
||||
out->p1 |= SEKITO_NUMPAD_R1;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_4) {
|
||||
out->p1 |= SEKITO_NUMPAD_C1;
|
||||
out->p1 |= SEKITO_NUMPAD_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_5) {
|
||||
out->p1 |= SEKITO_NUMPAD_C2;
|
||||
out->p1 |= SEKITO_NUMPAD_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_6) {
|
||||
out->p1 |= SEKITO_NUMPAD_C3;
|
||||
out->p1 |= SEKITO_NUMPAD_R2;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_7) {
|
||||
out->p1 |= SEKITO_NUMPAD_C1;
|
||||
out->p1 |= SEKITO_NUMPAD_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_8) {
|
||||
out->p1 |= SEKITO_NUMPAD_C2;
|
||||
out->p1 |= SEKITO_NUMPAD_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_9) {
|
||||
out->p1 |= SEKITO_NUMPAD_C3;
|
||||
out->p1 |= SEKITO_NUMPAD_R3;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_CLEAR) {
|
||||
out->p1 |= SEKITO_NUMPAD_C1;
|
||||
out->p1 |= SEKITO_NUMPAD_R4;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_NUMPAD_ENTER) {
|
||||
out->p1 |= SEKITO_NUMPAD_C3;
|
||||
out->p1 |= SEKITO_NUMPAD_R4;
|
||||
}
|
||||
|
||||
if (io_is_terminal) {
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_CANCEL) {
|
||||
out->p2 |= 1 << 8;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_DECIDE) {
|
||||
out->p2 |= 1 << 9;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_LEFT) {
|
||||
out->p1 |= 1 << 11;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_UP) {
|
||||
out->p1 |= 1 << 13;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_RIGHT) {
|
||||
out->p1 |= 1 << 10;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_DOWN) {
|
||||
out->p1 |= 1 << 12;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_LEFT_2) {
|
||||
out->p2 |= 1 << 11;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_RIGHT_2) {
|
||||
out->p2 |= 1 << 10;
|
||||
}
|
||||
|
||||
if (gamebtn & SEKITO_IO_GAMEBTN_TERMINAL_RESERVE) {
|
||||
out->p2 |= 1 << 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void sekito_jvs_read_rotary(
|
||||
void* ctx,
|
||||
uint16_t* rotary,
|
||||
uint8_t nrotary) {
|
||||
assert(rotary != NULL);
|
||||
assert(sekito_dll.get_trackball_position != NULL);
|
||||
|
||||
uint16_t x, y;
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
sekito_dll.get_trackball_position(&x, &y);
|
||||
|
||||
if (nrotary >= 4) {
|
||||
rotary[2] = x;
|
||||
rotary[3] = y;
|
||||
}
|
||||
}
|
||||
|
||||
static void sekito_jvs_read_coin_counter(
|
||||
void* ctx,
|
||||
uint8_t slot_no,
|
||||
uint16_t* out) {
|
||||
if (slot_no > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unused(!)
|
||||
*out = 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "jvs/jvs-bus.h"
|
||||
|
||||
enum {
|
||||
SEKITO_NUMPAD_R1 = 1 << 9,
|
||||
SEKITO_NUMPAD_R2 = 1 << 8,
|
||||
SEKITO_NUMPAD_R3 = 1 << 7,
|
||||
SEKITO_NUMPAD_R4 = 1 << 6,
|
||||
SEKITO_NUMPAD_C1 = 1 << 5,
|
||||
SEKITO_NUMPAD_C2 = 1 << 4,
|
||||
SEKITO_NUMPAD_C3 = 1 << 3
|
||||
};
|
||||
|
||||
HRESULT sekito_jvs_init(struct jvs_node **root);
|
||||
void sekito_jvs_set_terminal(bool is_terminal);
|
||||
@@ -0,0 +1,32 @@
|
||||
shared_library(
|
||||
'sekitohook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'sekitohook.def',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep')
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
amex_lib,
|
||||
board_lib,
|
||||
hooklib_lib,
|
||||
gfxhook_lib,
|
||||
jvs_lib,
|
||||
platform_lib,
|
||||
sekitoio_lib,
|
||||
util_lib,
|
||||
y3io_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'jvs.c',
|
||||
'jvs.h',
|
||||
'sekito-dll.c',
|
||||
'sekito-dll.h',
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sekitohook/sekito-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym sekito_dll_syms[] = {
|
||||
{
|
||||
.sym = "sekito_io_init",
|
||||
.off = offsetof(struct sekito_dll, init),
|
||||
}, {
|
||||
.sym = "sekito_io_poll",
|
||||
.off = offsetof(struct sekito_dll, poll),
|
||||
}, {
|
||||
.sym = "sekito_io_get_opbtns",
|
||||
.off = offsetof(struct sekito_dll, get_opbtns),
|
||||
}, {
|
||||
.sym = "sekito_io_get_gamebtns",
|
||||
.off = offsetof(struct sekito_dll, get_gamebtns),
|
||||
}, {
|
||||
.sym = "sekito_io_get_trackball_position",
|
||||
.off = offsetof(struct sekito_dll, get_trackball_position),
|
||||
}, {
|
||||
.sym = "sekito_io_led_init",
|
||||
.off = offsetof(struct sekito_dll, led_init),
|
||||
}, {
|
||||
.sym = "sekito_io_led_set_colors",
|
||||
.off = offsetof(struct sekito_dll, led_set_leds),
|
||||
}
|
||||
};
|
||||
|
||||
struct sekito_dll sekito_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 sekito_dll_init(const struct sekito_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("Sekito IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Sekito IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "sekito_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
sekito_dll.api_version = get_api_version();
|
||||
} else {
|
||||
sekito_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose sekito_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (sekito_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Sekito IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
sekito_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = sekito_dll_syms;
|
||||
hr = dll_bind(&sekito_dll, src, &sym, _countof(sekito_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Sekito 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;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "sekitoio/sekitoio.h"
|
||||
|
||||
struct sekito_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(void);
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
void (*get_gamebtns)(uint32_t *gamebtn);
|
||||
void (*get_trackball_position)(uint16_t *x, uint16_t *y);
|
||||
HRESULT (*led_init)(void);
|
||||
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||
};
|
||||
|
||||
struct sekito_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct sekito_dll sekito_dll;
|
||||
|
||||
HRESULT sekito_dll_init(const struct sekito_dll_config *cfg, HINSTANCE self);
|
||||
@@ -0,0 +1,78 @@
|
||||
LIBRARY sekitohook
|
||||
|
||||
EXPORTS
|
||||
Direct3DCreate9
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_vfd_set_text
|
||||
aime_io_vfd_set_state
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
aime_io_nfc_get_mifare_uid
|
||||
aime_io_nfc_mifare_select
|
||||
aime_io_nfc_mifare_set_key
|
||||
aime_io_nfc_mifare_authenticate
|
||||
aime_io_nfc_mifare_read_block
|
||||
aime_io_nfc_felica_transact
|
||||
aime_io_nfc_radio_on
|
||||
aime_io_nfc_radio_off
|
||||
aime_io_nfc_to_update_mode
|
||||
aime_io_nfc_send_hex_data
|
||||
sekito_io_get_api_version
|
||||
sekito_io_get_gamebtns
|
||||
sekito_io_get_opbtns
|
||||
sekito_io_get_trackball_position
|
||||
sekito_io_init
|
||||
sekito_io_poll
|
||||
sekito_io_led_init
|
||||
sekito_io_led_set_colors
|
||||
y3_io_get_api_version
|
||||
y3_io_init
|
||||
y3_io_close
|
||||
y3_io_get_cards
|
||||
amDllVideoClose
|
||||
amDllVideoGetVBiosVersion
|
||||
amDllVideoOpen
|
||||
amDllVideoSetResolution
|
||||
API_DLLVersion @1
|
||||
API_GetLastError @2
|
||||
API_GetErrorMessage @3
|
||||
API_Connect @4
|
||||
API_Close @5
|
||||
API_Start @6
|
||||
API_Stop @7
|
||||
API_GetFirmVersion @8
|
||||
API_GetFirmName @9
|
||||
API_GetTargetCode @10
|
||||
API_GetStatus @11
|
||||
API_GetCounter @12
|
||||
API_ClearError @13
|
||||
API_Reset @14
|
||||
API_GetCardInfo @15
|
||||
API_GetCardInfoCharSize @16
|
||||
API_SetDevice @17
|
||||
API_SetCommand @18
|
||||
API_FirmwareUpdate @19
|
||||
API_Calibration @20
|
||||
API_GetCalibrationResult @21
|
||||
API_GetProcTime @22
|
||||
API_GetMemStatus @23
|
||||
API_GetMemCounter @24
|
||||
API_SetSysControl @25
|
||||
API_GetSysControl @26
|
||||
API_SetParameter @27
|
||||
API_GetParameter @28
|
||||
API_TestReset @29
|
||||
API_DebugReset @30
|
||||
API_GetBoardType @31
|
||||
API_GetCardDataSize @32
|
||||
API_GetFirmDate @33
|
||||
API_SystemCommand @34
|
||||
API_CalcCheckSum @35
|
||||
API_GetCheckSumResult @36
|
||||
API_BlockRead @37
|
||||
API_GetBlockReadResult @38
|
||||
API_BlockWrite @39
|
||||
API_GetDebugParam @40
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sekitoio/sekitoio.h"
|
||||
|
||||
struct sekito_io_backend {
|
||||
void (*get_gamebtns)(uint32_t *gamebtn);
|
||||
void (*get_trackball)(uint16_t *x, uint16_t *y);
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sekitoio/config.h"
|
||||
|
||||
#include <xinput.h>
|
||||
|
||||
|
||||
void sekito_kb_config_load(
|
||||
struct sekito_kb_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
|
||||
cfg->vk_menu = GetPrivateProfileIntW(L"keyboard", L"menu", 'A', filename);
|
||||
cfg->vk_start = GetPrivateProfileIntW(L"keyboard", L"start", 'S', filename);
|
||||
cfg->vk_stratagem = GetPrivateProfileIntW(L"keyboard", L"stratagem", 'D', filename);
|
||||
cfg->vk_stratagem_lock = GetPrivateProfileIntW(L"keyboard", L"stratagem_lock", 'F', filename);
|
||||
cfg->vk_hougu = GetPrivateProfileIntW(L"keyboard", L"hougu", 'G', filename);
|
||||
|
||||
cfg->vk_tenkey_0 = GetPrivateProfileIntW(L"keyboard", L"tenkey_0", VK_NUMPAD0, filename);
|
||||
cfg->vk_tenkey_1 = GetPrivateProfileIntW(L"keyboard", L"tenkey_1", VK_NUMPAD1, filename);
|
||||
cfg->vk_tenkey_2 = GetPrivateProfileIntW(L"keyboard", L"tenkey_2", VK_NUMPAD2, filename);
|
||||
cfg->vk_tenkey_3 = GetPrivateProfileIntW(L"keyboard", L"tenkey_3", VK_NUMPAD3, filename);
|
||||
cfg->vk_tenkey_4 = GetPrivateProfileIntW(L"keyboard", L"tenkey_4", VK_NUMPAD4, filename);
|
||||
cfg->vk_tenkey_5 = GetPrivateProfileIntW(L"keyboard", L"tenkey_5", VK_NUMPAD5, filename);
|
||||
cfg->vk_tenkey_6 = GetPrivateProfileIntW(L"keyboard", L"tenkey_6", VK_NUMPAD6, filename);
|
||||
cfg->vk_tenkey_7 = GetPrivateProfileIntW(L"keyboard", L"tenkey_7", VK_NUMPAD7, filename);
|
||||
cfg->vk_tenkey_8 = GetPrivateProfileIntW(L"keyboard", L"tenkey_8", VK_NUMPAD8, filename);
|
||||
cfg->vk_tenkey_9 = GetPrivateProfileIntW(L"keyboard", L"tenkey_9", VK_NUMPAD9, filename);
|
||||
cfg->vk_tenkey_clear = GetPrivateProfileIntW(L"keyboard", L"tenkey_clear", VK_DECIMAL, filename);
|
||||
cfg->vk_tenkey_enter = GetPrivateProfileIntW(L"keyboard", L"tenkey_enter", VK_RETURN, filename);
|
||||
|
||||
cfg->vk_terminal_decide = GetPrivateProfileIntW(L"keyboard", L"decide", 'A', filename);
|
||||
cfg->vk_terminal_cancel = GetPrivateProfileIntW(L"keyboard", L"cancel", 'S', filename);
|
||||
cfg->vk_terminal_up = GetPrivateProfileIntW(L"keyboard", L"up", VK_UP, filename);
|
||||
cfg->vk_terminal_right = GetPrivateProfileIntW(L"keyboard", L"right", VK_RIGHT, filename);
|
||||
cfg->vk_terminal_down = GetPrivateProfileIntW(L"keyboard", L"down", VK_DOWN, filename);
|
||||
cfg->vk_terminal_left = GetPrivateProfileIntW(L"keyboard", L"left", VK_LEFT, filename);
|
||||
cfg->vk_terminal_left_2 = GetPrivateProfileIntW(L"keyboard", L"left2", 'Q', filename);
|
||||
cfg->vk_terminal_right_2 = GetPrivateProfileIntW(L"keyboard", L"right2", 'W', filename);
|
||||
cfg->vk_terminal_reserve = GetPrivateProfileIntW(L"keyboard", L"reserve", 'E', filename);
|
||||
|
||||
cfg->x_down = GetPrivateProfileIntW(L"keyboard", L"trackball_left", VK_LEFT, filename);
|
||||
cfg->x_up = GetPrivateProfileIntW(L"keyboard", L"trackball_right", VK_RIGHT, filename);
|
||||
cfg->y_down = GetPrivateProfileIntW(L"keyboard", L"trackball_up", VK_UP, filename);
|
||||
cfg->y_up = GetPrivateProfileIntW(L"keyboard", L"trackball_down", VK_DOWN, filename);
|
||||
cfg->speed = GetPrivateProfileIntW(L"keyboard", L"speed_modifier", 1, filename);
|
||||
}
|
||||
|
||||
void sekito_io_config_load(
|
||||
struct sekito_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||
cfg->vk_sw1 = GetPrivateProfileIntW(L"io4", L"sw1", '4', filename);
|
||||
cfg->vk_sw2 = GetPrivateProfileIntW(L"io4", L"sw2", '5', filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"io4",
|
||||
L"mode",
|
||||
L"keyboard",
|
||||
cfg->mode,
|
||||
_countof(cfg->mode),
|
||||
filename);
|
||||
|
||||
sekito_kb_config_load(&cfg->kb, filename);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct sekito_kb_config {
|
||||
uint8_t vk_menu;
|
||||
uint8_t vk_start;
|
||||
uint8_t vk_stratagem;
|
||||
uint8_t vk_stratagem_lock;
|
||||
uint8_t vk_hougu;
|
||||
|
||||
uint8_t vk_tenkey_0;
|
||||
uint8_t vk_tenkey_1;
|
||||
uint8_t vk_tenkey_2;
|
||||
uint8_t vk_tenkey_3;
|
||||
uint8_t vk_tenkey_4;
|
||||
uint8_t vk_tenkey_5;
|
||||
uint8_t vk_tenkey_6;
|
||||
uint8_t vk_tenkey_7;
|
||||
uint8_t vk_tenkey_8;
|
||||
uint8_t vk_tenkey_9;
|
||||
uint8_t vk_tenkey_clear;
|
||||
uint8_t vk_tenkey_enter;
|
||||
|
||||
uint8_t vk_terminal_up;
|
||||
uint8_t vk_terminal_right;
|
||||
uint8_t vk_terminal_down;
|
||||
uint8_t vk_terminal_left;
|
||||
uint8_t vk_terminal_left_2;
|
||||
uint8_t vk_terminal_right_2;
|
||||
uint8_t vk_terminal_reserve;
|
||||
uint8_t vk_terminal_cancel;
|
||||
uint8_t vk_terminal_decide;
|
||||
|
||||
uint8_t x_down;
|
||||
uint8_t x_up;
|
||||
uint8_t y_down;
|
||||
uint8_t y_up;
|
||||
uint8_t speed;
|
||||
};
|
||||
|
||||
struct sekito_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
uint8_t vk_sw1;
|
||||
uint8_t vk_sw2;
|
||||
|
||||
wchar_t mode[12];
|
||||
struct sekito_kb_config kb;
|
||||
};
|
||||
|
||||
void sekito_kb_config_load(struct sekito_kb_config *cfg, const wchar_t *filename);
|
||||
void sekito_io_config_load(
|
||||
struct sekito_io_config *cfg,
|
||||
const wchar_t *filename);
|
||||
@@ -0,0 +1,168 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "sekitoio/backend.h"
|
||||
#include "sekitoio/config.h"
|
||||
#include "sekitoio/sekitoio.h"
|
||||
#include "sekitoio/keyboard.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void sekito_kb_get_gamebtns(uint32_t* gamebtn_out);
|
||||
static void sekito_kb_get_trackball(uint16_t* x, uint16_t* y);
|
||||
|
||||
static const struct sekito_io_backend sekito_kb_backend = {
|
||||
.get_gamebtns = sekito_kb_get_gamebtns,
|
||||
.get_trackball = sekito_kb_get_trackball
|
||||
};
|
||||
|
||||
static uint16_t current_x;
|
||||
static uint16_t current_y;
|
||||
|
||||
static struct sekito_kb_config config;
|
||||
|
||||
HRESULT sekito_kb_init(const struct sekito_kb_config* cfg, const struct sekito_io_backend** backend) {
|
||||
assert(cfg != NULL);
|
||||
assert(backend != NULL);
|
||||
|
||||
dprintf("Keyboard: Using keyboard input\n");
|
||||
*backend = &sekito_kb_backend;
|
||||
config = *cfg;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void sekito_kb_get_gamebtns(uint32_t* gamebtn_out) {
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
uint32_t gamebtn = 0;
|
||||
|
||||
if (GetAsyncKeyState(config.vk_hougu) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_HOUGU;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_menu) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_MENU;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_start) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_START;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_stratagem) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_STRATAGEM;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_stratagem_lock) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_STRATAGEM_LOCK;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_0) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_0;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_1) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_1;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_2) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_3) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_3;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_4) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_4;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_5) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_5;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_6) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_6;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_7) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_7;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_8) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_8;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_9) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_9;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_clear) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_CLEAR;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_tenkey_enter) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_NUMPAD_ENTER;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_cancel) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_CANCEL;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_decide) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_DECIDE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_up) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_UP;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_right) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_RIGHT;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_down) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_DOWN;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_left) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_LEFT;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_left_2) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_LEFT_2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_right_2) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_RIGHT_2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_terminal_reserve) & 0x8000) {
|
||||
gamebtn |= SEKITO_IO_GAMEBTN_TERMINAL_RESERVE;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void sekito_kb_get_trackball(uint16_t* x, uint16_t* y) {
|
||||
assert(x != NULL);
|
||||
assert(y != NULL);
|
||||
|
||||
if (GetAsyncKeyState(config.x_down) & 0x8000) {
|
||||
current_x -= config.speed;
|
||||
} else if (GetAsyncKeyState(config.x_up) & 0x8000) {
|
||||
current_x += config.speed;
|
||||
}
|
||||
if (GetAsyncKeyState(config.y_down) & 0x8000) {
|
||||
current_y += config.speed;
|
||||
} else if (GetAsyncKeyState(config.y_up) & 0x8000) {
|
||||
current_y -= config.speed;
|
||||
}
|
||||
|
||||
*x = current_x;
|
||||
*y = current_y;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "sekitoio/backend.h"
|
||||
#include "sekitoio/config.h"
|
||||
|
||||
HRESULT sekito_kb_init(const struct sekito_kb_config *cfg, const struct sekito_io_backend **backend);
|
||||
@@ -0,0 +1,18 @@
|
||||
sekitoio_lib = static_library(
|
||||
'sekitoio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
dependencies : [
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
'backend.h',
|
||||
'keyboard.c',
|
||||
'keyboard.h',
|
||||
'sekitoio.c',
|
||||
'sekitoio.h',
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sekitoio/sekitoio.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "sekitoio/config.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static uint8_t sekito_opbtn;
|
||||
static uint32_t sekito_gamebtn;
|
||||
static uint8_t sekito_stick_x;
|
||||
static uint8_t sekito_stick_y;
|
||||
static struct sekito_io_config sekito_io_cfg;
|
||||
static const struct sekito_io_backend* sekito_io_backend;
|
||||
static bool sekito_io_coin;
|
||||
|
||||
uint16_t sekito_io_get_api_version(void) {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT sekito_io_init(void) {
|
||||
sekito_io_config_load(&sekito_io_cfg, get_config_path());
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if (wstr_ieq(sekito_io_cfg.mode, L"keyboard")) {
|
||||
hr = sekito_kb_init(&sekito_io_cfg.kb, &sekito_io_backend);
|
||||
} else {
|
||||
hr = E_INVALIDARG;
|
||||
dprintf("Sekito IO: Invalid IO mode \"%S\", use keyboard\n",
|
||||
sekito_io_cfg.mode);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT sekito_io_poll(void) {
|
||||
assert(sekito_io_backend != NULL);
|
||||
|
||||
sekito_opbtn = 0;
|
||||
sekito_gamebtn = 0;
|
||||
sekito_stick_x = 0;
|
||||
sekito_stick_y = 0;
|
||||
|
||||
if (GetAsyncKeyState(sekito_io_cfg.vk_test) & 0x8000) {
|
||||
sekito_opbtn |= SEKITO_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(sekito_io_cfg.vk_service) & 0x8000) {
|
||||
sekito_opbtn |= SEKITO_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(sekito_io_cfg.vk_sw1) & 0x8000) {
|
||||
sekito_opbtn |= SEKITO_IO_OPBTN_SW1;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(sekito_io_cfg.vk_sw2) & 0x8000) {
|
||||
sekito_opbtn |= SEKITO_IO_OPBTN_SW2;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(sekito_io_cfg.vk_coin) & 0x8000) {
|
||||
if (!sekito_io_coin) {
|
||||
sekito_io_coin = true;
|
||||
sekito_opbtn |= SEKITO_IO_OPBTN_COIN;
|
||||
}
|
||||
} else {
|
||||
sekito_io_coin = false;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void sekito_io_get_opbtns(uint8_t* opbtn) {
|
||||
if (opbtn != NULL) {
|
||||
*opbtn = sekito_opbtn;
|
||||
}
|
||||
}
|
||||
|
||||
void sekito_io_get_gamebtns(uint32_t* btn) {
|
||||
assert(sekito_io_backend != NULL);
|
||||
assert(btn != NULL);
|
||||
|
||||
sekito_io_backend->get_gamebtns(btn);
|
||||
}
|
||||
|
||||
void sekito_io_get_trackball_position(uint16_t* stick_x, uint16_t* stick_y) {
|
||||
assert(sekito_io_backend != NULL);
|
||||
assert(stick_x != NULL);
|
||||
assert(stick_y != NULL);
|
||||
|
||||
sekito_io_backend->get_trackball(stick_x, stick_y);
|
||||
}
|
||||
|
||||
HRESULT sekito_io_led_init(void) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void sekito_io_led_set_colors(uint8_t board, uint8_t* rgb) {
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
SEKITO_IO_OPBTN_TEST = 0x01,
|
||||
SEKITO_IO_OPBTN_SERVICE = 0x02,
|
||||
SEKITO_IO_OPBTN_COIN = 0x04,
|
||||
SEKITO_IO_OPBTN_SW1 = 0x08,
|
||||
SEKITO_IO_OPBTN_SW2 = 0x10,
|
||||
};
|
||||
|
||||
enum {
|
||||
SEKITO_IO_GAMEBTN_MENU = 0x01,
|
||||
SEKITO_IO_GAMEBTN_START = 0x02,
|
||||
SEKITO_IO_GAMEBTN_STRATAGEM = 0x04,
|
||||
SEKITO_IO_GAMEBTN_STRATAGEM_LOCK = 0x08,
|
||||
SEKITO_IO_GAMEBTN_HOUGU = 0x10,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_0 = 0x100,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_1 = 0x200,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_2 = 0x400,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_3 = 0x800,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_4 = 0x1000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_5 = 0x2000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_6 = 0x4000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_7 = 0x8000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_8 = 0x10000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_9 = 0x20000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_CLEAR = 0x40000,
|
||||
SEKITO_IO_GAMEBTN_NUMPAD_ENTER = 0x80000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_LEFT = 0x400000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_UP = 0x800000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_RIGHT = 0x1000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_DOWN = 0x2000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_LEFT_2 = 0x4000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_RIGHT_2 = 0x8000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_DECIDE = 0x10000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_CANCEL = 0x20000000,
|
||||
SEKITO_IO_GAMEBTN_TERMINAL_RESERVE = 0x40000000,
|
||||
};
|
||||
|
||||
/* Get the version of the Eiketsu Taisen 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 sekito_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after sekito_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT sekito_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 sekito_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
SEKITO_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *opbtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void sekito_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
SEKITO_IO_GAMEBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *gamebtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void sekito_io_get_gamebtns(uint32_t *gamebtn);
|
||||
|
||||
/* Get the position of the trackball as of the last poll.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void sekito_io_get_trackball_position(uint16_t *stick_x, uint16_t *stick_y);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other sekito_io_led_*() function calls.
|
||||
|
||||
All subsequent calls may originate from arbitrary threads and some may
|
||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||
your responsibility. */
|
||||
|
||||
HRESULT sekito_io_led_init(void);
|
||||
|
||||
/* Update the RGB LEDs.
|
||||
|
||||
Exact layout is TBD. */
|
||||
|
||||
void sekito_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||
Reference in New Issue
Block a user