forked from Hay1tsme/segatools
Compare commits
51 Commits
master
...
feature/ek
Author | SHA1 | Date | |
---|---|---|---|
6fa47f2c7f | |||
acedf0f372 | |||
6848a7a6c6 | |||
3195dbc282 | |||
67d0513273 | |||
a21fad184f | |||
fc22a29c56 | |||
e6e1171a5f | |||
84362a2839 | |||
7f017a0da9 | |||
f33fe0f2ae | |||
7dd1cd4a62 | |||
d264ae0b37 | |||
2950061d08 | |||
69a7f70388 | |||
1b09a57c0d | |||
d6143ebb5f | |||
136da4a2b8 | |||
04416715ef | |||
a6915a95f8 | |||
0f87e7510e | |||
05f68962cd | |||
bbfbe71852 | |||
619285c412 | |||
dc631215b1 | |||
3327548ca6 | |||
0480a7e767
|
|||
57d23726e8 | |||
837b0663aa | |||
873ae0a30a | |||
da0fc56500 | |||
fdd9c2fbc8
|
|||
bb47e4f1b5 | |||
d9210b52e1 | |||
4788e54398 | |||
e090f472af | |||
19c1a8e469 | |||
eb96660fdf | |||
83a9a49429 | |||
d423058cbd | |||
9703a0938a | |||
ec1a232103 | |||
c2af0a0df5 | |||
918d6368a5 | |||
d20bea1e16 | |||
dfab6bdb54 | |||
f8504b46b5 | |||
9b1f07e41b | |||
2313113fd0 | |||
bf3ff76f0c | |||
9c0ca7d66c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ build/
|
||||
|
||||
# External dependencies
|
||||
subprojects/capnhook
|
||||
subprojects/cwinwebsocket
|
||||
|
||||
# For enabling debug logging on local builds
|
||||
MesonLocalOptions.mk
|
||||
|
47
Package.mk
47
Package.mk
@ -256,6 +256,52 @@ $(BUILD_DIR_ZIP)/apm3.zip:
|
||||
$(V)strip $(BUILD_DIR_ZIP)/apm3/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/apm3 ; zip -r ../apm3.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/ekt.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/ekt
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/ekt/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_GAMES_64)/ekthook/ekthook.dll \
|
||||
$(DIST_DIR)/ekt/segatools_terminal.ini \
|
||||
$(DIST_DIR)/ekt/segatools_satellite.ini \
|
||||
$(DIST_DIR)/ekt/launch_terminal.bat \
|
||||
$(DIST_DIR)/ekt/launch_satellite.bat \
|
||||
$(DIST_DIR)/ekt/card_player.html \
|
||||
$(DIST_DIR)/ekt/config_hook.json \
|
||||
$(BUILD_DIR_ZIP)/ekt
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/ekt/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/ekt/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/ekt ; zip -r ../ekt.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/sekito.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/sekito
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/sekito/DEVICE
|
||||
$(V)cp $(DIST_DIR)/sekito/segatools_terminal.ini \
|
||||
$(DIST_DIR)/sekito/segatools_satellite.ini \
|
||||
$(DIST_DIR)/sekito/launch_terminal.bat \
|
||||
$(DIST_DIR)/sekito/launch_satellite.bat \
|
||||
$(DIST_DIR)/sekito/card_player.html \
|
||||
$(DIST_DIR)/sekito/config_hook.json \
|
||||
$(BUILD_DIR_ZIP)/sekito
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/sekito/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/sekito/inject_x86.exe
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/sekito/inject_x64.exe
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/sekito/inject_x86.exe
|
||||
$(V)cp $(BUILD_DIR_GAMES_32)/sekitohook/sekitohook.dll \
|
||||
$(BUILD_DIR_ZIP)/sekito/sekitohook_x86.dll
|
||||
$(V)cp $(BUILD_DIR_GAMES_64)/sekitohook/sekitohook.dll \
|
||||
$(BUILD_DIR_ZIP)/sekito/sekitohook_x64.dll
|
||||
$(V)strip $(BUILD_DIR_ZIP)/sekito/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/sekito ; zip -r ../sekito.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||
$(DOC_DIR)/config \
|
||||
$(DOC_DIR)/chunihook.md \
|
||||
@ -282,6 +328,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
|
||||
$(BUILD_DIR_ZIP)/fgo.zip \
|
||||
$(BUILD_DIR_ZIP)/kemono.zip \
|
||||
$(BUILD_DIR_ZIP)/apm3.zip \
|
||||
$(BUILD_DIR_ZIP)/ekt.zip \
|
||||
CHANGELOG.md \
|
||||
README.md \
|
||||
|
||||
|
@ -74,7 +74,7 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
|
||||
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename);
|
||||
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename);
|
||||
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 3, filename);
|
||||
cfg->proxy_flag = GetPrivateProfileIntW(L"aime", L"proxyFlag", 2, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/y3.h"
|
||||
#include "hooklib/y3-dll.h"
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
@ -26,7 +28,7 @@ void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *fi
|
||||
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
|
||||
}
|
||||
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
|
||||
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
@ -84,3 +86,161 @@ void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
|
||||
|
||||
cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename);
|
||||
}
|
||||
|
||||
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename){
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
char filenameA[MAX_PATH];
|
||||
|
||||
size_t n = wcstombs(filenameA, filename, MAX_PATH);
|
||||
for (int i = n; i < MAX_PATH; i++)
|
||||
{
|
||||
filenameA[i] = '\0';
|
||||
}
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 1, filename);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"firmwareVersion",
|
||||
"V04-03B",
|
||||
cfg->printer_firm_version,
|
||||
_countof(cfg->printer_firm_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"configVersion",
|
||||
"V01-75",
|
||||
cfg->printer_config_version,
|
||||
_countof(cfg->printer_config_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"tableVersion",
|
||||
"V01-E0",
|
||||
cfg->printer_table_version,
|
||||
_countof(cfg->printer_table_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"cameraVersion",
|
||||
"00.19",
|
||||
cfg->printer_camera_version,
|
||||
_countof(cfg->printer_camera_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"printerOutPath",
|
||||
L"DEVICE\\print",
|
||||
cfg->printer_out_path,
|
||||
_countof(cfg->printer_out_path),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"printerDataPath",
|
||||
L"DEVICE\\cx7000_data.bin",
|
||||
cfg->printer_data_path,
|
||||
_countof(cfg->printer_data_path),
|
||||
filename);
|
||||
|
||||
}
|
||||
|
||||
void y3_dll_config_load(
|
||||
struct y3_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3io",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void y3_config_load(
|
||||
struct y3_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[5];
|
||||
|
||||
memset(cfg->firm_name_field, ' ', sizeof(cfg->firm_name_field) - 1);
|
||||
cfg->firm_name_field[sizeof(cfg->firm_name_field) - 1] = '\0';
|
||||
|
||||
memset(cfg->firm_name_printer, ' ', sizeof(cfg->firm_name_printer) - 1);
|
||||
cfg->firm_name_printer[sizeof(cfg->firm_name_printer) - 1] = '\0';
|
||||
|
||||
memset(cfg->target_code_field, ' ', sizeof(cfg->target_code_field) - 1);
|
||||
cfg->target_code_field[sizeof(cfg->target_code_field) - 1] = '\0';
|
||||
|
||||
memset(cfg->target_code_printer, ' ', sizeof(cfg->target_code_printer) - 1);
|
||||
cfg->target_code_printer[sizeof(cfg->target_code_printer) - 1] = '\0';
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"flatPanelReader", L"enable", 1, filename);
|
||||
cfg->port_field = GetPrivateProfileIntW(L"flatPanelReader", L"port_field", 10, filename);
|
||||
cfg->port_printer = GetPrivateProfileIntW(L"flatPanelReader", L"port_printer", 11, filename);
|
||||
|
||||
cfg->dll_version = (float)GetPrivateProfileIntW(
|
||||
L"flatPanelReader",
|
||||
L"dllVersion",
|
||||
1,
|
||||
filename);
|
||||
|
||||
cfg->firm_version = (float)GetPrivateProfileIntW(
|
||||
L"flatPanelReader",
|
||||
L"firmVersion",
|
||||
1,
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"firmNameField",
|
||||
L"SFPR",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->firm_name_field, tmpstr, sizeof(cfg->firm_name_field) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"firmNamePrinter",
|
||||
L"SPRT",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->firm_name_printer, tmpstr, sizeof(cfg->firm_name_printer) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"targetCodeField",
|
||||
L"SFR0",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->target_code_field, tmpstr, sizeof(cfg->target_code_field) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"targetCodePrinter",
|
||||
L"SPT0",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->target_code_printer, tmpstr, sizeof(cfg->target_code_printer) - 1);
|
||||
}
|
@ -4,8 +4,29 @@
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
struct y3_config {
|
||||
bool enable;
|
||||
|
||||
float dll_version;
|
||||
float firm_version;
|
||||
char firm_name_field[5];
|
||||
char firm_name_printer[5];
|
||||
char target_code_field[5];
|
||||
char target_code_printer[5];
|
||||
uint8_t port_field;
|
||||
uint8_t port_printer;
|
||||
};
|
||||
|
||||
struct y3_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
|
||||
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename);
|
||||
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename);
|
||||
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename);
|
||||
void y3_config_load(struct y3_config *cfg, const wchar_t *filename);
|
||||
void y3_dll_config_load(struct y3_dll_config *cfg, const wchar_t *filename);
|
212
common/hooklib/imageutil.c
Normal file
212
common/hooklib/imageutil.c
Normal file
@ -0,0 +1,212 @@
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "imageutil.h"
|
||||
|
||||
// copy pasted from https://dev.s-ul.net/domeori/c310emu
|
||||
#define BITMAPHEADERSIZE 0x36
|
||||
|
||||
int ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip) {
|
||||
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
|
||||
|
||||
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
|
||||
|
||||
PBYTE pBuffer = malloc(cbInput);
|
||||
if (!pBuffer) return -2;
|
||||
|
||||
BYTE dwColors = (BYTE)(dwBitCount / 8);
|
||||
if (!dwColors) {
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UINT16 cbColors;
|
||||
RGBQUAD pbColors[256];
|
||||
|
||||
switch (dwBitCount) {
|
||||
case 1:
|
||||
cbColors = 1;
|
||||
break;
|
||||
case 2:
|
||||
cbColors = 4;
|
||||
break;
|
||||
case 4:
|
||||
cbColors = 16;
|
||||
break;
|
||||
case 8:
|
||||
cbColors = 256;
|
||||
break;
|
||||
default:
|
||||
cbColors = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cbColors) {
|
||||
BYTE dwStep = (BYTE)(256 / cbColors);
|
||||
|
||||
for (UINT16 i = 0; i < cbColors; ++i) {
|
||||
pbColors[i].rgbRed = dwStep * i;
|
||||
pbColors[i].rgbGreen = dwStep * i;
|
||||
pbColors[i].rgbBlue = dwStep * i;
|
||||
pbColors[i].rgbReserved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwTable = cbColors * sizeof(RGBQUAD);
|
||||
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
|
||||
|
||||
// calculate the padded row size, again
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
|
||||
BITMAPFILEHEADER bFile = {0};
|
||||
BITMAPINFOHEADER bInfo = {0};
|
||||
|
||||
bFile.bfType = 0x4D42; // MAGIC
|
||||
bFile.bfSize = dwOffset + cbInput;
|
||||
bFile.bfOffBits = dwOffset;
|
||||
|
||||
bInfo.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bInfo.biWidth = dwWidth;
|
||||
bInfo.biHeight = dwHeight;
|
||||
bInfo.biPlanes = 1;
|
||||
bInfo.biBitCount = (WORD)dwBitCount;
|
||||
bInfo.biCompression = BI_RGB;
|
||||
bInfo.biSizeImage = cbInput;
|
||||
|
||||
if (cbOutput < bFile.bfSize) {
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Flip the image (if necessary) and add padding to each row
|
||||
if (pFlip) {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
// Make sure to also flip the colors from RGB to BRG
|
||||
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
|
||||
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
|
||||
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
|
||||
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
|
||||
|
||||
*pcbResult = bFile.bfSize;
|
||||
|
||||
free(pBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip) {
|
||||
if (!lpFilePath || !pbInput) return -3;
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
hFile = CreateFileW(
|
||||
lpFilePath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
// calculate the padded row size and padded image size
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
DWORD dwImageSize = dwLineSize * dwHeight;
|
||||
|
||||
DWORD cbResult;
|
||||
DWORD cbBuffer = dwImageSize + 0x500;
|
||||
PBYTE pbBuffer = calloc(cbBuffer, 1);
|
||||
if (!pbBuffer) return -2;
|
||||
|
||||
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
|
||||
cbResult = -1;
|
||||
goto WriteDataToBitmapFile_End;
|
||||
}
|
||||
|
||||
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
|
||||
|
||||
if (pbMetadata)
|
||||
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
cbResult = dwBytesWritten;
|
||||
|
||||
WriteDataToBitmapFile_End:
|
||||
free(pbBuffer);
|
||||
return cbResult;
|
||||
}
|
||||
|
||||
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
|
||||
#ifdef NDEBUG
|
||||
|
||||
return nDataSize;
|
||||
|
||||
#else
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwCreationDisposition;
|
||||
|
||||
if (isAppend) {
|
||||
dwDesiredAccess = FILE_APPEND_DATA;
|
||||
dwCreationDisposition = OPEN_ALWAYS;
|
||||
} else {
|
||||
dwDesiredAccess = GENERIC_WRITE;
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
hFile = CreateFileA(
|
||||
lpOutputFilePath,
|
||||
dwDesiredAccess,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
dwCreationDisposition,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return dwBytesWritten;
|
||||
|
||||
#endif
|
||||
}
|
21
common/hooklib/imageutil.h
Normal file
21
common/hooklib/imageutil.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip);
|
||||
|
||||
int WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip);
|
||||
|
||||
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend);
|
@ -21,6 +21,8 @@ hooklib_lib = static_library(
|
||||
'dvd.h',
|
||||
'fdshark.c',
|
||||
'fdshark.h',
|
||||
'imageutil.c',
|
||||
'imageutil.h',
|
||||
'path.c',
|
||||
'path.h',
|
||||
'reg.c',
|
||||
@ -31,7 +33,13 @@ hooklib_lib = static_library(
|
||||
'spike.h',
|
||||
'touch.c',
|
||||
'touch.h',
|
||||
'printer.c',
|
||||
'printer.h',
|
||||
'printer_chc.c',
|
||||
'printer_chc.h',
|
||||
'printer_cx.c',
|
||||
'printer_cx.h',
|
||||
'y3.c',
|
||||
'y3.h',
|
||||
'y3-dll.c',
|
||||
'y3-dll.h',
|
||||
],
|
||||
)
|
||||
|
@ -9,7 +9,9 @@
|
||||
chc (emihiok)
|
||||
*/
|
||||
|
||||
#include "hooklib/printer.h"
|
||||
// ReSharper disable CppParameterNeverUsed
|
||||
// ReSharper disable CppDFAConstantFunctionResult
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
@ -98,7 +100,7 @@ int WINAPI chcusb_imageformat_330(
|
||||
uint16_t width,
|
||||
uint16_t height,
|
||||
uint16_t *rResult);
|
||||
int __fastcall chcusb_setmtf(int32_t *mtf);
|
||||
int WINAPI chcusb_setmtf(int32_t *mtf);
|
||||
int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB);
|
||||
int WINAPI chcusb_setIcctable(
|
||||
LPCSTR icc1,
|
||||
@ -147,6 +149,7 @@ int WINAPI chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult);
|
||||
int WINAPI chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult);
|
||||
int WINAPI chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult);
|
||||
int WINAPI chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult);
|
||||
int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult);
|
||||
|
||||
/* PrintDLL API hooks */
|
||||
|
||||
@ -864,6 +867,336 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* CHC320 x86 hook table */
|
||||
|
||||
static const struct hook_symbol C320usb_hooks[] = {
|
||||
{
|
||||
.name = "__imp_chcusb_MakeThread",
|
||||
.ordinal= 1,
|
||||
.patch = chcusb_MakeThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_open",
|
||||
.ordinal= 2,
|
||||
.patch = chcusb_open,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_close",
|
||||
.ordinal= 3,
|
||||
.patch = chcusb_close,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_ReleaseThread",
|
||||
.ordinal= 4,
|
||||
.patch = chcusb_ReleaseThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_listupPrinter",
|
||||
.ordinal= 5,
|
||||
.patch = chcusb_listupPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_listupPrinterSN",
|
||||
.ordinal= 6,
|
||||
.patch = chcusb_listupPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_selectPrinter",
|
||||
.ordinal= 7,
|
||||
.patch = chcusb_selectPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_selectPrinterSN",
|
||||
.ordinal= 8,
|
||||
.patch = chcusb_selectPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getPrinterInfo",
|
||||
.ordinal= 9,
|
||||
.patch = chcusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_imageformat",
|
||||
.ordinal= 10,
|
||||
.patch = chcusb_imageformat_330,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setmtf",
|
||||
.ordinal= 11,
|
||||
.patch = chcusb_setmtf,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_makeGamma",
|
||||
.ordinal= 12,
|
||||
.patch = chcusb_makeGamma,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setIcctable",
|
||||
.ordinal= 13,
|
||||
.patch = chcusb_setIcctable,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_copies",
|
||||
.ordinal= 14,
|
||||
.patch = chcusb_copies,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_status",
|
||||
.ordinal= 15,
|
||||
.patch = chcusb_status,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_statusAll",
|
||||
.ordinal= 16,
|
||||
.patch = chcusb_statusAll,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_startpage",
|
||||
.ordinal= 17,
|
||||
.patch = chcusb_startpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_endpage",
|
||||
.ordinal= 18,
|
||||
.patch = chcusb_endpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_write",
|
||||
.ordinal= 19,
|
||||
.patch = chcusb_write,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_writeLaminate",
|
||||
.ordinal= 20,
|
||||
.patch = chcusb_writeLaminate,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_writeHolo",
|
||||
.ordinal= 21,
|
||||
.patch = chcusb_writeHolo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setPrinterInfo",
|
||||
.ordinal= 22,
|
||||
.patch = chcusb_setPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getGamma",
|
||||
.ordinal= 23,
|
||||
.patch = chcusb_getGamma,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getMtf",
|
||||
.ordinal= 24,
|
||||
.patch = chcusb_getMtf,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_cancelCopies",
|
||||
.ordinal= 25,
|
||||
.patch = chcusb_cancelCopies,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setPrinterToneCurve",
|
||||
.ordinal= 26,
|
||||
.patch = chcusb_setPrinterToneCurve,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getPrinterToneCurve",
|
||||
.ordinal= 27,
|
||||
.patch = chcusb_getPrinterToneCurve,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_blinkLED",
|
||||
.ordinal= 28,
|
||||
.patch = chcusb_blinkLED,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_resetPrinter",
|
||||
.ordinal= 29,
|
||||
.patch = chcusb_resetPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_AttachThreadCount",
|
||||
.ordinal= 30,
|
||||
.patch = chcusb_AttachThreadCount,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getPrintIDStatus",
|
||||
.ordinal= 31,
|
||||
.patch = chcusb_getPrintIDStatus,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setPrintStandby",
|
||||
.ordinal= 32,
|
||||
.patch = chcusb_setPrintStandby,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_testCardFeed",
|
||||
.ordinal= 33,
|
||||
.patch = chcusb_testCardFeed,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_exitCard",
|
||||
.ordinal= 34,
|
||||
.patch = chcusb_exitCard,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getCardRfidTID",
|
||||
.ordinal= 35,
|
||||
.patch = chcusb_getCardRfidTID,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_commCardRfidReader",
|
||||
.ordinal= 36,
|
||||
.patch = chcusb_commCardRfidReader,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_updateCardRfidReader",
|
||||
.ordinal= 37,
|
||||
.patch = chcusb_updateCardRfidReader,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getErrorLog",
|
||||
.ordinal= 38,
|
||||
.patch = chcusb_getErrorLog,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getErrorStatus",
|
||||
.ordinal= 39,
|
||||
.patch = chcusb_getErrorStatus,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setCutList",
|
||||
.ordinal= 40,
|
||||
.patch = chcusb_setCutList,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setLaminatePattern",
|
||||
.ordinal= 41,
|
||||
.patch = chcusb_setLaminatePattern,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_color_adjustment",
|
||||
.ordinal= 42,
|
||||
.patch = chcusb_color_adjustment,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_color_adjustmentEx",
|
||||
.ordinal= 43,
|
||||
.patch = chcusb_color_adjustmentEx,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_writeIred",
|
||||
.ordinal= 50,
|
||||
.patch = chcusb_writeIred,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getEEPROM",
|
||||
.ordinal= 58,
|
||||
.patch = chcusb_getEEPROM,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_setParameter",
|
||||
.ordinal= 64,
|
||||
.patch = chcusb_setParameter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_getParameter",
|
||||
.ordinal= 65,
|
||||
.patch = chcusb_getParameter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_chcusb_universal_command",
|
||||
.ordinal= 73,
|
||||
.patch = chcusb_universal_command,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol C320FWDLusb_hooks[] = {
|
||||
{
|
||||
.name = "__imp_fwdlusb_open",
|
||||
.ordinal= 1,
|
||||
.patch = fwdlusb_open,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_close",
|
||||
.ordinal= 2,
|
||||
.patch = fwdlusb_close,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_listupPrinter",
|
||||
.ordinal= 3,
|
||||
.patch = fwdlusb_listupPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_listupPrinterSN",
|
||||
.ordinal= 4,
|
||||
.patch = fwdlusb_listupPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_selectPrinter",
|
||||
.ordinal= 5,
|
||||
.patch = fwdlusb_selectPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_selectPrinterSN",
|
||||
.ordinal= 6,
|
||||
.patch = fwdlusb_selectPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_getPrinterInfo",
|
||||
.ordinal= 7,
|
||||
.patch = fwdlusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_status",
|
||||
.ordinal= 8,
|
||||
.patch = fwdlusb_status,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_statusAll",
|
||||
.ordinal= 9,
|
||||
.patch = fwdlusb_statusAll,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_resetPrinter",
|
||||
.ordinal= 10,
|
||||
.patch = fwdlusb_resetPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_updateFirmware",
|
||||
.ordinal= 11,
|
||||
.patch = fwdlusb_updateFirmware,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_getFirmwareInfo",
|
||||
.ordinal= 12,
|
||||
.patch = fwdlusb_getFirmwareInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_MakeThread",
|
||||
.ordinal= 13,
|
||||
.patch = fwdlusb_MakeThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_ReleaseThread",
|
||||
.ordinal= 14,
|
||||
.patch = fwdlusb_ReleaseThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_AttachThreadCount",
|
||||
.ordinal= 15,
|
||||
.patch = fwdlusb_AttachThreadCount,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "__imp_fwdlusb_getErrorLog",
|
||||
.ordinal= 16,
|
||||
.patch = fwdlusb_getErrorLog,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
/* PrintDLL hook tbl */
|
||||
|
||||
static struct hook_symbol printdll_hooks[] = {
|
||||
@ -1150,9 +1483,9 @@ static struct hook_symbol printdll_hooks[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct printer_config printer_config;
|
||||
static struct printer_chc_config printer_config;
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self) {
|
||||
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self) {
|
||||
HANDLE fwFile = NULL;
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
@ -1170,7 +1503,7 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
|
||||
rotate180 = cfg->rotate_180;
|
||||
|
||||
memcpy(&printer_config, cfg, sizeof(*cfg));
|
||||
printer_hook_insert_hooks(NULL);
|
||||
printer_chc_hook_insert_hooks(NULL);
|
||||
|
||||
/*
|
||||
if (self != NULL) {
|
||||
@ -1229,13 +1562,13 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
|
||||
dprintf("Printer: hook enabled.\n");
|
||||
}
|
||||
|
||||
void printer_hook_insert_hooks(HMODULE target) {
|
||||
void printer_chc_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(target, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
hook_table_apply(target, "C310BFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
hook_table_apply(target, "C320Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C320AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
hook_table_apply(target, "C320Ausb.dll", C320usb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C320AFWDLusb.dll", C320FWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
hook_table_apply(target, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
|
||||
@ -2160,6 +2493,11 @@ int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t
|
||||
if (rBuffer) memset(rBuffer, 0, *rLen);
|
||||
break;
|
||||
|
||||
case 2: // unknown
|
||||
if (*rLen != 0x17) *rLen = 0x17;
|
||||
if (rBuffer) memset(rBuffer, 0, *rLen);
|
||||
break;
|
||||
|
||||
case 3: // getFirmwareVersion
|
||||
if (*rLen != 0x99) *rLen = 0x99;
|
||||
if (rBuffer) {
|
||||
@ -2334,7 +2672,7 @@ int WINAPI chcusb_imageformat_330(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __fastcall chcusb_setmtf(int32_t *mtf) {
|
||||
int WINAPI chcusb_setmtf(int32_t *mtf) {
|
||||
dprintf("Printer: C3XXusb: %s\n", __func__);
|
||||
|
||||
memcpy(MTF, mtf, sizeof(MTF));
|
||||
@ -3147,208 +3485,14 @@ int CHCUSB_writeLaminate(const void *handle, uint8_t *data, uint32_t offset, uin
|
||||
return chcusb_writeLaminate(data, writeSize, rResult);
|
||||
}
|
||||
|
||||
// copy pasted from https://dev.s-ul.net/domeori/c310emu
|
||||
#define BITMAPHEADERSIZE 0x36
|
||||
|
||||
DWORD ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip) {
|
||||
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
|
||||
|
||||
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
|
||||
|
||||
PBYTE pBuffer = (PBYTE)malloc(cbInput);
|
||||
if (!pBuffer) return -2;
|
||||
|
||||
BYTE dwColors = (BYTE)(dwBitCount / 8);
|
||||
if (!dwColors) return -1;
|
||||
|
||||
UINT16 cbColors;
|
||||
RGBQUAD pbColors[256];
|
||||
|
||||
switch (dwBitCount) {
|
||||
case 1:
|
||||
cbColors = 1;
|
||||
break;
|
||||
case 2:
|
||||
cbColors = 4;
|
||||
break;
|
||||
case 4:
|
||||
cbColors = 16;
|
||||
break;
|
||||
case 8:
|
||||
cbColors = 256;
|
||||
break;
|
||||
default:
|
||||
cbColors = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cbColors) {
|
||||
BYTE dwStep = (BYTE)(256 / cbColors);
|
||||
|
||||
for (UINT16 i = 0; i < cbColors; ++i) {
|
||||
pbColors[i].rgbRed = dwStep * i;
|
||||
pbColors[i].rgbGreen = dwStep * i;
|
||||
pbColors[i].rgbBlue = dwStep * i;
|
||||
pbColors[i].rgbReserved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwTable = cbColors * sizeof(RGBQUAD);
|
||||
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
|
||||
|
||||
// calculate the padded row size, again
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
|
||||
BITMAPFILEHEADER bFile = {0};
|
||||
BITMAPINFOHEADER bInfo = {0};
|
||||
|
||||
bFile.bfType = 0x4D42; // MAGIC
|
||||
bFile.bfSize = dwOffset + cbInput;
|
||||
bFile.bfOffBits = dwOffset;
|
||||
|
||||
bInfo.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bInfo.biWidth = dwWidth;
|
||||
bInfo.biHeight = dwHeight;
|
||||
bInfo.biPlanes = 1;
|
||||
bInfo.biBitCount = (WORD)dwBitCount;
|
||||
bInfo.biCompression = BI_RGB;
|
||||
bInfo.biSizeImage = cbInput;
|
||||
|
||||
if (cbOutput < bFile.bfSize) return -1;
|
||||
|
||||
// Flip the image (if necessary) and add padding to each row
|
||||
if (pFlip) {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
// Make sure to also flip the colors from RGB to BRG
|
||||
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
|
||||
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
|
||||
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
|
||||
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
|
||||
|
||||
*pcbResult = bFile.bfSize;
|
||||
|
||||
free(pBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip) {
|
||||
if (!lpFilePath || !pbInput) return -3;
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
hFile = CreateFileW(
|
||||
lpFilePath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
// calculate the padded row size and padded image size
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
DWORD dwImageSize = dwLineSize * dwHeight;
|
||||
|
||||
DWORD cbResult;
|
||||
DWORD cbBuffer = dwImageSize + 0x500;
|
||||
PBYTE pbBuffer = (PBYTE)calloc(cbBuffer, 1);
|
||||
if (!pbBuffer) return -2;
|
||||
|
||||
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
|
||||
cbResult = -1;
|
||||
goto WriteDataToBitmapFile_End;
|
||||
}
|
||||
|
||||
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
|
||||
|
||||
if (pbMetadata)
|
||||
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
cbResult = dwBytesWritten;
|
||||
|
||||
WriteDataToBitmapFile_End:
|
||||
free(pbBuffer);
|
||||
return cbResult;
|
||||
}
|
||||
|
||||
DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
|
||||
#ifdef NDEBUG
|
||||
|
||||
return nDataSize;
|
||||
|
||||
#else
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwCreationDisposition;
|
||||
|
||||
if (isAppend) {
|
||||
dwDesiredAccess = FILE_APPEND_DATA;
|
||||
dwCreationDisposition = OPEN_ALWAYS;
|
||||
} else {
|
||||
dwDesiredAccess = GENERIC_WRITE;
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
hFile = CreateFileA(
|
||||
lpOutputFilePath,
|
||||
dwDesiredAccess,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
dwCreationDisposition,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return dwBytesWritten;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void printer_set_dimensions(int width, int height){
|
||||
WIDTH = width;
|
||||
HEIGHT = height;
|
||||
}
|
||||
|
||||
|
||||
int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult) {
|
||||
dprintf("Printer: C3XXusb: %s\n", __func__);
|
||||
*rResult = 0;
|
||||
return 1;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct printer_config {
|
||||
struct printer_chc_config {
|
||||
bool enable;
|
||||
bool rotate_180;
|
||||
char serial_no[8];
|
||||
@ -15,8 +15,8 @@ struct printer_config {
|
||||
uint32_t wait_time;
|
||||
};
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_hook_insert_hooks(HMODULE target);
|
||||
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_chc_hook_insert_hooks(HMODULE target);
|
||||
|
||||
void printer_set_dimensions(int width, int height);
|
||||
int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult);
|
920
common/hooklib/printer_cx.c
Normal file
920
common/hooklib/printer_cx.c
Normal file
@ -0,0 +1,920 @@
|
||||
// ReSharper disable CppParameterNeverUsed
|
||||
// ReSharper disable CppParameterMayBeConstPtrOrRef
|
||||
#include "printer_cx.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <wtypes.h>
|
||||
|
||||
#include "imageutil.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hook/table.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#pragma region prototypes
|
||||
static int __stdcall hook_CXCMD_Retransfer();
|
||||
|
||||
static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId);
|
||||
|
||||
static int __stdcall hook_CXCMD_xImageOut();
|
||||
|
||||
static int __stdcall hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
|
||||
|
||||
static int __stdcall hook_CXCMD_xWriteMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed);
|
||||
|
||||
static int __stdcall hook_CXCMD_ScanPrinterNext();
|
||||
|
||||
static int __stdcall hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed);
|
||||
|
||||
static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action);
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer);
|
||||
|
||||
static int __stdcall hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer);
|
||||
|
||||
static int __stdcall hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer);
|
||||
|
||||
static int __stdcall hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID);
|
||||
|
||||
static int __stdcall hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData);
|
||||
|
||||
static int __stdcall hook_CXCMD_GetPrintingStatus();
|
||||
|
||||
static int __stdcall hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount);
|
||||
|
||||
static int __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed);
|
||||
|
||||
static int __stdcall hook_CXCMD_LogSelect(int iSlot, int iID, int iMod);
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer);
|
||||
|
||||
static int __stdcall hook_CXCMD_SecurityLock();
|
||||
|
||||
static int __stdcall hook_CXCMD_SetPrintingStatus();
|
||||
|
||||
static int __stdcall hook_CXCMD_xReadISOMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteISO3TrackMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_PasswordSet();
|
||||
|
||||
static int __stdcall hook_CXCMD_GetPrinterStatus();
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteProjectCode();
|
||||
|
||||
static int __stdcall hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_ScanPrinter(int* pSlotId, int* pId);
|
||||
|
||||
static int __stdcall hook_CXCMD_xWriteISOMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_ICControl();
|
||||
|
||||
static int __stdcall hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex);
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength);
|
||||
|
||||
static int __stdcall hook_CXCMD_xReadMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength);
|
||||
|
||||
static int __stdcall hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer);
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadISO3TrackMagData();
|
||||
|
||||
static int __stdcall hook_CXCMD_TestUnitReady(int slotId, int id);
|
||||
|
||||
static int __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed);
|
||||
|
||||
static bool __stdcall hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
|
||||
int sizeC);
|
||||
|
||||
static bool __stdcall hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
|
||||
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata);
|
||||
|
||||
static int __cdecl hook_init_accesscodekey(BSTR fileName);
|
||||
|
||||
static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen);
|
||||
#pragma endregion
|
||||
|
||||
#pragma region hooktables
|
||||
static const struct hook_symbol hook_pcp_syms[] = {
|
||||
{
|
||||
.name = "CXCMD_Retransfer",
|
||||
.patch = hook_CXCMD_Retransfer,
|
||||
.ordinal = 19,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_CheckIfConnected",
|
||||
.patch = hook_CXCMD_CheckIfConnected,
|
||||
.ordinal = 1,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xImageOut",
|
||||
.patch = hook_CXCMD_xImageOut,
|
||||
.ordinal = 36,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_MoveCard",
|
||||
.patch = hook_CXCMD_MoveCard,
|
||||
.ordinal = 12,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xWriteMagData",
|
||||
.patch = hook_CXCMD_xWriteMagData,
|
||||
.ordinal = 40,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SecurityPrint",
|
||||
.patch = hook_CXCMD_SecurityPrint,
|
||||
.ordinal = 26,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ScanPrinterNext",
|
||||
.patch = hook_CXCMD_ScanPrinterNext,
|
||||
.ordinal = 24,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_Print",
|
||||
.patch = hook_CXCMD_Print,
|
||||
.ordinal = 14,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RezeroUnit",
|
||||
.patch = hook_CXCMD_RezeroUnit,
|
||||
.ordinal = 22,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteMagData",
|
||||
.patch = hook_CXCMD_WriteMagData,
|
||||
.ordinal = 34,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LogSense",
|
||||
.patch = hook_CXCMD_LogSense,
|
||||
.ordinal = 9,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_StandardInquiry",
|
||||
.patch = hook_CXCMD_StandardInquiry,
|
||||
.ordinal = 29,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ModeSense",
|
||||
.patch = hook_CXCMD_ModeSense,
|
||||
.ordinal = 11,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_UpdateFirmware",
|
||||
.patch = hook_CXCMD_UpdateFirmware,
|
||||
.ordinal = 31,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ModeSelect",
|
||||
.patch = hook_CXCMD_ModeSelect,
|
||||
.ordinal = 10,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_GetPrintingStatus",
|
||||
.patch = hook_CXCMD_GetPrintingStatus,
|
||||
.ordinal = 4,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SendDiagnostic",
|
||||
.patch = hook_CXCMD_SendDiagnostic,
|
||||
.ordinal = 27,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RetransferAndTurn",
|
||||
.patch = hook_CXCMD_RetransferAndTurn,
|
||||
.ordinal = 21,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LogSelect",
|
||||
.patch = hook_CXCMD_LogSelect,
|
||||
.ordinal = 8,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadPosition",
|
||||
.patch = hook_CXCMD_ReadPosition,
|
||||
.ordinal = 18,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SecurityLock",
|
||||
.patch = hook_CXCMD_SecurityLock,
|
||||
.ordinal = 25,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SetPrintingStatus",
|
||||
.patch = hook_CXCMD_SetPrintingStatus,
|
||||
.ordinal = 28,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xReadISOMagData",
|
||||
.patch = hook_CXCMD_xReadISOMagData,
|
||||
.ordinal = 37,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteISO3TrackMagData",
|
||||
.patch = hook_CXCMD_WriteISO3TrackMagData,
|
||||
.ordinal = 33,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_PasswordSet",
|
||||
.patch = hook_CXCMD_PasswordSet,
|
||||
.ordinal = 13,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_GetPrinterStatus",
|
||||
.patch = hook_CXCMD_GetPrinterStatus,
|
||||
.ordinal = 3,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteProjectCode",
|
||||
.patch = hook_CXCMD_WriteProjectCode,
|
||||
.ordinal = 35,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LoadCard",
|
||||
.patch = hook_CXCMD_LoadCard,
|
||||
.ordinal = 7,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadMagData",
|
||||
.patch = hook_CXCMD_ReadMagData,
|
||||
.ordinal = 17,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ScanPrinter",
|
||||
.patch = hook_CXCMD_ScanPrinter,
|
||||
.ordinal = 23,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xWriteISOMagData",
|
||||
.patch = hook_CXCMD_xWriteISOMagData,
|
||||
.ordinal = 39,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ICControl",
|
||||
.patch = hook_CXCMD_ICControl,
|
||||
.ordinal = 5,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ImageOut",
|
||||
.patch = hook_CXCMD_ImageOut,
|
||||
.ordinal = 6,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadBuffer",
|
||||
.patch = hook_CXCMD_ReadBuffer,
|
||||
.ordinal = 15,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xReadMagData",
|
||||
.patch = hook_CXCMD_xReadMagData,
|
||||
.ordinal = 38,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteBuffer",
|
||||
.patch = hook_CXCMD_WriteBuffer,
|
||||
.ordinal = 32,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_DefineLUT",
|
||||
.patch = hook_CXCMD_DefineLUT,
|
||||
.ordinal = 2,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadISO3TrackMagData",
|
||||
.patch = hook_CXCMD_ReadISO3TrackMagData,
|
||||
.ordinal = 16,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_TestUnitReady",
|
||||
.patch = hook_CXCMD_TestUnitReady,
|
||||
.ordinal = 30,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RetransferAndEject",
|
||||
.patch = hook_CXCMD_RetransferAndEject,
|
||||
.ordinal = 20,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol hook_lut_syms[] = {
|
||||
{
|
||||
.name = "Lut24_Exchange",
|
||||
.patch = hook_Lut24_Exchange,
|
||||
.ordinal = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol hook_wdata_syms[] = {
|
||||
{
|
||||
.name = "Wdata_create",
|
||||
.patch = hook_Wdata_create,
|
||||
.ordinal = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol hook_ac_syms[] = {
|
||||
{
|
||||
.name = "init_accesscodekey",
|
||||
.patch = hook_init_accesscodekey,
|
||||
},{
|
||||
.name = "accesscodekeyoverwriteheader",
|
||||
.patch = hook_accesscodekeyoverwriteheader,
|
||||
},
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
static void write_int(uint8_t* data, int index, int value) {
|
||||
data[index] = value >> 24;
|
||||
data[index + 1] = value >> 16;
|
||||
data[index + 2] = value >> 8;
|
||||
data[index + 3] = value;
|
||||
}
|
||||
|
||||
static void write_short(uint8_t* data, int index, short value) {
|
||||
data[index] = value >> 8;
|
||||
data[index + 1] = value;
|
||||
}
|
||||
|
||||
static struct printer_cx_config printer_config;
|
||||
static wchar_t printer_out_path[MAX_PATH];
|
||||
static struct printer_cx_data printer_data;
|
||||
|
||||
#define HEIGHT 664
|
||||
#define WIDTH 1036
|
||||
#define IMAGE_BUFFER_SIZE WIDTH * HEIGHT
|
||||
static uint8_t back_buffer[4][IMAGE_BUFFER_SIZE];
|
||||
static uint8_t front_buffer[4][IMAGE_BUFFER_SIZE];
|
||||
static uint64_t current_card_id;
|
||||
|
||||
DWORD load_printer_data() {
|
||||
DWORD bytesRead = 0;
|
||||
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSave != INVALID_HANDLE_VALUE) {
|
||||
if (!ReadFile(hSave, &printer_data, sizeof(printer_data), &bytesRead, NULL)){
|
||||
CloseHandle(hSave);
|
||||
return GetLastError();
|
||||
}
|
||||
CloseHandle(hSave);
|
||||
if (bytesRead != sizeof(printer_data)){
|
||||
return -1;
|
||||
}
|
||||
if (printer_data.version != PRINTER_DATA_VERSION) {
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD save_printer_data() {
|
||||
DWORD bytesWritten = 0;
|
||||
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSave != NULL) {
|
||||
if (!WriteFile(hSave, &printer_data, sizeof(printer_data), &bytesWritten, NULL)){
|
||||
CloseHandle(hSave);
|
||||
dprintf("CX7000: Failed writing data: %lx\n", GetLastError());
|
||||
return GetLastError();
|
||||
}
|
||||
CloseHandle(hSave);
|
||||
return 0;
|
||||
} else {
|
||||
dprintf("CX7000: Failed opening data file for writing: %lx\n", GetLastError());
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
void printer_cx_hook_init(const struct printer_cx_config* cfg, HINSTANCE self) {
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&printer_config, cfg, sizeof(*cfg));
|
||||
printer_cx_hook_insert_hooks(NULL);
|
||||
|
||||
CreateDirectoryW(cfg->printer_out_path, NULL);
|
||||
memcpy(printer_out_path, cfg->printer_out_path, MAX_PATH);
|
||||
|
||||
if (load_printer_data() != 0) {
|
||||
memset(&printer_data, 0, sizeof(printer_data));
|
||||
printer_data.version = PRINTER_DATA_VERSION;
|
||||
if (save_printer_data() == 0) {
|
||||
dprintf("CX7000: Printer data initialized.\n");
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("CX7000: hook enabled.\n");
|
||||
}
|
||||
|
||||
void printer_cx_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
|
||||
hook_table_apply(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
|
||||
hook_table_apply(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
|
||||
hook_table_apply(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_syms));
|
||||
|
||||
/* Unity workaround */
|
||||
proc_addr_table_push(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
|
||||
proc_addr_table_push(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
|
||||
proc_addr_table_push(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
|
||||
proc_addr_table_push(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_syms));
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_Retransfer() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return printer_config.enable;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_xImageOut() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_xWriteMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ScanPrinterNext() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
assert(color >= 0 && color <= 3);
|
||||
assert(bufferIndex >= 0 && bufferIndex <= 1);
|
||||
assert(length == IMAGE_BUFFER_SIZE);
|
||||
|
||||
// colorIndex: 0 = w, 1 = c, 2 = m, 3 = y
|
||||
// bufferIndex: 0 = back, 1 = front
|
||||
|
||||
if (bufferIndex == 0) {
|
||||
memcpy(back_buffer[color], plane, length);
|
||||
} else {
|
||||
memcpy(front_buffer[color], plane, length);
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, color, bufferIndex, immed);
|
||||
|
||||
assert(bufferIndex >= 0 && bufferIndex <= 1);
|
||||
|
||||
SYSTEMTIME t;
|
||||
GetLocalTime(&t);
|
||||
|
||||
// color: 1 = back, 3 = front
|
||||
// bufferIndex: 0 = back, 1 = front
|
||||
|
||||
wchar_t dumpPath[MAX_PATH];
|
||||
uint8_t metadata[5];
|
||||
|
||||
metadata[0] = current_card_id >> 32;
|
||||
write_int(metadata, 1, (int32_t)current_card_id);
|
||||
|
||||
swprintf_s(
|
||||
dumpPath, MAX_PATH,
|
||||
L"%s\\CX7000_%04d%02d%02d_%02d%02d%02d_%s.bmp",
|
||||
printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, bufferIndex == 0 ? L"back" : L"front");
|
||||
|
||||
// convert image from seperate CMY arrays to one RGB array
|
||||
int size = IMAGE_BUFFER_SIZE * 3;
|
||||
uint8_t* raw_image = (uint8_t*)malloc(size);
|
||||
for (int i = 0; i < IMAGE_BUFFER_SIZE; i++) {
|
||||
// 0 is "white" and we don't really care about that
|
||||
raw_image[i * 3] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[1][i];
|
||||
raw_image[i * 3 + 1] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[2][i];
|
||||
raw_image[i * 3 + 2] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[3][i];
|
||||
}
|
||||
|
||||
dprintf("CX7000: Saving %s image to %ls\n", bufferIndex == 0 ? "back" : "front", dumpPath);
|
||||
|
||||
int ret = WriteDataToBitmapFile(dumpPath, 24, WIDTH, HEIGHT, raw_image, size, metadata, 5, false);
|
||||
|
||||
free(raw_image);
|
||||
|
||||
if (ret < 0) {
|
||||
dprintf("CX7000: WriteDataToBitmapFile returned %d\n", ret);
|
||||
return CX_ERROR_FATAL_3301;
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
const int size = 108;
|
||||
memset(pbyBuffer, 0, size);
|
||||
|
||||
|
||||
if (iPage == 56) {
|
||||
dprintf("CX7000: MediumQuantity\n");
|
||||
|
||||
write_int(pbyBuffer, 8, (int)printer_data.print_counter); // total count
|
||||
write_int(pbyBuffer, 16, 22); // free count
|
||||
write_int(pbyBuffer, 24, 33); // head count
|
||||
write_int(pbyBuffer, 32, (int)printer_data.print_counter_since_clean); // cleaning count
|
||||
write_int(pbyBuffer, 40, 55); // error count
|
||||
write_int(pbyBuffer, 48, 66); // cru cleaning count
|
||||
|
||||
return CX_OK;
|
||||
} else if (iPage == 57) {
|
||||
dprintf("CX7000: Miscellaneous\n");
|
||||
|
||||
write_int(pbyBuffer, 16, 234); // re transfer hr power on time
|
||||
write_int(pbyBuffer, 24, 456); // remedy hr power on time
|
||||
write_int(pbyBuffer, 40, 789); // unresettable re transfer hr power on time
|
||||
write_int(pbyBuffer, 48, 1023); // unresettable remedy hr power on time
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown LogSense\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer) {
|
||||
const int size = 96;
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
memset(pbyBuffer, 0, size);
|
||||
memcpy(pbyBuffer + 32, printer_config.printer_firm_version, 8);
|
||||
memcpy(pbyBuffer + 50, printer_config.printer_camera_version, 8);
|
||||
memcpy(pbyBuffer + 71, printer_config.printer_config_version, 8);
|
||||
memcpy(pbyBuffer + 79, printer_config.printer_table_version, 8);
|
||||
//memcpy(pbyBuffer + 58, printer_config.thermal_head_info, 13); // unused
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer) {
|
||||
dprintf("CX7000: %s(%d, %d)\n", __func__, iPC, iPage);
|
||||
|
||||
const int size = 104;
|
||||
memset(pbyBuffer, 0, size);
|
||||
|
||||
if (iPC == 1 && iPage == 40) { // GetMediaInfo
|
||||
pbyBuffer[51] = 10; // film count (10=100%)
|
||||
pbyBuffer[52] = 50; // ink count (50=100%)
|
||||
return CX_OK;
|
||||
} else if (iPC == 1 && iPage == 35) { // ReadInkInfo
|
||||
pbyBuffer[6] = 0; // "b"
|
||||
write_short(pbyBuffer, 8, 50); // Remain
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown ModeSense\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // intentionally not implemented
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_GetPrintingStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iTestMode, iTestPatten, iTestCount);
|
||||
if (iTestMode == 19) {
|
||||
dprintf("CX7000: Printer Front Buttons Enabled: %d\n", iTestPatten);
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 17) {
|
||||
dprintf("CX7000: Printer was cleaned (haha)\n");
|
||||
printer_data.print_counter_since_clean = 0;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 18) {
|
||||
dprintf("CX7000: Transport Mode enabled\n");
|
||||
printer_data.is_transport = true;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 20) {
|
||||
dprintf("CX7000: Transport Mode disabled\n");
|
||||
printer_data.is_transport = false;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown SendDiagnostic\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_LogSelect(int iSlot, int iID, int iMod) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
const int size = 8;
|
||||
|
||||
memset(buffer, 0, size);
|
||||
buffer[0] = 1 << 2; // IsExist (0 means YES!)
|
||||
buffer[7] = 0; // position (of card; 0 = printer, 1 = "IR")
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_SecurityLock() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_SetPrintingStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_xReadISOMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteISO3TrackMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_PasswordSet() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_GetPrinterStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteProjectCode() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ScanPrinter(int* pSlotId, int* pId) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
if (!printer_config.enable) {
|
||||
return CX_ERROR_NOT_CONNECTED_6804;
|
||||
}
|
||||
|
||||
*pSlotId = 1;
|
||||
*pId = 1;
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_xWriteISOMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ICControl() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iMode, iBufferID, iLength);
|
||||
|
||||
memset(pbyData, 0, iLength);
|
||||
|
||||
if (iMode == 2 && iBufferID == 87 && iLength == 10) {
|
||||
dprintf("CX7000: ReadCondition\n");
|
||||
|
||||
pbyData[0] = printer_data.is_transport; // transport mode
|
||||
pbyData[1] = 0; // head white ink level, unused
|
||||
pbyData[2] = 0; // main white ink level, unused
|
||||
pbyData[3] = 0; // total white ink level, unused
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 112 && iLength == 6) {
|
||||
dprintf("CX7000: GetMacAddress\n");
|
||||
|
||||
pbyData[0] = 0x12; // displays in test menu, else ununused?
|
||||
pbyData[1] = 0x34;
|
||||
pbyData[2] = 0x56;
|
||||
pbyData[3] = 0x78;
|
||||
pbyData[4] = 0x9A;
|
||||
pbyData[5] = 0xBC;
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 82 && iLength == 4) {
|
||||
dprintf("CX7000: GetCleaningWaitCount\n");
|
||||
|
||||
// seemingly unused
|
||||
write_short(pbyData, 0, 0);
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 85 && iLength == 10) {
|
||||
dprintf("CX7000: GetSensorInfo\n");
|
||||
|
||||
pbyData[0] = 244; // retransfer heat roller thermistor; must be over 243
|
||||
pbyData[1] = 0; // main pwb thermistor; unused
|
||||
pbyData[2] = 0; // thermal head thermistor; unused
|
||||
pbyData[3] = 0; // heater cover thermistor; unused
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 88 && iLength == 16) {
|
||||
dprintf("CX7000: ReadErrorStatus\n");
|
||||
|
||||
pbyData[1] = 0; // is door open?
|
||||
//pbyData[2...] = // any of the error codes that fit in a byte (from CX_ERROR_FATAL_3301 to CX_ERROR_PRINT_INTERRUPT_6805_3)
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 224 && iLength == 10) {
|
||||
dprintf("CX7000: ReadCode\n");
|
||||
|
||||
printer_data.print_counter_since_clean++;
|
||||
current_card_id = ++printer_data.print_counter;
|
||||
dprintf("CX7000: Generated new card ID: %lld\n", current_card_id);
|
||||
|
||||
save_printer_data();
|
||||
|
||||
pbyData[0] = current_card_id >> 32; // MSB of card id
|
||||
write_int(pbyData, 1, (int32_t)current_card_id); // lower 4 bytes of card id
|
||||
pbyData[5] = 0x0; // Direction (1 = rotate image by 180 degrees)
|
||||
pbyData[6] = 0x1; // CheckCode (0 = error)
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 144 && iLength == 260) {
|
||||
dprintf("CX7000: ReadErrorLog\n");
|
||||
|
||||
write_int(pbyData, 0, 0); // LogCount
|
||||
/*for (int i = 0; false; i++) { // list of error ids
|
||||
write_int(pbyData, i + 4, 0);
|
||||
}*/
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown ReadBuffer\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_xReadMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset, // NOLINT(*-non-const-parameter)
|
||||
int iLength) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, iMode, iBufferID, iOffset, iLength);
|
||||
if (iMode == 2 && iBufferID == 82 && iLength == 4) {
|
||||
int val = pbyData[0] << 8 | pbyData[1];
|
||||
dprintf("CX7000: Set cleaning limit: %d\n", val);
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown WriteBuffer\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_ReadISO3TrackMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_TestUnitReady(int slotId, int id) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
if (!printer_config.enable) {
|
||||
return CX_ERROR_NOT_CONNECTED_6804;
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static bool __stdcall hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
|
||||
int sizeC) {
|
||||
dprintf("CX7000: %s(%ls)\n", __func__, pFile);
|
||||
|
||||
// stub?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __stdcall hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
|
||||
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iHeight, bPortrait, iAlgorithim);
|
||||
|
||||
// stub?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: these two only exist while we have no decrypted dump of accesscode_dll
|
||||
static int __cdecl hook_init_accesscodekey(BSTR fileName) {
|
||||
dprintf("AccesscodeKey: Init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen) {
|
||||
dprintf("AccesscodeKey: Overwrite Header\n");
|
||||
return 0;
|
||||
}
|
73
common/hooklib/printer_cx.h
Normal file
73
common/hooklib/printer_cx.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define PRINTER_DATA_VERSION 1
|
||||
|
||||
struct printer_cx_config {
|
||||
bool enable;
|
||||
wchar_t printer_out_path[MAX_PATH];
|
||||
wchar_t printer_data_path[MAX_PATH];
|
||||
char printer_firm_version[8];
|
||||
char printer_camera_version[8];
|
||||
char printer_config_version[8];
|
||||
char printer_table_version[8];
|
||||
};
|
||||
|
||||
struct printer_cx_data {
|
||||
uint8_t version;
|
||||
uint64_t print_counter;
|
||||
uint64_t print_counter_since_clean;
|
||||
bool is_transport;
|
||||
};
|
||||
|
||||
enum {
|
||||
CX_OK = 0,
|
||||
CX_ERROR_FATAL_3301 = -1,
|
||||
CX_ERROR_USB_COM_3201 = -2,
|
||||
CX_ERROR_PRINT_INTERRUPT_6805_4 = -4,
|
||||
CX_ERROR_CODE_UNREADABLE_3303 = -5,
|
||||
CX_ERROR_INK_LOW_3202 = -6,
|
||||
CX_ERROR_PRINT_INTERRUPT_6805_3 = -7,
|
||||
CX_ERROR_NO_CARD_6801 = -16961536,
|
||||
CX_ERROR_DOOR_OPEN_6808 = -16961792,
|
||||
CX_ERROR_6831 = -16963328,
|
||||
CX_ERROR_6810 = -16964864,
|
||||
CX_ERROR_CLEAN_PRINTER_3999 = -16973056,
|
||||
CX_ERROR_JAM_6805_1 = -17010688,
|
||||
CX_ERROR_REVERSE_JAM_6805_2 = -17010944,
|
||||
CX_ERROR_CAMERA_JAM_6805_3 = -17011200,
|
||||
CX_ERROR_TRANSPORT_JAM_6805_4 = -17011456,
|
||||
CX_ERROR_PAPER_SENSOR_JAM_6805_5 = -17011712,
|
||||
CX_ERROR_RETRANSFER_JAM_6805_6 = -17011968,
|
||||
CX_ERROR_PAPER_RIPPED_6813_3 = -17015040,
|
||||
CX_ERROR_CODE_READ_6811 = -17018112,
|
||||
CX_ERROR_UNAUTHORIZED_INK_6803_1 = -17018880,
|
||||
CX_ERROR_INK_EMPTY_6813_1 = -17019136,
|
||||
CX_ERROR_PRINT_TIMEOUT_6810_3 = -17056768,
|
||||
CX_ERROR_CAMERA_HARDWARE_FAULT_6810_5 = -17083136,
|
||||
CX_ERROR_CAMERA_COM_6810_6 = -17083392,
|
||||
CX_ERROR_ROLLER_6810_15 = -17088768,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_16 = -17089024,
|
||||
CX_ERROR_POWER_INTERRUPT_6810_1 = -17089280,
|
||||
CX_ERROR_INITIALIZATION_6810_2 = -17094656,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_10 = -17100800,
|
||||
CX_ERROR_RETRANSFER_ROLLER_6810_11 = -17101056,
|
||||
CX_ERROR_THERMOSTAT_6810_12 = -17101312,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_20 = -17101568,
|
||||
CX_ERROR_STRAIGHTEN_ROLLER_6810_21 = -17101824,
|
||||
CX_ERROR_THERMOSTAT_6810_22 = -17102080,
|
||||
CX_ERROR_PRINTER_TOO_COLD_6833_1 = -16971264,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_25 = -17102848,
|
||||
CX_ERROR_CAMERA_NOT_FOUND_6810_7 = -17116672,
|
||||
CX_ERROR_RETRANSFER_ROLL_EMPTY_6802_3 = -21144064,
|
||||
CX_ERROR_INK_ROLL_EMPTY_6802_1 = -21148160,
|
||||
CX_ERROR_NOT_CONNECTED_6804 = -33554432,
|
||||
CX_ERROR_CAMERA_JAM_6805_7 = -17012224,
|
||||
CX_ERROR_INVALID_CLEANING_CARD_6832_1 = -16965376,
|
||||
CX_ERROR_TEMPERATURE_RESOLVED_6833_2 = -16971520,
|
||||
};
|
||||
|
||||
void printer_cx_hook_init(const struct printer_cx_config *cfg, HINSTANCE self);
|
||||
void printer_cx_hook_insert_hooks(HMODULE target);
|
109
common/hooklib/y3-dll.c
Normal file
109
common/hooklib/y3-dll.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "y3.h"
|
||||
#include "y3-dll.h"
|
||||
|
||||
const struct dll_bind_sym y3_dll_syms[] = {
|
||||
{
|
||||
.sym = "y3_io_init",
|
||||
.off = offsetof(struct y3_dll, init),
|
||||
}, {
|
||||
.sym = "y3_io_get_cards",
|
||||
.off = offsetof(struct y3_dll, get_cards),
|
||||
}, {
|
||||
.sym = "y3_io_close",
|
||||
.off = offsetof(struct y3_dll, close),
|
||||
}
|
||||
};
|
||||
|
||||
struct y3_dll y3_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 y3_dll_init(const struct y3_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("Y3: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Y3: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "y3_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
y3_dll.api_version = get_api_version();
|
||||
} else {
|
||||
y3_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose y3_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (y3_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Y3: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
y3_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = y3_dll_syms;
|
||||
hr = dll_bind(&y3_dll, src, &sym, _countof(y3_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Y3: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
19
common/hooklib/y3-dll.h
Normal file
19
common/hooklib/y3-dll.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
|
||||
struct y3_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*close)(void);
|
||||
HRESULT (*get_cards)(struct CardInfo* cards, int* len);
|
||||
};
|
||||
|
||||
extern struct y3_dll y3_dll;
|
||||
|
||||
HRESULT y3_dll_init(const struct y3_dll_config *cfg, HINSTANCE self);
|
631
common/hooklib/y3.c
Normal file
631
common/hooklib/y3.c
Normal file
@ -0,0 +1,631 @@
|
||||
// ReSharper disable CppParameterNeverUsed
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "y3.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "hooklib/y3-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#if _WIN32 || _WIN64
|
||||
#if _WIN64
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#if __GNUC__
|
||||
#if __x86_64__ || __ppc64__
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENV64BIT
|
||||
#define CALL
|
||||
#else
|
||||
#define CALL __cdecl
|
||||
#endif
|
||||
|
||||
float CALL API_DLLVersion();
|
||||
uint32_t CALL API_GetLastError(int* hDevice);
|
||||
uint32_t CALL API_GetErrorMessage(uint32_t errNo, char* szMessage, int numBytes);
|
||||
int* CALL API_Connect(char* szPortName);
|
||||
int CALL API_Close(int* hDevice);
|
||||
int CALL API_Start(int* hDevice);
|
||||
int CALL API_Stop(int* hDevice);
|
||||
float CALL API_GetFirmVersion(int* hDevice);
|
||||
uint32_t CALL API_GetFirmName(int* hDevice);
|
||||
uint32_t CALL API_GetTargetCode(int* hDevice);
|
||||
uint32_t CALL API_GetStatus(int* hDevice);
|
||||
uint32_t CALL API_GetCounter(int* hDevice);
|
||||
int CALL API_ClearError(int* hDevice);
|
||||
int CALL API_Reset(int* hDevice, bool isHardReset);
|
||||
int CALL API_GetCardInfo(int* hDevice, int numCards, struct CardInfo* pCardInfo);
|
||||
int CALL API_GetCardInfoCharSize();
|
||||
int CALL API_FirmwareUpdate(int* hDevice, uint32_t address, uint32_t size, uint8_t* buffer);
|
||||
int CALL API_Calibration(int* hDevice, int calib);
|
||||
int CALL API_GetCalibrationResult(int* hDevice, int calib, uint32_t* result);
|
||||
uint32_t CALL API_GetProcTime(int* hDevice);
|
||||
uint32_t CALL API_GetMemStatus(int* hDevice);
|
||||
uint32_t CALL API_GetMemCounter(int* hDevice);
|
||||
int CALL API_SetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam);
|
||||
int CALL API_GetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam);
|
||||
|
||||
signed int CALL API_SetDevice(int a1, int a2);
|
||||
signed int CALL API_SetCommand(int a1, int a2, int a3, int* a4);
|
||||
signed int CALL API_SetSysControl(int a1, int a2, int* a3);
|
||||
signed int CALL API_GetSysControl(int a1, int a2, int* a3);
|
||||
int CALL API_TestReset(int a1);
|
||||
signed int API_DebugReset(int a1, ...);
|
||||
int CALL API_GetBoardType(int a1);
|
||||
int CALL API_GetCardDataSize(int a1);
|
||||
int CALL API_GetFirmDate(int a1);
|
||||
int API_SystemCommand(int a1, char a2, ...);
|
||||
int CALL API_CalcCheckSum(DWORD* a1, int a2, int a3);
|
||||
int CALL API_GetCheckSumResult(int a1);
|
||||
int CALL API_BlockRead(int a1, int a2, int a3, SIZE_T dwBytes);
|
||||
int CALL API_GetBlockReadResult(int a1, void* a2);
|
||||
int CALL API_BlockWrite(int a1, int a2, int a3, SIZE_T dwBytes, void* a5);
|
||||
signed int CALL API_GetDebugParam(int a1, int a2, DWORD* a3);
|
||||
|
||||
uint32_t convert_string_to_uint(const char* firmName);
|
||||
|
||||
static const struct hook_symbol Y3_hooks[] = {
|
||||
{
|
||||
.name = "API_DLLVersion",
|
||||
.patch = API_DLLVersion,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetLastError",
|
||||
.patch = API_GetLastError,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetErrorMessage",
|
||||
.patch = API_GetErrorMessage,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Connect",
|
||||
.patch = API_Connect,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Close",
|
||||
.patch = API_Close,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Start",
|
||||
.patch = API_Start,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Stop",
|
||||
.patch = API_Stop,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmVersion",
|
||||
.patch = API_GetFirmVersion,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmName",
|
||||
.patch = API_GetFirmName,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetTargetCode",
|
||||
.patch = API_GetTargetCode,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetStatus",
|
||||
.patch = API_GetStatus,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCounter",
|
||||
.patch = API_GetCounter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Reset",
|
||||
.patch = API_Reset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardInfo",
|
||||
.patch = API_GetCardInfo,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardInfoCharSize",
|
||||
.patch = API_GetCardInfoCharSize,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_FirmwareUpdate",
|
||||
.patch = API_FirmwareUpdate,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Calibration",
|
||||
.patch = API_Calibration,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCalibrationResult",
|
||||
.patch = API_GetCalibrationResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetProcTime",
|
||||
.patch = API_GetProcTime,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetMemStatus",
|
||||
.patch = API_GetMemStatus,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetMemCounter",
|
||||
.patch = API_GetMemCounter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetParameter",
|
||||
.patch = API_SetParameter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetParameter",
|
||||
.patch = API_GetParameter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetDevice",
|
||||
.patch = API_SetDevice,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetCommand",
|
||||
.patch = API_SetCommand,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetSysControl",
|
||||
.patch = API_SetSysControl,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetSysControl",
|
||||
.patch = API_GetSysControl,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_TestReset",
|
||||
.patch = API_TestReset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_DebugReset",
|
||||
.patch = API_DebugReset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetBoardType",
|
||||
.patch = API_GetBoardType,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardDataSize",
|
||||
.patch = API_GetCardDataSize,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmDate",
|
||||
.patch = API_GetFirmDate,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SystemCommand",
|
||||
.patch = API_SystemCommand,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_CalcCheckSum",
|
||||
.patch = API_CalcCheckSum,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCheckSumResult",
|
||||
.patch = API_GetCheckSumResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_BlockRead",
|
||||
.patch = API_BlockRead,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetBlockReadResult",
|
||||
.patch = API_GetBlockReadResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_BlockWrite",
|
||||
.patch = API_BlockWrite,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetDebugParam",
|
||||
.patch = API_GetDebugParam,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
static struct y3_config y3_config;
|
||||
|
||||
#define MAX_CARD_SIZE 32
|
||||
static struct CardInfo card_data[MAX_CARD_SIZE];
|
||||
|
||||
static int* Y3_COM_FIELD = (int*)10;
|
||||
static int* Y3_COM_PRINT = (int*)11;
|
||||
|
||||
HRESULT y3_hook_init(const struct y3_config* cfg, HINSTANCE self, const wchar_t* config_filename) {
|
||||
HRESULT hr;
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
memcpy(&y3_config, cfg, sizeof(*cfg));
|
||||
Y3_COM_FIELD = (int*)(uintptr_t)cfg->port_field;
|
||||
Y3_COM_PRINT = (int*)(uintptr_t)cfg->port_printer;
|
||||
|
||||
y3_insert_hooks(NULL);
|
||||
|
||||
memset(card_data, 0, sizeof(card_data));
|
||||
|
||||
struct y3_dll_config config;
|
||||
y3_dll_config_load(&config, config_filename);
|
||||
|
||||
hr = y3_dll_init(&config, self);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("Y3: hook enabled (field port = %d, printer port = %d)\n", cfg->port_field, cfg->port_printer);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void y3_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"Y3CodeReaderNE.dll",
|
||||
Y3_hooks,
|
||||
_countof(Y3_hooks));
|
||||
|
||||
proc_addr_table_push(
|
||||
target,
|
||||
"Y3CodeReaderNE.dll",
|
||||
Y3_hooks,
|
||||
_countof(Y3_hooks));
|
||||
}
|
||||
|
||||
float CALL API_DLLVersion() {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetLastError(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
if (!y3_config.enable) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetErrorMessage(uint32_t errNo, char* szMessage,
|
||||
int numBytes) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
if (!y3_config.enable) {
|
||||
strcpy_s(szMessage, numBytes,
|
||||
"Y3Emu is disabled but emulator DLL is called");
|
||||
} else {
|
||||
strcpy_s(szMessage, numBytes, "No error - Y3Emu");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int* CALL API_Connect(char* szPortName) {
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("Y3: %s(%s)\n", __func__, szPortName);
|
||||
|
||||
if (!y3_config.enable) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char number[2];
|
||||
strncpy(number, szPortName + 3, 2);
|
||||
int* hDevice = (int*)(uintptr_t)atoi(number);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
hr = y3_dll.init();
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Y3: Hook DLL initialization failed: %lx\n", hr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return hDevice;
|
||||
}
|
||||
|
||||
int CALL API_Close(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
y3_dll.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Start(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Stop(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float CALL API_GetFirmVersion(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetFirmName(int* hDevice) {
|
||||
uint32_t result = 0;
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
result = convert_string_to_uint(y3_config.firm_name_field);
|
||||
dprintf("Y3: This device is a FIELD: %s\n", y3_config.firm_name_field);
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
result = convert_string_to_uint(y3_config.firm_name_printer);
|
||||
dprintf("Y3: This device is a PRINTER: %s\n", y3_config.firm_name_printer);
|
||||
} else {
|
||||
dprintf("Y3: This device is UNKNOWN\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetTargetCode(int* hDevice) {
|
||||
uint32_t result = 1162760014;
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
result = convert_string_to_uint(y3_config.target_code_field);
|
||||
dprintf("Y3: This device is a FIELD: %s\n", y3_config.target_code_field);
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
result = convert_string_to_uint(y3_config.target_code_printer);
|
||||
dprintf("Y3: This device is a PRINTER: %s\n", y3_config.target_code_printer);
|
||||
} else {
|
||||
dprintf("Y3: This Y3 device is UNKNOWN\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetStatus(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetCounter(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_ClearError(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Reset(int* hDevice, bool isHardReset) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardInfo(int* hDevice, int numCards, struct CardInfo* pCardInfo) {
|
||||
// dprintf("Y3: %s(%p), %d\n", __func__, hDevice, numCards);
|
||||
// ret = num cards
|
||||
// numCards = max cards
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
|
||||
int cards = numCards;
|
||||
HRESULT hr = y3_dll.get_cards(pCardInfo, &cards);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Y3: DLL returned error when retrieving cards: %lx\n", hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cards;
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
pCardInfo[0].fX = 0;
|
||||
pCardInfo[0].fY = 0;
|
||||
pCardInfo[0].fAngle = 0;
|
||||
pCardInfo[0].eCardType = TYPE0;
|
||||
pCardInfo[0].eCardStatus = MARKER;
|
||||
pCardInfo[0].uID = 0x10;
|
||||
pCardInfo[0].nNumChars = 0;
|
||||
pCardInfo[0].ubChar0.Data = 0;
|
||||
pCardInfo[0].ubChar1.Data = 0x4000;
|
||||
pCardInfo[0].ubChar2.Data = 0;
|
||||
pCardInfo[0].ubChar3.Data = 0x0; // 40
|
||||
pCardInfo[0].ubChar4.Data = 0;
|
||||
pCardInfo[0].ubChar5.Data = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardInfoCharSize() {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_FirmwareUpdate(int* hDevice, uint32_t address, uint32_t size,
|
||||
uint8_t* buffer) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1; // not supported
|
||||
}
|
||||
|
||||
int CALL API_Calibration(int* hDevice, int calib) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CALL API_GetCalibrationResult(int* hDevice, int calib, uint32_t* result) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetProcTime(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetMemStatus(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
uint32_t CALL API_GetMemCounter(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_SetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetDevice(int a1, int a2) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetCommand(int a1, int a2, int a3, int* a4) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetSysControl(int a1, int a2, int* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_GetSysControl(int a1, int a2, int* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_TestReset(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int API_DebugReset(int a1, ...) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetBoardType(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardDataSize(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetFirmDate(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int API_SystemCommand(int a1, char a2, ...) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_CalcCheckSum(DWORD* a1, int a2, int a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCheckSumResult(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_BlockRead(int a1, int a2, int a3, SIZE_T dwBytes) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetBlockReadResult(int a1, void* a2) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_BlockWrite(int a1, int a2, int a3, SIZE_T dwBytes, void* a5) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_GetDebugParam(int a1, int a2, DWORD* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t convert_string_to_uint(const char* firmName) {
|
||||
uint32_t result = 0;
|
||||
|
||||
// Iterate over each character in the string and construct the uint32_t
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result |= (uint32_t)firmName[i] << (i * 8);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
71
common/hooklib/y3.h
Normal file
71
common/hooklib/y3.h
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Value held on a card.
|
||||
struct CardByteData {
|
||||
unsigned int Data;
|
||||
};
|
||||
|
||||
// Unused
|
||||
enum CardType {
|
||||
TYPE0 = 0,
|
||||
TYPE1,
|
||||
TYPE2,
|
||||
TYPE3,
|
||||
TYPE4,
|
||||
TYPE5,
|
||||
TYPE6,
|
||||
TYPE7 = 7
|
||||
};
|
||||
|
||||
enum CardStatus {
|
||||
// Unset entry
|
||||
INVALID = 0,
|
||||
// Valid card
|
||||
VALID = 1,
|
||||
// Not a card but rather infrared interference. Only relevant in test mode.
|
||||
INFERENCE = 2,
|
||||
// This is only used by the printer camera.
|
||||
MARKER = 3
|
||||
};
|
||||
|
||||
struct CardInfo {
|
||||
// X position of the card.
|
||||
float fX; // 0x00|0
|
||||
// Y position of the card.
|
||||
float fY; // 0x04|4
|
||||
// Rotation of the card in degrees >=0.0 && <360.0
|
||||
float fAngle; // 0x08|8
|
||||
// Unused
|
||||
enum CardType eCardType; // 0x0C|12
|
||||
// see enum CardStatus
|
||||
enum CardStatus eCardStatus; // 0x10|16
|
||||
// card's BaseCode. used for a reference to the card being tracked as well as part of the IvCode.
|
||||
unsigned int uID; // 0x14|20
|
||||
// Unused
|
||||
int nNumChars; // 0x18|24
|
||||
// Title Code. Is 8589934592 for EKT.
|
||||
struct CardByteData ubChar0; // 0x1C|28
|
||||
// Must be 0x4000 for the printer camera.
|
||||
struct CardByteData ubChar1; // 0x20|32
|
||||
// Unused
|
||||
struct CardByteData ubChar2; // 0x24|36
|
||||
// Must be 0x0 for the printer camera.
|
||||
struct CardByteData ubChar3; // 0x28|40
|
||||
// Unused
|
||||
struct CardByteData ubChar4; // 0x2C|44
|
||||
// Unused
|
||||
struct CardByteData ubChar5; // 0x30|48
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
HRESULT y3_hook_init(const struct y3_config *cfg, HINSTANCE self, const wchar_t* config_path);
|
||||
|
||||
void y3_insert_hooks(HMODULE target);
|
@ -18,6 +18,7 @@
|
||||
static HRESULT amvideo_reg_read_name(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_port_X(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_resolution_1(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_resolution_2(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_setting(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_use_segatiming(void *bytes, uint32_t *nbytes);
|
||||
|
||||
@ -81,6 +82,10 @@ static const struct reg_hook_val amvideo_reg_mode_vals[] = {
|
||||
.name = L"resolution_1",
|
||||
.read = amvideo_reg_read_resolution_1,
|
||||
.type = REG_SZ,
|
||||
}, {
|
||||
.name = L"resolution_2",
|
||||
.read = amvideo_reg_read_resolution_2,
|
||||
.type = REG_SZ,
|
||||
}, {
|
||||
.name = L"use_segatiming",
|
||||
.read = amvideo_reg_read_use_segatiming,
|
||||
@ -171,6 +176,11 @@ static HRESULT amvideo_reg_read_resolution_1(void *bytes, uint32_t *nbytes)
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"1920x1080");
|
||||
}
|
||||
|
||||
static HRESULT amvideo_reg_read_resolution_2(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"1920x1080");
|
||||
}
|
||||
|
||||
static HRESULT amvideo_reg_read_setting(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"0");
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/config.h"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
@ -23,12 +26,21 @@
|
||||
#include "platform/platform.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/system.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
if (!PathFileExistsW(filename)) {
|
||||
wchar_t temp[MAX_PATH];
|
||||
dprintf("ERROR: Configuration does not exist\n");
|
||||
dprintf(" Configured: \"%ls\"\n", filename);
|
||||
GetFullPathNameW(filename, _countof(temp), temp, NULL);
|
||||
dprintf(" Expanded: \"%ls\"\n", temp);
|
||||
}
|
||||
|
||||
amvideo_config_load(&cfg->amvideo, filename);
|
||||
clock_config_load(&cfg->clock, filename);
|
||||
dns_config_load(&cfg->dns, filename);
|
||||
@ -201,6 +213,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
||||
wchar_t game_id[5];
|
||||
wchar_t platform_id[5];
|
||||
wchar_t subnet[16];
|
||||
wchar_t bcast[16];
|
||||
unsigned int ip[4];
|
||||
size_t i;
|
||||
|
||||
@ -212,6 +225,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
||||
memset(game_id, 0, sizeof(game_id));
|
||||
memset(platform_id, 0, sizeof(platform_id));
|
||||
memset(subnet, 0, sizeof(subnet));
|
||||
memset(bcast, 0, sizeof(bcast));
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"keychip", L"enable", 1, filename);
|
||||
|
||||
@ -255,6 +269,14 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
||||
_countof(subnet),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"netenv",
|
||||
L"broadcast",
|
||||
L"255.255.255.255",
|
||||
bcast,
|
||||
_countof(bcast),
|
||||
filename);
|
||||
|
||||
for (i = 0 ; i < 16 ; i++) {
|
||||
cfg->keychip_id[i] = (char) keychip_id[i];
|
||||
}
|
||||
@ -270,6 +292,9 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
||||
swscanf(subnet, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);
|
||||
cfg->subnet = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | 0;
|
||||
|
||||
swscanf(bcast, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);
|
||||
cfg->bcast = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | (ip[3]);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"keychip",
|
||||
L"billingCa",
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "platform/netenv.h"
|
||||
|
||||
#include "hook/procaddr.h"
|
||||
#include "platform/nusec.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
@ -72,6 +74,14 @@ static uint32_t WINAPI hook_IcmpSendEcho2(
|
||||
uint32_t ReplySize,
|
||||
uint32_t Timeout);
|
||||
|
||||
static int WINAPI hook_sendto(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr *to,
|
||||
int tolen);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static uint32_t (WINAPI *next_GetAdaptersAddresses)(
|
||||
@ -108,6 +118,15 @@ static uint32_t (WINAPI *next_IcmpSendEcho2)(
|
||||
uint32_t ReplySize,
|
||||
uint32_t Timeout);
|
||||
|
||||
static int (WINAPI *next_sendto)(
|
||||
SOCKET s,
|
||||
const char *buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr *to,
|
||||
int tolen);
|
||||
|
||||
|
||||
static const struct hook_symbol netenv_hook_syms[] = {
|
||||
{
|
||||
.name = "GetAdaptersAddresses",
|
||||
@ -132,7 +151,17 @@ static const struct hook_symbol netenv_hook_syms[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct hook_symbol netenv_hook_syms_ws2[] = {
|
||||
{
|
||||
.name = "sendto",
|
||||
.patch = hook_sendto,
|
||||
.ordinal = 20,
|
||||
.link = (void **) &next_sendto
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t netenv_ip_prefix;
|
||||
static uint32_t netenv_ip_bcast;
|
||||
static uint32_t netenv_ip_iface;
|
||||
static uint32_t netenv_ip_router;
|
||||
static uint8_t netenv_mac_addr[6];
|
||||
@ -155,17 +184,34 @@ HRESULT netenv_hook_init(
|
||||
}
|
||||
|
||||
netenv_ip_prefix = kc_cfg->subnet;
|
||||
netenv_ip_bcast = kc_cfg->bcast;
|
||||
netenv_ip_iface = kc_cfg->subnet | cfg->addr_suffix;
|
||||
netenv_ip_router = kc_cfg->subnet | cfg->router_suffix;
|
||||
memcpy(netenv_mac_addr, cfg->mac_addr, sizeof(netenv_mac_addr));
|
||||
|
||||
netenv_hook_apply_hooks(NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void netenv_hook_apply_hooks(HMODULE mod) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
mod,
|
||||
"iphlpapi.dll",
|
||||
netenv_hook_syms,
|
||||
_countof(netenv_hook_syms));
|
||||
|
||||
return S_OK;
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"ws2_32.dll",
|
||||
netenv_hook_syms_ws2,
|
||||
_countof(netenv_hook_syms_ws2));
|
||||
|
||||
proc_addr_table_push(
|
||||
mod,
|
||||
"ws2_32.dll",
|
||||
netenv_hook_syms_ws2,
|
||||
_countof(netenv_hook_syms_ws2));
|
||||
}
|
||||
|
||||
static uint32_t WINAPI hook_GetAdaptersAddresses(
|
||||
@ -506,3 +552,39 @@ static uint32_t WINAPI hook_IcmpSendEcho2(
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int WINAPI hook_sendto(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr* to,
|
||||
int tolen) {
|
||||
if (to->sa_family != AF_INET) {
|
||||
// we only care about IP packets
|
||||
return next_sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
const struct sockaddr_in* original_to = (struct sockaddr_in*)to;
|
||||
|
||||
uint32_t bc_addr = _byteswap_ulong(netenv_ip_prefix | 0xFF);
|
||||
|
||||
if (original_to->sin_addr.S_un.S_addr == bc_addr) {
|
||||
|
||||
uint32_t src_addr = _byteswap_ulong(original_to->sin_addr.S_un.S_addr);
|
||||
uint32_t dest_addr = _byteswap_ulong(netenv_ip_bcast);
|
||||
|
||||
dprintf("Netenv: sendTo broadcast %u.%u.%u.%u -> %u.%u.%u.%u\n",
|
||||
(src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff,
|
||||
(dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff);
|
||||
|
||||
struct sockaddr_in modified_to = {0};
|
||||
memcpy(&modified_to, original_to, tolen);
|
||||
|
||||
modified_to.sin_addr.S_un.S_addr = dest_addr;
|
||||
|
||||
return next_sendto(s, buf, len, flags, (struct sockaddr*)&modified_to, sizeof(modified_to));
|
||||
}
|
||||
|
||||
return next_sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
@ -18,3 +18,4 @@ HRESULT netenv_hook_init(
|
||||
const struct netenv_config *cfg,
|
||||
const struct nusec_config *kc_cfg);
|
||||
|
||||
void netenv_hook_apply_hooks(HMODULE mod);
|
@ -14,6 +14,7 @@ struct nusec_config {
|
||||
uint8_t region;
|
||||
uint8_t system_flag;
|
||||
uint32_t subnet;
|
||||
uint32_t bcast;
|
||||
uint16_t billing_type;
|
||||
wchar_t billing_ca[MAX_PATH];
|
||||
wchar_t billing_pub[MAX_PATH];
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/serial.h"
|
||||
|
68
common/y3io/impl/dummy/y3io.c
Normal file
68
common/y3io/impl/dummy/y3io.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
|
||||
uint16_t y3_io_get_api_version() {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT y3_io_init() {
|
||||
dprintf("Y3 Dummy Cards: initialized\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
memset(pCardInfo, 0, sizeof(struct CardInfo) * *numCards);
|
||||
|
||||
const float paddingX = 86.0f;
|
||||
const float paddingY = 54.0f;
|
||||
|
||||
// Dimensions of the flat panel
|
||||
const float panelHeight = 1232.0f;
|
||||
const float panelWidth = 1160.0f;
|
||||
|
||||
// Number of cards in each row and column
|
||||
const int numRows = 4;
|
||||
const int numCols = 4;
|
||||
int activeCards = numRows * numCols;
|
||||
|
||||
if (*numCards < activeCards) {
|
||||
activeCards = *numCards;
|
||||
}
|
||||
*numCards = activeCards;
|
||||
|
||||
|
||||
// Calculate spacing between cards
|
||||
const float cardWidth = (panelWidth - paddingY * 2) / (numCols - 1);
|
||||
const float cardHeight = (panelHeight - paddingX * 2) / (numRows - 1);
|
||||
|
||||
// Create example card info
|
||||
for (int i = 0; i < activeCards; i++) {
|
||||
int row = i / numCols;
|
||||
int col = i % numCols;
|
||||
|
||||
pCardInfo[i].fX = paddingX + (col * cardHeight);
|
||||
pCardInfo[i].fY = paddingY + (row * cardWidth);
|
||||
pCardInfo[i].fAngle = 0.0f;
|
||||
pCardInfo[i].eCardType = TYPE0;
|
||||
pCardInfo[i].eCardStatus = VALID;
|
||||
pCardInfo[i].uID = 1000 + i;
|
||||
pCardInfo[i].nNumChars = 0;
|
||||
pCardInfo[i].ubChar0.Data = 0;
|
||||
pCardInfo[i].ubChar1.Data = 0;
|
||||
pCardInfo[i].ubChar2.Data = 0;
|
||||
pCardInfo[i].ubChar3.Data = 0;
|
||||
pCardInfo[i].ubChar4.Data = 0;
|
||||
pCardInfo[i].ubChar5.Data = 0;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON_Utils__h
|
||||
#define cJSON_Utils__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
/* Utility for generating patch array entries. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
|
||||
/* Returns 0 for success. */
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
|
||||
//{
|
||||
// cJSON *modme = cJSON_Duplicate(*object, 1);
|
||||
// int error = cJSONUtils_ApplyPatches(modme, patches);
|
||||
// if (!error)
|
||||
// {
|
||||
// cJSON_Delete(*object);
|
||||
// *object = modme;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cJSON_Delete(modme);
|
||||
// }
|
||||
//
|
||||
// return error;
|
||||
//}
|
||||
// Code not added to library since this strategy is a LOT slower.
|
||||
*/
|
||||
|
||||
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
|
||||
/* target will be modified by patch. return value is new ptr for target. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
|
||||
/* generates a patch to move from -> to */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
|
||||
/* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
|
||||
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
39
common/y3io/impl/websockets/config.c
Normal file
39
common/y3io/impl/websockets/config.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void y3ws_config_load(struct y3ws_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"y3ws", L"enable", 1, filename);
|
||||
cfg->debug = GetPrivateProfileIntW(L"y3ws", L"debug", 0, filename);
|
||||
|
||||
cfg->port = GetPrivateProfileIntW(L"y3ws", L"port", 3594, filename);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3ws",
|
||||
L"gameId",
|
||||
L"SDEY",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->game_id, tmpstr, sizeof(cfg->game_id));
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3ws",
|
||||
L"cardDirectory",
|
||||
L"DEVICE\\print",
|
||||
cfg->card_path,
|
||||
_countof(cfg->card_path),
|
||||
filename);
|
||||
}
|
19
common/y3io/impl/websockets/config.h
Normal file
19
common/y3io/impl/websockets/config.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
struct y3ws_config {
|
||||
bool enable;
|
||||
bool debug;
|
||||
|
||||
uint16_t port;
|
||||
char game_id[5];
|
||||
wchar_t card_path[MAX_PATH];
|
||||
};
|
||||
|
||||
void y3ws_config_load(struct y3ws_config *cfg, const wchar_t *filename);
|
352
common/y3io/impl/websockets/y3ws.c
Normal file
352
common/y3io/impl/websockets/y3ws.c
Normal file
@ -0,0 +1,352 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "3rdparty/cjson/cJSON.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "y3ws.h"
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
#include "winwebsocket.h"
|
||||
#include "lib/base64.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
|
||||
static void onopen(struct wws_connection*);
|
||||
static void onclose(struct wws_connection*);
|
||||
static void onmessage(struct wws_connection*, const char*, size_t);
|
||||
static void onlog(const char*, ...);
|
||||
|
||||
#define PROTOCOL_VERSION 1
|
||||
#define GAME_MAX_CARDS 32
|
||||
#define MAX_CARDS 500
|
||||
#define CARD_ID_LEN 5
|
||||
#define OUTPUT_BUFFER_SIZE (1024 * 1024 * 5)
|
||||
|
||||
static struct y3ws_config cfg;
|
||||
|
||||
static bool is_initialized = false;
|
||||
static struct CardInfo card_info[GAME_MAX_CARDS];
|
||||
static int card_info_size = 0;
|
||||
static CRITICAL_SECTION card_info_lock;
|
||||
|
||||
#pragma region y3-dll functions
|
||||
uint16_t y3_io_get_api_version() {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT y3_io_init() {
|
||||
if (is_initialized) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
y3ws_config_load(&cfg, get_config_path());
|
||||
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
InitializeCriticalSection(&card_info_lock);
|
||||
|
||||
wws_set_callbacks(onopen, onclose, onmessage, onlog);
|
||||
wws_set_verbose(cfg.debug);
|
||||
|
||||
HRESULT hr = wws_start(cfg.port);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
dprintf("Y3WS: Started server on port %d\n", cfg.port);
|
||||
if (cfg.debug) {
|
||||
dprintf("Y3WS: WS debug logging is on\n");
|
||||
}
|
||||
is_initialized = true;
|
||||
} else {
|
||||
dprintf("Y3WS: Error starting server: %lx\n", hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
|
||||
HRESULT hr = wws_stop();
|
||||
|
||||
DeleteCriticalSection(&card_info_lock);
|
||||
|
||||
is_initialized = false;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
for (int i = 0; i < card_info_size; i++) {
|
||||
memcpy(&pCardInfo[i], &card_info[i], sizeof(struct CardInfo));
|
||||
}
|
||||
*numCards = card_info_size;
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
return S_OK;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region y3ws functions
|
||||
static void y3ws_make_error_packet(const char* message, char* output_data, size_t* output_size) {
|
||||
dprintf("Y3WS: Error: %s\n", message);
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":false,\"error\":\"%s\"}", PROTOCOL_VERSION, message);
|
||||
}
|
||||
|
||||
static void y3ws_make_success_packet(char* output_data, size_t* output_size) {
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true}", PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
static void y3ws_read_cards(char* output_data, size_t* output_size) {
|
||||
WIN32_FIND_DATAW ffd;
|
||||
|
||||
wchar_t path[MAX_PATH];
|
||||
swprintf(path, MAX_PATH, L"%ls\\*", cfg.card_path);
|
||||
|
||||
HANDLE hFind = FindFirstFileW(path, &ffd);
|
||||
if (INVALID_HANDLE_VALUE == hFind) {
|
||||
dprintf("Y3WS: Failed to access directory: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read from card directory", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON* pversion = cJSON_CreateNumber(PROTOCOL_VERSION);
|
||||
cJSON_AddItemToObject(response, "version", pversion);
|
||||
cJSON* success = cJSON_CreateBool(true);
|
||||
cJSON_AddItemToObject(response, "success", success);
|
||||
cJSON* cards = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(response, "cards", cards);
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
swprintf(path, MAX_PATH, L"%ls\\%ls", cfg.card_path, ffd.cFileName);
|
||||
|
||||
HANDLE hImage = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hImage == INVALID_HANDLE_VALUE) {
|
||||
dprintf("Y3WS: Error opening %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
DWORD ret = SetFilePointer(hImage, -CARD_ID_LEN, NULL, FILE_END);
|
||||
if (ret == INVALID_SET_FILE_POINTER) {
|
||||
dprintf("Y3WS: Error seeking in %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
uint8_t buf[CARD_ID_LEN];
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(hImage, &buf, CARD_ID_LEN, &bytesRead, NULL) || bytesRead != CARD_ID_LEN) {
|
||||
dprintf("Y3WS: Error reading card ID from %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* card = cJSON_CreateObject();
|
||||
cJSON_AddItemToArray(cards, card);
|
||||
|
||||
// cJSON isn't wide...
|
||||
char fpatha[MAX_PATH];
|
||||
size_t fpatha_len = 0;
|
||||
wcstombs_s(&fpatha_len, fpatha, MAX_PATH, ffd.cFileName, MAX_PATH);
|
||||
fpatha[fpatha_len] = 0;
|
||||
|
||||
// ReSharper disable once CppRedundantCastExpression
|
||||
cJSON* path_str = cJSON_CreateString(fpatha);
|
||||
cJSON_AddItemToObject(card, "path", path_str);
|
||||
cJSON* card_id = cJSON_CreateNumber((double)((uint64_t)buf[0] >> 32 | (uint64_t)buf[1] >> 24 | (uint64_t)buf[2] >> 16 | (uint64_t)buf[3] >> 8 | buf[4]));
|
||||
cJSON_AddItemToObject(card, "card_id", card_id);
|
||||
|
||||
} while (FindNextFileW(hFind, &ffd) != 0 && count++ < MAX_CARDS);
|
||||
|
||||
cJSON_PrintPreallocated(response, output_data, (int)*output_size, false);
|
||||
*output_size = strlen(output_data);
|
||||
|
||||
dprintf("Y3WS: Sent %d card(s) to the client\n", count);
|
||||
|
||||
cJSON_Delete(response);
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
static void y3ws_read_card_image(char* file_name, char* output_data, size_t* output_size) {
|
||||
wchar_t path[MAX_PATH];
|
||||
swprintf(path, MAX_PATH, L"%ls\\%hs", cfg.card_path, file_name);
|
||||
|
||||
HANDLE hImage = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hImage == INVALID_HANDLE_VALUE) {
|
||||
dprintf("Y3WS: Failed to access file: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD size = GetFileSize(hImage, NULL);
|
||||
if (size == INVALID_FILE_SIZE) {
|
||||
dprintf("Y3WS: Failed to access file size: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* buf = malloc(size);
|
||||
size_t b64size = ((size * 4) / 3) + (size / 96) + 6;
|
||||
char* b64buf = malloc(b64size);
|
||||
if (buf == NULL) {
|
||||
dprintf("Y3WS: Allocation error for file: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(hImage, buf, size, &bytesRead, NULL) || bytesRead != size) {
|
||||
dprintf("Y3WS: File read failed: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
b64size = base64_encode(buf, size, b64buf);
|
||||
|
||||
if (b64size + 100 > *output_size) {
|
||||
dprintf("Y3WS: Encoded file size exceeds buffer: %ls (%lld / %lld)\n", path, b64size, *output_size);
|
||||
y3ws_make_error_packet("File too large", output_data, output_size);
|
||||
}
|
||||
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true,\"data\":\"%s\"}", PROTOCOL_VERSION, (char*)b64buf);
|
||||
end:
|
||||
free(buf);
|
||||
free(b64buf);
|
||||
}
|
||||
|
||||
static void y3ws_set_cards_from_json(const cJSON* cards, char* output_data, size_t* output_size) {
|
||||
|
||||
const cJSON* card = NULL;
|
||||
card_info_size = 0;
|
||||
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
cJSON_ArrayForEach(card, cards) {
|
||||
cJSON* x = cJSON_GetObjectItemCaseSensitive(card, "x");
|
||||
cJSON* y = cJSON_GetObjectItemCaseSensitive(card, "y");
|
||||
cJSON* r = cJSON_GetObjectItemCaseSensitive(card, "rotation");
|
||||
cJSON* id = cJSON_GetObjectItemCaseSensitive(card, "card_id");
|
||||
|
||||
if (cJSON_IsNumber(x) && cJSON_IsNumber(y) && cJSON_IsNumber(r) && cJSON_IsNumber(id)) {
|
||||
card_info[card_info_size].eCardStatus = VALID;
|
||||
card_info[card_info_size].fX = (float)x->valuedouble;
|
||||
card_info[card_info_size].fY = (float)y->valuedouble;
|
||||
card_info[card_info_size].fAngle = (float)r->valuedouble;
|
||||
card_info[card_info_size].uID = id->valueint;
|
||||
} else {
|
||||
dprintf("Y3WS: Invalid object in card array at index %d\n", card_info_size);
|
||||
}
|
||||
|
||||
if (++card_info_size >= GAME_MAX_CARDS) {
|
||||
dprintf("Y3WS: too many cards specified, truncating!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
y3ws_make_success_packet(output_data, output_size);
|
||||
}
|
||||
|
||||
static void y3ws_handle(const char* input_data, uint32_t input_length, char* output_data, size_t* output_size) {
|
||||
cJSON* json = cJSON_ParseWithLength(input_data, input_length);
|
||||
if (json == NULL) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
|
||||
dprintf("Y3WS: Invalid JSON received!\n");
|
||||
dprintf("Y3WS: Message was: %s\n", input_data);
|
||||
dprintf("Y3WS: Error at: %s\n", error_ptr);
|
||||
}
|
||||
|
||||
const cJSON* ver = cJSON_GetObjectItemCaseSensitive(json, "version");
|
||||
const cJSON* cmd = cJSON_GetObjectItemCaseSensitive(json, "command");
|
||||
|
||||
if (!cJSON_IsNumber(ver) || ver->valueint <= 0) {
|
||||
y3ws_make_error_packet("Missing version attribute", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
if (!cJSON_IsString(cmd)) {
|
||||
y3ws_make_error_packet("Missing command attribute", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
if (ver->valueint != PROTOCOL_VERSION) {
|
||||
y3ws_make_error_packet("Incompatible version", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(cmd->valuestring, "ping") == 0) {
|
||||
y3ws_make_success_packet(output_data, output_size);
|
||||
} else if (strcmp(cmd->valuestring, "get_game_id") == 0) {
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true,\"game_id\":\"%s\"}", PROTOCOL_VERSION, cfg.game_id);
|
||||
} else if (strcmp(cmd->valuestring, "get_cards") == 0) {
|
||||
y3ws_read_cards(output_data, output_size);
|
||||
} else if (strcmp(cmd->valuestring, "get_card_image") == 0) {
|
||||
const cJSON* path = cJSON_GetObjectItemCaseSensitive(json, "path");
|
||||
if (cJSON_IsString(path)) {
|
||||
y3ws_read_card_image(path->valuestring, output_data, output_size);
|
||||
} else {
|
||||
y3ws_make_error_packet("Missing attribute", output_data, output_size);
|
||||
}
|
||||
} else if (strcmp(cmd->valuestring, "set_field") == 0) {
|
||||
const cJSON* cards = cJSON_GetObjectItemCaseSensitive(json, "cards");
|
||||
if (cJSON_IsArray(cards)) {
|
||||
y3ws_set_cards_from_json(cards, output_data, output_size);
|
||||
} else {
|
||||
y3ws_make_error_packet("Missing attribute", output_data, output_size);
|
||||
}
|
||||
} else {
|
||||
y3ws_make_error_packet("Unknown command", output_data, output_size);
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region websocket callbacks
|
||||
|
||||
static void onopen(struct wws_connection* client) {
|
||||
dprintf("Y3WS: Connection opened, addr: %s\n", client->ip_str);
|
||||
}
|
||||
|
||||
static void onclose(struct wws_connection* client) {
|
||||
dprintf("Y3WS: Connection closed, addr: %s\n", client->ip_str);
|
||||
}
|
||||
|
||||
static void onmessage(struct wws_connection* client, const char* msg, size_t size) {
|
||||
if (cfg.debug) {
|
||||
dprintf("Y3WS: Message: %.*s\n", (int)size, msg);
|
||||
}
|
||||
char* out_buf = malloc(OUTPUT_BUFFER_SIZE);
|
||||
if (out_buf == NULL) {
|
||||
dprintf("Y3WS: out of memory for allocating response buffer\n");
|
||||
client->is_connected = false;
|
||||
return;
|
||||
}
|
||||
size_t out_size = OUTPUT_BUFFER_SIZE;
|
||||
|
||||
y3ws_handle(msg, size, out_buf, &out_size);
|
||||
HRESULT hr = wws_send(client, out_buf, out_size);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Y3WS: Error sending message: %lx\n", hr);
|
||||
}
|
||||
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
static void onlog(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
dprintf("Websocket: ");
|
||||
dprintfv(format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
#pragma endregion
|
4
common/y3io/impl/websockets/y3ws.h
Normal file
4
common/y3io/impl/websockets/y3ws.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
31
common/y3io/impl/y3io.h
Normal file
31
common/y3io/impl/y3io.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
/* Get the version of the Y3 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 y3_io_get_api_version();
|
||||
|
||||
/* Initialize the Y3 board. This function will be called before any other
|
||||
y3_io_*() function calls. Errors returned from this function will
|
||||
manifest as a disconnected Y3 board.
|
||||
|
||||
This method may be called multiple times.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
HRESULT y3_io_init();
|
||||
|
||||
/* Fills the given buffer with cards that are detected on the play field.
|
||||
For the values inside CardInfo, see y3.h.
|
||||
The input value of numCards is the size of the pCardInfo array.
|
||||
The output value of numCards is how many cards (>=0) have been set in pCardInfo.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards);
|
25
common/y3io/meson.build
Normal file
25
common/y3io/meson.build
Normal file
@ -0,0 +1,25 @@
|
||||
y3io_lib = static_library(
|
||||
'y3io',
|
||||
name_prefix : '',
|
||||
include_directories: inc,
|
||||
implicit_include_directories : false,
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
cwinwebsocket.get_variable('cws_dep'),
|
||||
],
|
||||
link_with : [
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
'impl/websockets/config.c',
|
||||
'impl/websockets/config.h',
|
||||
'impl/websockets/y3ws.c',
|
||||
'impl/websockets/y3ws.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.h',
|
||||
'impl/y3io.h',
|
||||
],
|
||||
)
|
2
dist/apm3/launch.bat
vendored
2
dist/apm3/launch.bat
vendored
@ -17,8 +17,10 @@ if exist %tmp%\SequenceSetting.json (
|
||||
:BEGIN
|
||||
pushd %~dp0
|
||||
|
||||
set DOORSTOP_DISABLE=TRUE
|
||||
qprocess amdaemon.exe > NUL
|
||||
IF %ERRORLEVEL% NEQ 0 start /min "AM Daemon" inject -d -k apm3hook.dll amdaemon.exe -c daemon_config\common.json daemon_config\server.json config_hook.json
|
||||
set DOORSTOP_DISABLE=
|
||||
|
||||
REM Add "-screen-fullscreen 0 -popupWindow" if you want to run in windowed mode
|
||||
inject -d -k apm3hook.dll APMV3System -logFile output_log.txt
|
||||
|
224
dist/ekt/card_player.html
vendored
Normal file
224
dist/ekt/card_player.html
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
<!-- very basic thing, I can't do UX/CSS/design, don't blame me, I'm a network engineer lmao -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Taisen Card Field</title>
|
||||
</head>
|
||||
<style>
|
||||
html, body {
|
||||
width: 99%;
|
||||
height: 99%;
|
||||
}
|
||||
.playfield {
|
||||
width: 79%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.card_menu {
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
border: 1px solid black;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 200px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
#playfield .card {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#status {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var VERSION = 1;
|
||||
|
||||
var socket;
|
||||
var state = 0;
|
||||
var game_id;
|
||||
var cards = [];
|
||||
var current_card_fetch = 0;
|
||||
|
||||
function send(obj){
|
||||
if (!socket){ return; }
|
||||
var data = JSON.stringify(obj);
|
||||
console.log("Sending: " + data);
|
||||
socket.send(data);
|
||||
}
|
||||
|
||||
function connect(){
|
||||
socket = new WebSocket("ws://127.0.0.1:3594/y3io");
|
||||
|
||||
socket.onopen = function(e) {
|
||||
document.getElementById("status").innerText = "Connected. Loading information...";
|
||||
state = 0;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_game_id"
|
||||
});
|
||||
};
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.log("Received: " + event.data);
|
||||
handle_response(JSON.parse(event.data));
|
||||
};
|
||||
|
||||
socket.onclose = function(event) {
|
||||
state = -1;
|
||||
document.getElementById("status").innerHTML = "Disconnected. <a href='javascript:window.location.reload();'>Reconnect</a>";
|
||||
};
|
||||
|
||||
socket.onerror = function(error) {
|
||||
console.log(error);
|
||||
};
|
||||
}
|
||||
|
||||
function handle_response(obj){
|
||||
if (!obj.success){
|
||||
alert("Error receiving data while in state " + state + ": " + obj.error);
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
if (state == 0){
|
||||
game_id = obj.game_id;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading cards...";
|
||||
state = 1;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_cards"
|
||||
});
|
||||
} else if (state == 1){
|
||||
cards = obj.cards;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading card images...";
|
||||
document.getElementById("cards").innerHTML = "";
|
||||
document.getElementById("playfield").innerHTML = "";
|
||||
current_card_fetch = 0;
|
||||
state = 2;
|
||||
if (cards.length > 0){
|
||||
fetch_next_card();
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". No cards available.";
|
||||
}
|
||||
} else if (state == 2){
|
||||
cards[current_card_fetch].image = obj.data;
|
||||
document.getElementById("cards").innerHTML += "<img class='card' src='data:image/bmp;base64, "+obj.data+"' onclick='spawn_card("+current_card_fetch+");' />";
|
||||
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_next_card(){
|
||||
var p = cards[current_card_fetch].path;
|
||||
if (!p.includes("_front")){
|
||||
current_card_fetch++;
|
||||
fetch_next_card();
|
||||
return;
|
||||
}
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_card_image",
|
||||
path: p
|
||||
});
|
||||
}
|
||||
|
||||
function spawn_card(i){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("playfield").innerHTML += "<img class='card' src='data:image/bmp;base64, "+cards[i].image+"' onmousedown='startMoving(event, this, "+i+");' />";
|
||||
}
|
||||
|
||||
function update_pos(i, x, y){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
var panelHeight = 1272;
|
||||
var panelWidth = 1260;
|
||||
|
||||
cards[i].x = panelHeight - ((y / window.screen.height) * panelHeight);
|
||||
cards[i].y = panelWidth - ((x / window.screen.width) * panelWidth);
|
||||
cards[i].rotation = 0;
|
||||
|
||||
|
||||
var list = [];
|
||||
for (var j = 0; j < cards.length; j++){
|
||||
var c = cards[j];
|
||||
if (c.x && c.y){
|
||||
list.push({
|
||||
card_id: c.card_id,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
rotation: c.rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "set_field",
|
||||
cards: list
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var mousePosition;
|
||||
var offset = [-75,-75];
|
||||
var div;
|
||||
var current_card = -1;
|
||||
var isDown = false;
|
||||
|
||||
function startMoving(e, el, card){
|
||||
div = el;
|
||||
isDown = true;
|
||||
current_card = card;
|
||||
offset = [
|
||||
div.offsetLeft - e.clientX,
|
||||
div.offsetTop - e.clientY
|
||||
];
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', function() {
|
||||
isDown = false;
|
||||
current_card = -1;
|
||||
}, true);
|
||||
|
||||
document.addEventListener('mousemove', function(event) {
|
||||
event.preventDefault();
|
||||
if (isDown) {
|
||||
mousePosition = {
|
||||
|
||||
x : event.clientX,
|
||||
y : event.clientY
|
||||
|
||||
};
|
||||
div.style.left = (mousePosition.x + offset[0]) + 'px';
|
||||
div.style.top = (mousePosition.y + offset[1]) + 'px';
|
||||
update_pos(current_card, event.clientX, event.clientY);
|
||||
}
|
||||
}, true);
|
||||
</script>
|
||||
<body onload="connect();">
|
||||
<div id="playfield" class="playfield">
|
||||
|
||||
</div>
|
||||
<div class="card_menu">
|
||||
<div id="status">Please wait...</div>
|
||||
<div id="cards">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
13
dist/ekt/config_hook.json
vendored
Normal file
13
dist/ekt/config_hook.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"language": "english"
|
||||
},
|
||||
"network": {
|
||||
"property": {
|
||||
"dhcp": true
|
||||
}
|
||||
},
|
||||
"allnet_auth": {
|
||||
"type": "1.0"
|
||||
}
|
||||
}
|
18
dist/ekt/launch_satellite.bat
vendored
Normal file
18
dist/ekt/launch_satellite.bat
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_satellite.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject -d -k ekthook.dll ..\PackageBase\amdaemon.exe -c ..\PackageBase\config_sate.json config_hook.json
|
||||
|
||||
pushd ..\PackageBase\am_capture
|
||||
start "AM Capture" /min AmCapture.exe
|
||||
popd
|
||||
|
||||
inject -d -k ekthook.dll ekt.exe -logfile satellite.log -screen-fullscreen 1 -screen-width 1920 -screen-height 1080 -screen-quality Ultra -silent-crashes
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
13
dist/ekt/launch_terminal.bat
vendored
Normal file
13
dist/ekt/launch_terminal.bat
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_terminal.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject -d -k ekthook.dll ..\PackageBase\amdaemon.exe -c ..\PackageBase\config_terminal.json config_hook.json
|
||||
inject -d -k ekthook.dll ekt.exe -terminal -logfile terminal.log -screen-fullscreen 1 -screen-width 1920 -screen-height 1080 -screen-quality Ultra -silent-crashes
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
179
dist/ekt/segatools_satellite.ini
vendored
Normal file
179
dist/ekt/segatools_satellite.ini
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=ACA2
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
; this to 0 on exactly one machine and set this to 1 on all others.
|
||||
dipsw1=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[unity]
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
[flatPanelReader]
|
||||
; Enable the Y3 board emulation.
|
||||
enable=1
|
||||
|
||||
[y3ws]
|
||||
; Enable the Y3 websocket server.
|
||||
enable=1
|
||||
; Set the TCP port on which the Y3 websocket server runs.
|
||||
port=3594
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
[y3io]
|
||||
; To use a custom Y3 IO DLL enter its path here.
|
||||
; Leave empty if you want to use ... TBA ...
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
menu=0x41
|
||||
start=0x42
|
||||
stratagem=0x43
|
||||
stratagem_lock=0x44
|
||||
hougu=0x45
|
||||
ryuuha=0x46
|
||||
|
||||
tenkey_0=0x60
|
||||
tenkey_1=0x61
|
||||
tenkey_2=0x62
|
||||
tenkey_3=0x63
|
||||
tenkey_4=0x64
|
||||
tenkey_5=0x65
|
||||
tenkey_6=0x66
|
||||
tenkey_7=0x67
|
||||
tenkey_8=0x68
|
||||
tenkey_9=0x69
|
||||
tenkey_clear=0x6E
|
||||
tenkey_enter=0x0D
|
||||
|
||||
vol_up=0x21
|
||||
vol_down=0x22
|
||||
|
||||
trackball_up=0x26
|
||||
trackball_right=0x27
|
||||
trackball_down=0x28
|
||||
trackball_left=0x25
|
||||
speed_modifier=10
|
149
dist/ekt/segatools_terminal.ini
vendored
Normal file
149
dist/ekt/segatools_terminal.ini
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=ACA1
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
; this to 0 on exactly one machine and set this to 1 on all others.
|
||||
dipsw1=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[unity]
|
||||
; Enable Unity hook. This will allow you to run custom .NET code before the game
|
||||
enable=1
|
||||
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
cancel=0x53
|
||||
decide=0x41
|
||||
|
||||
up=0x26
|
||||
right=0x27
|
||||
down=0x28
|
||||
left=0x25
|
||||
|
||||
left_2=0x4F
|
||||
right_2=0x57
|
3
dist/idac/segatools.ini
vendored
3
dist/idac/segatools.ini
vendored
@ -235,6 +235,9 @@ viewChg=2
|
||||
; This is not possible on most devices, so we set the left and right button again.
|
||||
left=7
|
||||
right=8
|
||||
; Additional mapping for up and down buttons in DPad.
|
||||
up=4
|
||||
down=3
|
||||
; Button mappings for the simulated six-speed shifter.
|
||||
shiftDn=6
|
||||
shiftUp=5
|
||||
|
228
dist/sekito/card_player.html
vendored
Normal file
228
dist/sekito/card_player.html
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
<!-- very basic thing, I can't do UX/CSS/design, don't blame me, I'm a network engineer lmao -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Taisen Card Field</title>
|
||||
</head>
|
||||
<style>
|
||||
html, body {
|
||||
width: 99%;
|
||||
height: 99%;
|
||||
}
|
||||
.playfield {
|
||||
width: 79%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.card_menu {
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
border: 1px solid black;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 200px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
#playfield .card {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#status {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var VERSION = 1;
|
||||
|
||||
var socket;
|
||||
var state = 0;
|
||||
var game_id;
|
||||
var cards = [];
|
||||
var current_card_fetch = 0;
|
||||
|
||||
function send(obj){
|
||||
if (!socket){ return; }
|
||||
var data = JSON.stringify(obj);
|
||||
console.log("Sending: " + data);
|
||||
socket.send(data);
|
||||
}
|
||||
|
||||
function connect(){
|
||||
socket = new WebSocket("ws://127.0.0.1:3594/y3io");
|
||||
|
||||
socket.onopen = function(e) {
|
||||
document.getElementById("status").innerText = "Connected. Loading information...";
|
||||
state = 0;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_game_id"
|
||||
});
|
||||
};
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.log("Received: " + event.data);
|
||||
handle_response(JSON.parse(event.data));
|
||||
};
|
||||
|
||||
socket.onclose = function(event) {
|
||||
state = -1;
|
||||
document.getElementById("status").innerHTML = "Disconnected. <a href='javascript:window.location.reload();'>Reconnect</a>";
|
||||
};
|
||||
|
||||
socket.onerror = function(error) {
|
||||
console.log(error);
|
||||
};
|
||||
}
|
||||
|
||||
function handle_response(obj){
|
||||
if (!obj.success){
|
||||
alert("Error receiving data while in state " + state + ": " + obj.error);
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
if (state == 0){
|
||||
game_id = obj.game_id;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading cards...";
|
||||
state = 1;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_cards"
|
||||
});
|
||||
} else if (state == 1){
|
||||
cards = obj.cards;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading card images...";
|
||||
document.getElementById("cards").innerHTML = "";
|
||||
document.getElementById("playfield").innerHTML = "";
|
||||
current_card_fetch = 0;
|
||||
state = 2;
|
||||
if (cards.length > 0){
|
||||
fetch_next_card();
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". No cards available.";
|
||||
}
|
||||
} else if (state == 2){
|
||||
cards[current_card_fetch].image = obj.data;
|
||||
document.getElementById("cards").innerHTML += "<img class='card' src='data:image/bmp;base64, "+obj.data+"' onclick='spawn_card("+current_card_fetch+");' />";
|
||||
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_next_card(){
|
||||
var p = cards[current_card_fetch].path;
|
||||
if (p.includes("holo")){
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
return;
|
||||
}
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_card_image",
|
||||
path: p
|
||||
});
|
||||
}
|
||||
|
||||
function spawn_card(i){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("playfield").innerHTML += "<img class='card' src='data:image/bmp;base64, "+cards[i].image+"' onmousedown='startMoving(event, this, "+i+");' />";
|
||||
}
|
||||
|
||||
function update_pos(i, x, y){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
var panelHeight = 1272;
|
||||
var panelWidth = 1260;
|
||||
|
||||
cards[i].x = panelHeight - ((y / window.screen.height) * panelHeight);
|
||||
cards[i].y = panelWidth - ((x / window.screen.width) * panelWidth);
|
||||
cards[i].rotation = 0;
|
||||
|
||||
|
||||
var list = [];
|
||||
for (var j = 0; j < cards.length; j++){
|
||||
var c = cards[j];
|
||||
if (c.x && c.y){
|
||||
list.push({
|
||||
card_id: c.card_id,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
rotation: c.rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "set_field",
|
||||
cards: list
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var mousePosition;
|
||||
var offset = [-75,-75];
|
||||
var div;
|
||||
var current_card = -1;
|
||||
var isDown = false;
|
||||
|
||||
function startMoving(e, el, card){
|
||||
div = el;
|
||||
isDown = true;
|
||||
current_card = card;
|
||||
offset = [
|
||||
div.offsetLeft - e.clientX,
|
||||
div.offsetTop - e.clientY
|
||||
];
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', function() {
|
||||
isDown = false;
|
||||
current_card = -1;
|
||||
}, true);
|
||||
|
||||
document.addEventListener('mousemove', function(event) {
|
||||
event.preventDefault();
|
||||
if (isDown) {
|
||||
mousePosition = {
|
||||
|
||||
x : event.clientX,
|
||||
y : event.clientY
|
||||
|
||||
};
|
||||
div.style.left = (mousePosition.x + offset[0]) + 'px';
|
||||
div.style.top = (mousePosition.y + offset[1]) + 'px';
|
||||
update_pos(current_card, event.clientX, event.clientY);
|
||||
}
|
||||
}, true);
|
||||
</script>
|
||||
<body onload="connect();">
|
||||
<div id="playfield" class="playfield">
|
||||
|
||||
</div>
|
||||
<div class="card_menu">
|
||||
<div id="status">Please wait...</div>
|
||||
<div id="cards">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
16
dist/sekito/config_hook.json
vendored
Normal file
16
dist/sekito/config_hook.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"common": {
|
||||
"language": "english"
|
||||
},
|
||||
"network": {
|
||||
"property": {
|
||||
"dhcp": true
|
||||
}
|
||||
},
|
||||
"allnet_auth": {
|
||||
"type": "1.0"
|
||||
},
|
||||
"aime": {
|
||||
"firmware_path": []
|
||||
}
|
||||
}
|
15
dist/sekito/launch_satellite.bat
vendored
Normal file
15
dist/sekito/launch_satellite.bat
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_satellite.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject_x64 -d -k sekitohook_x64.dll bin\amdaemon.exe -c bin\config_new.json -c bin\config_video_single.json -c bin\config_video_multi.json -c bin\config_input_sate.json -c bin\config_input_terminal.json -c bin\config_input_terminal_exp.json -c config_hook.json
|
||||
|
||||
inject_x86 -d -k sekitohook_x86.dll bin\appSate.exe
|
||||
|
||||
taskkill /f /im appSate.exe > nul 2>&1
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
19
dist/sekito/launch_terminal.bat
vendored
Normal file
19
dist/sekito/launch_terminal.bat
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_terminal.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject_x64 -d -k sekitohook_x64.dll bin\amdaemon.exe -c bin\config_new.json -c bin\config_video_single.json -c bin\config_video_multi.json -c bin\config_input_sate.json -c bin\config_input_terminal.json -c bin\config_input_terminal_exp.json -c config_hook.json
|
||||
|
||||
call bin\server\server_start.bat
|
||||
|
||||
inject_x86 -d -k sekitohook_x86.dll bin\appTerminal.exe
|
||||
|
||||
taskkill /f /im appTerminal.exe > nul 2>&1
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
call bin\server\server_stop.bat
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
192
dist/sekito/segatools_satellite.ini
vendored
Normal file
192
dist/sekito/segatools_satellite.ini
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=AAV2
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
; this to 0 on exactly one machine and set this to 1 on all others.
|
||||
dipsw1=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[printer]
|
||||
; Sinfonia CHC-C320 printer emulation setting.
|
||||
enable=1
|
||||
; Change the printer serial number here.
|
||||
serial_no="5A-A123"
|
||||
; Insert the path to the image output directory here.
|
||||
printerOutPath="DEVICE\print"
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
[flatPanelReader]
|
||||
; Enable the Y3 board emulation.
|
||||
enable=1
|
||||
|
||||
[y3ws]
|
||||
; Enable the Y3 websocket server.
|
||||
enable=1
|
||||
; Set the TCP port on which the Y3 websocket server runs.
|
||||
port=3594
|
||||
; Game ID used for clients.
|
||||
gameId=SDDD
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
[y3io]
|
||||
; To use a custom Y3 IO DLL enter its path here.
|
||||
; Leave empty if you want to use ... TBA ...
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
menu=0x41
|
||||
start=0x42
|
||||
stratagem=0x43
|
||||
stratagem_lock=0x44
|
||||
hougu=0x45
|
||||
|
||||
tenkey_0=0x60
|
||||
tenkey_1=0x61
|
||||
tenkey_2=0x62
|
||||
tenkey_3=0x63
|
||||
tenkey_4=0x64
|
||||
tenkey_5=0x65
|
||||
tenkey_6=0x66
|
||||
tenkey_7=0x67
|
||||
tenkey_8=0x68
|
||||
tenkey_9=0x69
|
||||
tenkey_clear=0x6E
|
||||
tenkey_enter=0x0D
|
||||
|
||||
trackball_up=0x26
|
||||
trackball_right=0x27
|
||||
trackball_down=0x28
|
||||
trackball_left=0x25
|
||||
speed_modifier=10
|
154
dist/sekito/segatools_terminal.ini
vendored
Normal file
154
dist/sekito/segatools_terminal.ini
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=AAV1
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
; this to 0 on exactly one machine and set this to 1 on all others.
|
||||
dipsw1=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
cancel=0x53
|
||||
decide=0x41
|
||||
reserve=0x45
|
||||
|
||||
up=0x26
|
||||
right=0x27
|
||||
down=0x28
|
||||
left=0x25
|
||||
|
||||
left_2=0x4F
|
||||
right_2=0x57
|
@ -576,6 +576,12 @@ Default: `01:02:03:04:05:06`
|
||||
The MAC address of the virtualized Ethernet adapter. The exact value shouldn't
|
||||
ever matter.
|
||||
|
||||
### `broadcast`
|
||||
|
||||
Default: `255.255.255.255`
|
||||
|
||||
The UDP broadcast address that should be used if packets are being sent to the virtual keychip's subnet. This is used for cab-to-cab communication (Local Play, Satellite to Terminal, etc.). Depending on your network adapters (VPNs etc), sometimes you must explicitely specify your real LANs subnet.
|
||||
|
||||
## `[pcbid]`
|
||||
|
||||
Configure Windows host name virtualization. The ALLS-series platform no longer
|
||||
|
107
doc/config/taisen.md
Normal file
107
doc/config/taisen.md
Normal file
@ -0,0 +1,107 @@
|
||||
# Taisen configuration settings
|
||||
|
||||
This file describes configuration settings specific to the Taisen series.
|
||||
|
||||
Keyboard binding settings use
|
||||
[Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
|
||||
|
||||
## `[ektio]` / `[sekitoio]`
|
||||
|
||||
Controls the input driver.
|
||||
|
||||
### `path`
|
||||
|
||||
Specify a path for a third-party input driver DLL. Default is empty
|
||||
(use built-in keyboard IO emulation).
|
||||
|
||||
## `[flatPanelReader]`
|
||||
|
||||
Controls settings for the Flat Panel (a.k.a. Y3 Board)
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Whether or not to enable Flat Panel emulation. Disable to use a real board.
|
||||
|
||||
### `port_field`
|
||||
|
||||
Default: `10`
|
||||
|
||||
The COM port on which the emulated Flat Panel is connected to. This differs per game.
|
||||
|
||||
### `port_printer`
|
||||
|
||||
Default: `11`
|
||||
|
||||
The COM port on which the emulated Printer Camera is connected to. This only exists in Sangokushi.
|
||||
|
||||
### `dllVersion`
|
||||
|
||||
Default: `1`
|
||||
|
||||
The version of the emulated Y3CodeReader dll. Unsure if that is used anywhere.
|
||||
|
||||
### `firmVersion`
|
||||
|
||||
Default: `1`
|
||||
|
||||
The version of the emulated Y3CodeReader firmware. Unsure if that is used anywhere.
|
||||
|
||||
### `firmNameField`
|
||||
|
||||
Default: `SFPR`
|
||||
|
||||
The device name of the emulated Flat Panel. This should never need changing.
|
||||
|
||||
### `firmNamePrinter`
|
||||
|
||||
Default: `SPRT`
|
||||
|
||||
The device name of the emulated Printer Camera. This should never need changing.
|
||||
|
||||
### `targetCodeField`
|
||||
|
||||
Default: `SFR0`
|
||||
|
||||
The target name of the emulated Flat Panel. This should never need changing.
|
||||
|
||||
### `targetCodePrinter`
|
||||
|
||||
Default: `SPT0`
|
||||
|
||||
The target name of the emulated Printer Camera. This should never need changing.
|
||||
|
||||
## `[y3ws]`
|
||||
|
||||
Settings for the default implementation of setting cards on the Flat Panel remotely via websockets
|
||||
|
||||
### `enable`
|
||||
|
||||
Default: `1`
|
||||
|
||||
Enable the websocket server.
|
||||
|
||||
### `debug`
|
||||
|
||||
Default: `0`
|
||||
|
||||
Makes y3ws I/O very verbose. For debugging only. May lag the game.
|
||||
|
||||
### `port`
|
||||
|
||||
Default: `3594`
|
||||
|
||||
The TCP port the websocket server listens on.
|
||||
|
||||
### `gameId`
|
||||
|
||||
Default: `SDEY`
|
||||
|
||||
The game ID that the websocket server transmits, so clients can change their behaviour based on that (UI, etc.)
|
||||
|
||||
### `cardDirectory`
|
||||
|
||||
Default: `DEVICE\print`
|
||||
|
||||
The directory where printed card images are placed. Should be the same as in `[printer]`.
|
57
doc/y3ws.txt
Normal file
57
doc/y3ws.txt
Normal file
@ -0,0 +1,57 @@
|
||||
Y3WS websocket protocol for card I/O for the Taisen series by Haruka:
|
||||
|
||||
Default listening port: 3594 (san-go-ku-shi)
|
||||
|
||||
All packets are JSON and, unless otherwise specified contain these fields:
|
||||
|
||||
* Requests:
|
||||
{"version": 1, "command": "..."}
|
||||
|
||||
* Responses:
|
||||
{"version": 1, "success": <bool>, "error": <null/string>}
|
||||
|
||||
Commands:
|
||||
|
||||
- ping
|
||||
|
||||
Does nothing except answering with a success response.
|
||||
|
||||
|
||||
- get_game_id
|
||||
|
||||
Extra response fields:
|
||||
- game_id: <string>
|
||||
|
||||
Returns the current game ID that is being run (SDDD, SDGY).
|
||||
|
||||
|
||||
- get_cards
|
||||
|
||||
Extra response fields:
|
||||
- cards: <array of objects>
|
||||
- card_id: <long>
|
||||
- path: <string>
|
||||
|
||||
Returns all cards that the player has in possession.
|
||||
|
||||
|
||||
- get_card_image
|
||||
|
||||
Extra request fields:
|
||||
- path: <string>
|
||||
Extra response fields:
|
||||
- data: <base64 encoded string>
|
||||
|
||||
Returns the card image for the given path (format TBA).
|
||||
|
||||
|
||||
- set_field
|
||||
|
||||
Extra request fields:
|
||||
- array of objects
|
||||
- card_id: <long>
|
||||
- x: <float>
|
||||
- y: <float>
|
||||
- rotation: <float>
|
||||
|
||||
Sets the given cards onto the given positions on the field. Always replaces the entire board.
|
@ -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"
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
107
games/ekthook/config.c
Normal file
107
games/ekthook/config.c
Normal file
@ -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);
|
||||
}
|
37
games/ekthook/config.h
Normal file
37
games/ekthook/config.h
Normal file
@ -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);
|
181
games/ekthook/dllmain.c
Normal file
181
games/ekthook/dllmain.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
"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 <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/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"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
/* 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);
|
||||
}
|
118
games/ekthook/ekt-dll.c
Normal file
118
games/ekthook/ekt-dll.c
Normal file
@ -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;
|
||||
}
|
24
games/ekthook/ekt-dll.h
Normal file
24
games/ekthook/ekt-dll.h
Normal file
@ -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);
|
61
games/ekthook/ekthook.def
Normal file
61
games/ekthook/ekthook.def
Normal file
@ -0,0 +1,61 @@
|
||||
LIBRARY ekthook
|
||||
|
||||
EXPORTS
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
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
|
223
games/ekthook/io4.c
Normal file
223
games/ekthook/io4.c
Normal file
@ -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);
|
||||
|
||||
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;
|
||||
}
|
24
games/ekthook/io4.h
Normal file
24
games/ekthook/io4.h
Normal file
@ -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);
|
31
games/ekthook/meson.build
Normal file
31
games/ekthook/meson.build
Normal file
@ -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',
|
||||
],
|
||||
)
|
10
games/ektio/backend.h
Normal file
10
games/ektio/backend.h
Normal file
@ -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);
|
||||
};
|
77
games/ektio/config.c
Normal file
77
games/ektio/config.c
Normal file
@ -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);
|
||||
}
|
62
games/ektio/config.h
Normal file
62
games/ektio/config.h
Normal file
@ -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);
|
108
games/ektio/ektio.c
Normal file
108
games/ektio/ektio.c
Normal file
@ -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;
|
||||
}
|
106
games/ektio/ektio.h
Normal file
106
games/ektio/ektio.h
Normal file
@ -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);
|
176
games/ektio/keyboard.c
Normal file
176
games/ektio/keyboard.c
Normal file
@ -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;
|
||||
}
|
8
games/ektio/keyboard.h
Normal file
8
games/ektio/keyboard.h
Normal file
@ -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);
|
18
games/ektio/meson.build
Normal file
18
games/ektio/meson.build
Normal file
@ -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");
|
||||
|
@ -60,6 +60,8 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename)
|
||||
cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename);
|
||||
cfg->left = GetPrivateProfileIntW(L"dinput", L"left", 0, filename);
|
||||
cfg->right = GetPrivateProfileIntW(L"dinput", L"right", 0, filename);
|
||||
cfg->up = GetPrivateProfileIntW(L"dinput", L"up", 0, filename);
|
||||
cfg->down = GetPrivateProfileIntW(L"dinput", L"down", 0, filename);
|
||||
cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename);
|
||||
cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename);
|
||||
|
||||
|
@ -18,6 +18,8 @@ struct idac_di_config {
|
||||
uint8_t view_chg;
|
||||
uint8_t left;
|
||||
uint8_t right;
|
||||
uint8_t up;
|
||||
uint8_t down;
|
||||
uint8_t shift_dn;
|
||||
uint8_t shift_up;
|
||||
uint8_t gear[6];
|
||||
|
@ -71,6 +71,8 @@ static uint8_t idac_di_view_chg;
|
||||
static uint8_t idac_di_start;
|
||||
static uint8_t idac_di_left;
|
||||
static uint8_t idac_di_right;
|
||||
static uint8_t idac_di_up;
|
||||
static uint8_t idac_di_down;
|
||||
static uint8_t idac_di_gear[6];
|
||||
static bool idac_di_use_pedals;
|
||||
static bool idac_di_reverse_brake_axis;
|
||||
@ -247,6 +249,16 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (cfg->up > 32) {
|
||||
dprintf("Wheel: Invalid up button: %i\n", cfg->up);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (cfg->down > 32) {
|
||||
dprintf("Wheel: Invalid down button: %i\n", cfg->down);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (cfg->shift_dn > 32) {
|
||||
dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn);
|
||||
|
||||
@ -282,6 +294,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
||||
dprintf("Wheel: View Change button : %i\n", cfg->view_chg);
|
||||
dprintf("Wheel: Left button . . . . : %i\n", cfg->left);
|
||||
dprintf("Wheel: Right button . . . : %i\n", cfg->right);
|
||||
dprintf("Wheel: Up button . . . . . : %i\n", cfg->up);
|
||||
dprintf("Wheel: Down button . . . : %i\n", cfg->down);
|
||||
dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn);
|
||||
dprintf("Wheel: Shift Up button . . : %i\n", cfg->shift_up);
|
||||
dprintf("Wheel: Reverse Brake Axis : %i\n", cfg->reverse_brake_axis);
|
||||
@ -317,6 +331,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg)
|
||||
idac_di_view_chg = cfg->view_chg;
|
||||
idac_di_left = cfg->left;
|
||||
idac_di_right = cfg->right;
|
||||
idac_di_up = cfg->up;
|
||||
idac_di_down = cfg->down;
|
||||
idac_di_shift_dn = cfg->shift_dn;
|
||||
idac_di_shift_up = cfg->shift_up;
|
||||
idac_di_reverse_brake_axis = cfg->reverse_brake_axis;
|
||||
@ -480,6 +496,14 @@ static void idac_di_get_buttons(uint8_t *gamebtn_out)
|
||||
gamebtn |= IDAC_IO_GAMEBTN_RIGHT;
|
||||
}
|
||||
|
||||
if (idac_di_up && state.st.rgbButtons[idac_di_up - 1]) {
|
||||
gamebtn |= IDAC_IO_GAMEBTN_UP;
|
||||
}
|
||||
|
||||
if (idac_di_down && state.st.rgbButtons[idac_di_down - 1]) {
|
||||
gamebtn |= IDAC_IO_GAMEBTN_DOWN;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -65,7 +65,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 */
|
||||
|
112
games/sekitohook/config.c
Normal file
112
games/sekitohook/config.c
Normal file
@ -0,0 +1,112 @@
|
||||
#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);
|
||||
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);
|
||||
}
|
40
games/sekitohook/config.h
Normal file
40
games/sekitohook/config.h
Normal file
@ -0,0 +1,40 @@
|
||||
#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 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);
|
185
games/sekitohook/dllmain.c
Normal file
185
games/sekitohook/dllmain.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
"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 "sekito-dll.h"
|
||||
#include "amex/amex.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/led15093.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 "sekitohook/config.h"
|
||||
#include "sekitohook/jvs.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "hooklib/y3.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)
|
||||
{
|
||||
HRESULT hr;
|
||||
bool is_terminal;
|
||||
|
||||
dprintf("--- Begin sekito_pre_startup ---\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);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&sekito_hook_cfg.aime, 12, 2,
|
||||
sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (is_terminal) {
|
||||
hr = sg_reader_hook_init(&sekito_hook_cfg.aime, 1, 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;
|
||||
}
|
||||
|
||||
hr = amvideo_hook_init(&sekito_hook_cfg.amvideo, sekito_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
258
games/sekitohook/jvs.c
Normal file
258
games/sekitohook/jvs.c
Normal file
@ -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;
|
||||
}
|
18
games/sekitohook/jvs.h
Normal file
18
games/sekitohook/jvs.h
Normal file
@ -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);
|
32
games/sekitohook/meson.build
Normal file
32
games/sekitohook/meson.build
Normal file
@ -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',
|
||||
],
|
||||
)
|
118
games/sekitohook/sekito-dll.c
Normal file
118
games/sekitohook/sekito-dll.c
Normal file
@ -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;
|
||||
}
|
24
games/sekitohook/sekito-dll.h
Normal file
24
games/sekitohook/sekito-dll.h
Normal file
@ -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);
|
65
games/sekitohook/sekitohook.def
Normal file
65
games/sekitohook/sekitohook.def
Normal file
@ -0,0 +1,65 @@
|
||||
LIBRARY sekitohook
|
||||
|
||||
EXPORTS
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
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
|
10
games/sekitoio/backend.h
Normal file
10
games/sekitoio/backend.h
Normal file
@ -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);
|
||||
};
|
74
games/sekitoio/config.c
Normal file
74
games/sekitoio/config.c
Normal file
@ -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);
|
||||
}
|
59
games/sekitoio/config.h
Normal file
59
games/sekitoio/config.h
Normal file
@ -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);
|
168
games/sekitoio/keyboard.c
Normal file
168
games/sekitoio/keyboard.c
Normal file
@ -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;
|
||||
}
|
8
games/sekitoio/keyboard.h
Normal file
8
games/sekitoio/keyboard.h
Normal file
@ -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);
|
18
games/sekitoio/meson.build
Normal file
18
games/sekitoio/meson.build
Normal file
@ -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',
|
||||
],
|
||||
)
|
108
games/sekitoio/sekitoio.c
Normal file
108
games/sekitoio/sekitoio.c
Normal file
@ -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;
|
||||
}
|
104
games/sekitoio/sekitoio.h
Normal file
104
games/sekitoio/sekitoio.h
Normal file
@ -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);
|
@ -97,6 +97,7 @@ bcrypt_lib = cc.find_library('bcrypt')
|
||||
|
||||
inc = include_directories('common', 'games')
|
||||
capnhook = subproject('capnhook')
|
||||
cwinwebsocket = subproject('cwinwebsocket')
|
||||
|
||||
subdir('common/amex')
|
||||
subdir('common/iccard')
|
||||
@ -106,6 +107,7 @@ subdir('common/jvs')
|
||||
subdir('common/platform')
|
||||
subdir('common/util')
|
||||
subdir('common/aimeio')
|
||||
subdir('common/y3io')
|
||||
|
||||
subdir('common/gfxhook')
|
||||
subdir('common/unityhook')
|
||||
@ -125,6 +127,8 @@ subdir('games/tokyoio')
|
||||
subdir('games/fgoio')
|
||||
subdir('games/kemonoio')
|
||||
subdir('games/apm3io')
|
||||
subdir('games/sekitoio')
|
||||
subdir('games/ektio')
|
||||
|
||||
subdir('games/chunihook')
|
||||
subdir('games/divahook')
|
||||
@ -142,3 +146,5 @@ subdir('games/tokyohook')
|
||||
subdir('games/fgohook')
|
||||
subdir('games/kemonohook')
|
||||
subdir('games/apm3hook')
|
||||
subdir('games/ekthook')
|
||||
subdir('games/sekitohook')
|
||||
|
5
subprojects/cwinwebsocket.wrap
Normal file
5
subprojects/cwinwebsocket.wrap
Normal file
@ -0,0 +1,5 @@
|
||||
[wrap-git]
|
||||
directory = cwinwebsocket
|
||||
url = https://github.com/akechi-haruka/cwinwebsocket
|
||||
revision = HEAD
|
||||
|
Reference in New Issue
Block a user