Lots of stuff
This commit is contained in:
parent
50737e6011
commit
3423861c3c
54
Makefile
54
Makefile
@ -1,4 +1,7 @@
|
||||
BUILD_DIR := build
|
||||
BUILD_DIR_32 := $(BUILD_DIR)\build32
|
||||
BUILD_DIR_64 := $(BUILD_DIR)\build64
|
||||
COMMIT := $(shell git rev-parse --short HEAD)
|
||||
DIST_DIR := dist
|
||||
|
||||
BUILD_DRIVE := M:
|
||||
@ -8,19 +11,33 @@ MICE := "$(BUILD_DIR)/src\mice.exe"
|
||||
# VCVARS := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat"
|
||||
|
||||
# For windows XP:
|
||||
VCVARS := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
|
||||
VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
|
||||
VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16
|
||||
|
||||
.ONESHELL:
|
||||
|
||||
.PHONY: all
|
||||
all: mice dist
|
||||
# all: mice mice64 dist
|
||||
|
||||
.PHONY: mice
|
||||
mice:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd /D $(BUILD_DRIVE) \
|
||||
& $(VCVARS) \
|
||||
& meson.py setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR) \
|
||||
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR)
|
||||
& $(VCVARS_32) \
|
||||
& meson.py setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \
|
||||
& meson.py configure -Dmice_version=$(COMMIT) $(BUILD_DRIVE)\$(BUILD_DIR_32) \
|
||||
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
.PHONY: mice64
|
||||
mice64:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd /D $(BUILD_DRIVE) \
|
||||
& $(VCVARS_64) \
|
||||
& meson.py setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \
|
||||
& meson.py configure -Dmice_version=$(COMMIT) $(BUILD_DRIVE)\$(BUILD_DIR_64) -Dwin64=true \
|
||||
& meson.py compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
.PHONY: clean
|
||||
@ -39,21 +56,26 @@ dist:
|
||||
@-mkdir $(DIST_DIR)\Execute\Z > NUL 2>&1
|
||||
@-mkdir $(DIST_DIR)\Execute\S > NUL 2>&1
|
||||
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/micemaster\micemaster.exe" "$(DIST_DIR)/micemaster.exe"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micemaster\micemaster.exe" "$(DIST_DIR)/micemaster.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
|
||||
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice.exe"
|
||||
# @copy /Y "$(BUILD_DIR)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice.pdb"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice.pdb"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice.dll"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice.exe"
|
||||
# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice.dll"
|
||||
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice64.exe" "$(DIST_DIR)/mice64.exe"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice64.pdb" "$(DIST_DIR)/mice64.pdb"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice64.pdb" "$(DIST_DIR)/mice64.pdb"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice64.dll" "$(DIST_DIR)/mice64.dll"
|
||||
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/util\*.exe" "$(DIST_DIR)/util/"
|
||||
@copy /Y "$(BUILD_DIR)/src/micetools/util\*.pdb" "$(DIST_DIR)/util/"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\*.exe" "$(DIST_DIR)/util/"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\*.pdb" "$(DIST_DIR)/util/"
|
||||
|
||||
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
|
||||
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"
|
||||
|
@ -9,4 +9,3 @@ system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
||||
|
||||
|
11
cross-64.ini
Normal file
11
cross-64.ini
Normal file
@ -0,0 +1,11 @@
|
||||
[binaries]
|
||||
c = 'cl'
|
||||
cpp = 'cl'
|
||||
strip = 'cl'
|
||||
ar = ['lib', '/LTCG']
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
40
meson.build
40
meson.build
@ -5,17 +5,38 @@ project('micetools', 'c', default_options: [
|
||||
'warning_level=3',
|
||||
])
|
||||
|
||||
winxp = true
|
||||
subsystem = 'console,5.01'
|
||||
add_global_arguments('-DMICE_VERSION=' + '"' + get_option('mice_version') + '"', language : 'c')
|
||||
|
||||
if get_option('win64')
|
||||
add_project_arguments(
|
||||
'/D_AMD64_',
|
||||
language: 'c',
|
||||
)
|
||||
winxp = false
|
||||
subsystem = 'console'
|
||||
else
|
||||
add_project_arguments(
|
||||
'/D_X86_',
|
||||
language: 'c',
|
||||
)
|
||||
winxp = true
|
||||
subsystem = 'console,5.01'
|
||||
endif
|
||||
|
||||
if (host_machine.cpu_family() == 'x86')
|
||||
add_project_arguments('-DMICE_WIN32', language: 'c')
|
||||
endif
|
||||
|
||||
openssl_inc = include_directories('openssl-1.0.1/include')
|
||||
openssl_lib = meson.get_compiler('c').find_library('libeay32', dirs: [
|
||||
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
|
||||
], required: true)
|
||||
if get_option('win64')
|
||||
openssl_lib = meson.get_compiler('c').find_library('libeay64', dirs: [
|
||||
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
|
||||
], required: true)
|
||||
else
|
||||
openssl_lib = meson.get_compiler('c').find_library('libeay32', dirs: [
|
||||
join_paths(meson.source_root(), 'openssl-1.0.1/lib')
|
||||
], required: true)
|
||||
endif
|
||||
assert(openssl_lib.found(), 'Please download openssl!')
|
||||
|
||||
freeglut_lib = meson.get_compiler('c').find_library('freeglut', dirs: [
|
||||
@ -27,9 +48,13 @@ add_project_link_arguments(
|
||||
'/DYNAMICBASE',
|
||||
'/OPT:REF',
|
||||
'/LTCG',
|
||||
|
||||
'/IGNORE:4099', # no PDBs
|
||||
language: 'c'
|
||||
)
|
||||
add_project_link_arguments(
|
||||
'/IGNORE:4099', # no PDBs
|
||||
language: 'cpp'
|
||||
)
|
||||
add_project_arguments(
|
||||
'/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
|
||||
'/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
|
||||
@ -54,6 +79,9 @@ add_project_arguments(
|
||||
'/we4057', # ... differs in levels of indirection (slightly) from ...
|
||||
'/we4024', # ... different types for formal and actual paramter ...
|
||||
'/we4013', # ... undefined; assuming extern returning int
|
||||
'/we4431', # missing type specifier - int assumed.
|
||||
|
||||
'/W4',
|
||||
|
||||
language: 'c',
|
||||
)
|
||||
|
@ -1 +1,10 @@
|
||||
option('vsenv', type: 'boolean', value: false)
|
||||
option(
|
||||
'win64',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Set this flag when targeting Win64 rather than Win32 (default)'
|
||||
)
|
||||
option(
|
||||
'mice_version',
|
||||
type: 'string',
|
||||
)
|
||||
|
Binary file not shown.
BIN
openssl-1.0.1/lib/libeay64.lib
Normal file
BIN
openssl-1.0.1/lib/libeay64.lib
Normal file
Binary file not shown.
Binary file not shown.
BIN
openssl-1.0.1/lib/ssleay64.lib
Normal file
BIN
openssl-1.0.1/lib/ssleay64.lib
Normal file
Binary file not shown.
@ -1,4 +1,5 @@
|
||||
inih = subproject('inih_dep')
|
||||
detours = subproject('detours')
|
||||
cimgui = subproject('cimgui_dep', default_options: [
|
||||
'win32=enabled',
|
||||
'dx9=enabled',
|
||||
|
@ -20,8 +20,11 @@ typedef struct {
|
||||
} ERROR_LOG_BODY;
|
||||
|
||||
typedef struct {
|
||||
// 0 = Common, 1 = Individual
|
||||
uint8_t ChuteType;
|
||||
// 0 = Common, 1 = Individual
|
||||
uint8_t ServiceType;
|
||||
// 0 = Normal, 1 = Freeplay
|
||||
uint8_t Operation;
|
||||
uint8_t CoinRate[2];
|
||||
uint8_t BonusAdder;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
com_device_t* GetComDevice(HANDLE hFile) {
|
||||
open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE);
|
||||
if (pHData == NULL || pHData->hook == NULL || pHData->hook->com_hook == NULL) return NULL;
|
||||
return pHData->hook->com_hook->com_device;
|
||||
}
|
||||
|
||||
@ -13,18 +14,23 @@ BOOL DevGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TR
|
||||
BOOL DevSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
|
||||
BOOL DevSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
|
||||
BOOL DevPurgeComm(HANDLE hFile, DWORD dwFlags) {
|
||||
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&(GetComDevice(hFile)->out));
|
||||
com_device_t* dev = GetComDevice(hFile);
|
||||
if (dev == NULL) return FALSE;
|
||||
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&(dev->out));
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevGetCommModemStatus(HANDLE hFile, LPDWORD lpModemStatus) {
|
||||
if (!lpModemStatus) return FALSE;
|
||||
com_device_t* dev = GetComDevice(hFile);
|
||||
if (!dev) return false;
|
||||
if (dev == NULL) return FALSE;
|
||||
*lpModemStatus = dev->modemStatus;
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
WaitForSingleObject(GetComDevice(hFile)->dataOutReady, INFINITE);
|
||||
com_device_t* dev = GetComDevice(hFile);
|
||||
if (dev == NULL) return FALSE;
|
||||
|
||||
WaitForSingleObject(dev->dataOutReady, INFINITE);
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
return TRUE;
|
||||
}
|
||||
@ -39,8 +45,12 @@ BOOL DevClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
lpStat->fEof = FALSE;
|
||||
lpStat->fTxim = FALSE;
|
||||
lpStat->fReserved = 0;
|
||||
lpStat->cbInQue = ringbuf_available(&(GetComDevice(hFile)->out));
|
||||
lpStat->cbOutQue = ringbuf_available(&(GetComDevice(hFile)->in));
|
||||
|
||||
com_device_t* dev = GetComDevice(hFile);
|
||||
if (dev == NULL) return FALSE;
|
||||
|
||||
lpStat->cbInQue = ringbuf_available(&dev->out);
|
||||
lpStat->cbOutQue = ringbuf_available(&dev->in);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@ -49,22 +59,28 @@ BOOL DevWriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToW
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToWrite > 0xffff) return FALSE;
|
||||
com_device_t* dev = GetComDevice(ctx->m_Handle);
|
||||
if (dev == NULL) return FALSE;
|
||||
|
||||
// Ignore overflow
|
||||
ringbuf_write(&(dev->in), lpBuffer, nNumberOfBytesToWrite & 0xffff);
|
||||
SetEvent(dev->dataInReady);
|
||||
ringbuf_write(&dev->in, lpBuffer, nNumberOfBytesToWrite & 0xffff);
|
||||
if (!SetEvent(dev->dataInReady))
|
||||
log_error(plfComm, "Failed to signal data in: %d", GetLastError());
|
||||
|
||||
if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToRead > 0xffff) return FALSE;
|
||||
com_device_t* comdev = GetComDevice(ctx->m_Handle);
|
||||
com_device_t* dev = GetComDevice(ctx->m_Handle);
|
||||
if (dev == NULL) return FALSE;
|
||||
|
||||
// Make sure we have at least one byte to return
|
||||
// while (!ringbuf_available(&(comdev->out))) {
|
||||
// WaitForSingleObject(comdev->event, INFINITE);
|
||||
// while (!ringbuf_available(&(dev->out))) {
|
||||
// WaitForSingleObject(dev->event, INFINITE);
|
||||
// }
|
||||
|
||||
short read = ringbuf_read(&(comdev->out), lpBuffer, nNumberOfBytesToRead & 0xffff);
|
||||
short read = ringbuf_read(&dev->out, lpBuffer, nNumberOfBytesToRead & 0xffff);
|
||||
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read;
|
||||
|
||||
if (lpOverlapped) {
|
||||
@ -75,10 +91,7 @@ BOOL DevReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
}
|
||||
|
||||
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes) {
|
||||
while (comdev_available(com) < bytes) {
|
||||
WaitForSingleObject(com->dataInReady, INFINITE);
|
||||
SwitchToThread();
|
||||
}
|
||||
while (comdev_available(com) < bytes) WaitForSingleObject(com->dataInReady, INFINITE);
|
||||
return ringbuf_read(&com->in, buffer, bytes);
|
||||
}
|
||||
short comdev_read(com_device_t* com, LPVOID buffer, short bytes) {
|
||||
@ -94,6 +107,7 @@ BYTE comdev_peek(com_device_t* com) { return com->in.buffer[com->in.read]; }
|
||||
|
||||
// Read data from a com device, unescaping as we go
|
||||
void comio_read(com_device_t* com, LPVOID data, BYTE len) {
|
||||
LPBYTE lpbData = (LPBYTE)data;
|
||||
BYTE one_byte;
|
||||
for (; len; len--) {
|
||||
comdev_read_blocking(com, &one_byte, 1);
|
||||
@ -101,14 +115,15 @@ void comio_read(com_device_t* com, LPVOID data, BYTE len) {
|
||||
comdev_read_blocking(com, &one_byte, 1);
|
||||
one_byte++;
|
||||
}
|
||||
*(((LPBYTE)data)++) = one_byte;
|
||||
*(lpbData++) = one_byte;
|
||||
}
|
||||
}
|
||||
// Write data to a com device, escaping as we go
|
||||
void comio_write(com_device_t* com, LPCVOID data, BYTE len) {
|
||||
LPBYTE lpbData = (LPBYTE)data;
|
||||
BYTE one_byte;
|
||||
for (; len; len--) {
|
||||
one_byte = *(((LPBYTE)data)++);
|
||||
one_byte = *(lpbData++);
|
||||
if (one_byte == COMIO_MARK || one_byte == COMIO_SYNC) {
|
||||
BYTE mark = COMIO_MARK;
|
||||
comdev_write(com, &mark, 1);
|
||||
@ -120,11 +135,7 @@ void comio_write(com_device_t* com, LPCVOID data, BYTE len) {
|
||||
unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, LPVOID data) {
|
||||
BYTE one_byte;
|
||||
do {
|
||||
if (comdev_available(com) < (sizeof *head + 1)) {
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
comdev_read(com, &one_byte, 1);
|
||||
comdev_read_blocking(com, &one_byte, 1);
|
||||
if (one_byte != COMIO_SYNC) {
|
||||
log_error(plfComm, "Garbage on JVS: %02x", one_byte);
|
||||
continue;
|
||||
@ -165,25 +176,31 @@ void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE le
|
||||
comio_write(com, &one_byte, 1);
|
||||
}
|
||||
|
||||
BOOL attach_com_device(BYTE port, FnComDeviceThread* thread) {
|
||||
BOOL attach_com_device(BYTE port, PVIRTUAL_SERIAL_DEVICE lpDevice) {
|
||||
if (port < 1 || port > NUM_COM_PORTS) {
|
||||
log_error(plfComm, "Requested COM%hhu but that is out of range!", port);
|
||||
return FALSE;
|
||||
}
|
||||
com_device_t* com = com_devices[port - 1];
|
||||
|
||||
if (com->thread != INVALID_HANDLE_VALUE) {
|
||||
if (port == RESERVED_JVS_COM_PORT) return FALSE;
|
||||
if (com->thread != NULL) {
|
||||
if (port == RESERVED_JVS_COM_PORT) {
|
||||
log_warning(plfComm, "Refusing to attach to reserved port COM%hhu", port);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// No need to change what's assigned!
|
||||
if (com->thread_worker == thread) return TRUE;
|
||||
|
||||
if (com->lpDevice == lpDevice) return TRUE;
|
||||
log_warning(plfComm, "COM%hhu is already attached!", port);
|
||||
TerminateThread(com->thread, (DWORD)-1);
|
||||
}
|
||||
|
||||
com->thread = CreateThread(NULL, 0, thread, com, 0, NULL);
|
||||
com->thread_worker = thread;
|
||||
com->thread = CreateThread(NULL, 0, lpDevice->m_Entrypoint, com, 0, NULL);
|
||||
if (com->thread == NULL) {
|
||||
log_error(plfComm, "Attach to COM%hhu failed: %d", port, GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
com->lpDevice = lpDevice;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -196,15 +213,15 @@ void detach_com_device(BYTE port) {
|
||||
if (!com->thread) return;
|
||||
|
||||
TerminateThread(com->thread, (DWORD)-1);
|
||||
com->thread = INVALID_HANDLE_VALUE;
|
||||
com->thread = NULL;
|
||||
}
|
||||
void detach_all_com_devices(void) {
|
||||
for (int i = 0; i < NUM_COM_PORTS; i++) {
|
||||
if (i == RESERVED_JVS_COM_PORT - 1) continue;
|
||||
|
||||
if (com_devices[i]->thread != INVALID_HANDLE_VALUE) {
|
||||
if (com_devices[i]->thread != NULL) {
|
||||
TerminateThread(com_devices[i]->thread, (DWORD)-1);
|
||||
com_devices[i]->thread = INVALID_HANDLE_VALUE;
|
||||
com_devices[i]->thread = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,6 +236,8 @@ com_device_t* new_com_device(BYTE port) {
|
||||
file->altFilename = com->wDosName;
|
||||
com_device->com = com;
|
||||
com_device->file = file;
|
||||
com_device->dataInReady = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
com_device->dataOutReady = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
com->GetCommState = DevGetCommState;
|
||||
com->SetCommState = DevSetCommState;
|
||||
@ -235,8 +254,7 @@ com_device_t* new_com_device(BYTE port) {
|
||||
|
||||
ringbuf_purge(&com_device->in);
|
||||
ringbuf_purge(&com_device->out);
|
||||
com_device->dataOutReady = CreateEventW(NULL, TRUE, FALSE, com_device->com->wName);
|
||||
com_device->thread = INVALID_HANDLE_VALUE;
|
||||
com_device->thread = NULL;
|
||||
|
||||
hook_file(file);
|
||||
|
||||
@ -244,7 +262,7 @@ com_device_t* new_com_device(BYTE port) {
|
||||
}
|
||||
|
||||
void init_com_devices(void) {
|
||||
for (BYTE i = 0; i < NUM_COM_PORTS; i++) {
|
||||
for (BYTE i = 1; i < NUM_COM_PORTS; i++) {
|
||||
com_devices[i] = new_com_device(i + 1);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,11 @@
|
||||
typedef struct com_device com_device_t;
|
||||
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
|
||||
|
||||
typedef struct VIRTUAL_SERIAL_DEVICE {
|
||||
LPCSTR m_Name;
|
||||
FnComDeviceThread* m_Entrypoint;
|
||||
} VIRTUAL_SERIAL_DEVICE, *PVIRTUAL_SERIAL_DEVICE;
|
||||
|
||||
struct com_device {
|
||||
com_hook_t* com;
|
||||
file_hook_t* file;
|
||||
@ -18,7 +23,7 @@ struct com_device {
|
||||
HANDLE dataInReady;
|
||||
HANDLE dataOutReady;
|
||||
HANDLE thread;
|
||||
FnComDeviceThread* thread_worker;
|
||||
PVIRTUAL_SERIAL_DEVICE lpDevice;
|
||||
};
|
||||
com_device_t* com_devices[NUM_COM_PORTS];
|
||||
|
||||
@ -60,7 +65,7 @@ unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, LPVOID
|
||||
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, LPCVOID data);
|
||||
|
||||
com_device_t* new_com_device(BYTE port);
|
||||
BOOL attach_com_device(BYTE port, FnComDeviceThread* thread);
|
||||
BOOL attach_com_device(BYTE port, PVIRTUAL_SERIAL_DEVICE thread);
|
||||
void detach_com_device(BYTE port);
|
||||
void detach_all_com_devices(void);
|
||||
void init_com_devices(void);
|
||||
|
@ -23,8 +23,15 @@
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "./util/_util.h"
|
||||
#include "micefs.h"
|
||||
|
||||
void mice_got_game_id(char game_id[4]);
|
||||
#define size2int(x) ((int)((x) & 0x7fffffff))
|
||||
#define size2uint(x) ((unsigned int)((x) & 0xffffffff))
|
||||
|
||||
void _MiceGotGameId(char game_id[4]);
|
||||
BOOL MiceGuessGameId(char* lpGameId);
|
||||
|
||||
extern WCHAR exeName[MAX_PATH + 1];
|
||||
extern DWORD imageOffset;
|
||||
extern size_t imageOffset;
|
||||
|
||||
extern BOOL g_bIsInDllMain;
|
||||
|
@ -6,46 +6,52 @@
|
||||
#include "smb_pca9535.h"
|
||||
|
||||
typedef struct _device_list {
|
||||
const char* m_Name;
|
||||
FnComDeviceThread* m_Thread;
|
||||
VIRTUAL_SERIAL_DEVICE m_Device;
|
||||
struct _device_list* m_Next;
|
||||
} device_list_t;
|
||||
device_list_t device_list = { .m_Next = NULL };
|
||||
|
||||
#define _start_device_n(n) \
|
||||
if (strcmp(MiceConfig.devices.com##n, name) == 0) attach_com_device(n, thread)
|
||||
|
||||
inline void start_device(const char* name, FnComDeviceThread* thread) {
|
||||
_start_device_n(1);
|
||||
_start_device_n(2);
|
||||
_start_device_n(3);
|
||||
_start_device_n(5);
|
||||
_start_device_n(6);
|
||||
_start_device_n(7);
|
||||
_start_device_n(8);
|
||||
static DWORD WINAPI dummy_comdev_thread(com_device_t* dev) {
|
||||
BYTE buffer[1];
|
||||
while (1) {
|
||||
comdev_read_blocking(dev, buffer, 1);
|
||||
log_warning(plfComm, "Idle data on port %ls: %02x", dev->com->wName, buffer[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#define _stop_if_unregistered(n) \
|
||||
if (MiceConfig.devices.com##n[0] == '\0') detach_com_device(n)
|
||||
static VIRTUAL_SERIAL_DEVICE dummySerialDevice = {
|
||||
.m_Name = "Port idler",
|
||||
.m_Entrypoint = dummy_comdev_thread,
|
||||
};
|
||||
|
||||
inline void stop_old_devices() {
|
||||
_stop_if_unregistered(1);
|
||||
_stop_if_unregistered(2);
|
||||
_stop_if_unregistered(3);
|
||||
_stop_if_unregistered(5);
|
||||
_stop_if_unregistered(6);
|
||||
_stop_if_unregistered(7);
|
||||
_stop_if_unregistered(8);
|
||||
inline void start_virtual_device(BYTE bPort, LPCSTR szName) {
|
||||
if (szName[0] != '\0') {
|
||||
device_list_t* device = &device_list;
|
||||
while (device->m_Next) {
|
||||
device = device->m_Next;
|
||||
if (strcmp(szName, device->m_Device.m_Name) == 0) {
|
||||
attach_com_device(bPort, &device->m_Device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log_error(plfComm, "Device %s requested by unknown! (COM%hhu)", szName, bPort);
|
||||
}
|
||||
|
||||
if (MiceConfig.devices.add_idlers)
|
||||
attach_com_device(bPort, &dummySerialDevice);
|
||||
else
|
||||
detach_com_device(bPort);
|
||||
}
|
||||
|
||||
void start_devices() {
|
||||
stop_old_devices();
|
||||
|
||||
device_list_t* device = &device_list;
|
||||
while (device->m_Next) {
|
||||
device = device->m_Next;
|
||||
start_device(device->m_Name, device->m_Thread);
|
||||
}
|
||||
// start_virtual_device(1, MiceConfig.devices.com1);
|
||||
start_virtual_device(2, MiceConfig.devices.com2);
|
||||
start_virtual_device(3, MiceConfig.devices.com3);
|
||||
start_virtual_device(5, MiceConfig.devices.com5);
|
||||
start_virtual_device(6, MiceConfig.devices.com6);
|
||||
start_virtual_device(7, MiceConfig.devices.com7);
|
||||
start_virtual_device(8, MiceConfig.devices.com8);
|
||||
}
|
||||
|
||||
void register_device(const char* name, FnComDeviceThread* thread) {
|
||||
@ -54,8 +60,8 @@ void register_device(const char* name, FnComDeviceThread* thread) {
|
||||
|
||||
device_list_t* us = tail->m_Next = malloc(sizeof(device_list_t));
|
||||
|
||||
us->m_Name = name;
|
||||
us->m_Thread = thread;
|
||||
us->m_Device.m_Name = name;
|
||||
us->m_Device.m_Entrypoint = thread;
|
||||
us->m_Next = NULL;
|
||||
}
|
||||
|
||||
@ -64,8 +70,8 @@ void install_devices() {
|
||||
install_touch_bd();
|
||||
install_aime_bd();
|
||||
install_servo_15069();
|
||||
|
||||
start_devices();
|
||||
install_gacchu_guts_card();
|
||||
install_gacchu_guts_screen();
|
||||
|
||||
smbus_install(/* 0x20 */ PCA9535_ADDRESS, &smbus_PCA9535_write, &smbus_PCA9535_read);
|
||||
|
||||
|
@ -7,6 +7,8 @@ void install_led_bd();
|
||||
void install_touch_bd();
|
||||
void install_aime_bd();
|
||||
void install_servo_15069();
|
||||
void install_gacchu_guts_card();
|
||||
void install_gacchu_guts_screen();
|
||||
|
||||
smbus_callback_t smbus_N2_write;
|
||||
smbus_callback_t smbus_N2_read;
|
||||
|
@ -8,6 +8,8 @@ devices_files = files(
|
||||
'ser_maitouch.c',
|
||||
'ser_tn32msec.c',
|
||||
'ser_servo_838-15069.c',
|
||||
'ser_gacchu_guts_card.c',
|
||||
'ser_gacchu_guts_screen.c',
|
||||
# SMBus devices
|
||||
'smb_pca9535.c',
|
||||
'smb_ds2460.c',
|
||||
|
31
src/micetools/dll/devices/ser_gacchu_guts_card.c
Normal file
31
src/micetools/dll/devices/ser_gacchu_guts_card.c
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Commands in:
|
||||
*
|
||||
* - Length prefix (ie 2)
|
||||
* - Command (ie "C2" or "Z8")
|
||||
* - 0x03
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "_devices.h"
|
||||
|
||||
static DWORD WINAPI ser_gacchu_guts_card(com_device_t* com) {
|
||||
puts("GG CARD");
|
||||
BYTE nBytes;
|
||||
BYTE buffer[256];
|
||||
BYTE tail;
|
||||
while (1) {
|
||||
comdev_read_blocking(com, &nBytes, 1);
|
||||
comdev_read_blocking(com, buffer, nBytes);
|
||||
comdev_read_blocking(com, &tail, 1);
|
||||
|
||||
printf("Got Gacchu command: %.*s\n", nBytes, buffer);
|
||||
BYTE response[1];
|
||||
response[0] = '\0';
|
||||
// comdev_write(com, response, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void install_gacchu_guts_card() { register_device("gacchu_guts_card", ser_gacchu_guts_card); }
|
187
src/micetools/dll/devices/ser_gacchu_guts_screen.c
Normal file
187
src/micetools/dll/devices/ser_gacchu_guts_screen.c
Normal file
@ -0,0 +1,187 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "_devices.h"
|
||||
|
||||
/*
|
||||
Packet format:
|
||||
String packets:
|
||||
[0]: commandNum > 16 ? 0x81 : 0x01
|
||||
[...]: string. does not contain null.
|
||||
[n]: commandNum > 16 ? 0x8d : 0x0d
|
||||
Binary packets:
|
||||
[0]: 0x55
|
||||
[1]:
|
||||
[2]:
|
||||
[3]:
|
||||
[4]:
|
||||
[5]:
|
||||
[6]:
|
||||
[7]: Sum of ([1] through [6]) + 0xAA
|
||||
|
||||
Responses:
|
||||
Type(0) packets:
|
||||
[0]: 0x80 | (if 0x40 set, arg2 = 0x80, else arg2 = 0)
|
||||
[1]: arg0 & 0x7f
|
||||
[2]: (arg0 >> 7) & 0x7f
|
||||
[3]: arg1 & 0x7f
|
||||
[4]: (arg1 >> 7) & 0x7f
|
||||
|
||||
Type(2) packets:
|
||||
[0]: 0x40 | (if 0x02 set, arg2 = 0, else arg2 = 0x80)
|
||||
[1]: arg0 & 0x3f
|
||||
[2]: (arg0 >> 6) & 0x3f
|
||||
[3]: arg1 & 0x3f
|
||||
[4]: (arg1 >> 6) & 0x3f
|
||||
[5]: ???
|
||||
|
||||
Binary packets:
|
||||
// String packets (this seems.. like an impossible contradiction!?):
|
||||
// [0]: 0x01
|
||||
// [1]: 0x0d
|
||||
|
||||
// [0]: 0x55
|
||||
// [1]: 0x54
|
||||
// [...?] -> Buffer length reset to 2. Do these matter?
|
||||
// [9] 0x55
|
||||
// [10] 0x54
|
||||
|
||||
// --- OR ---
|
||||
|
||||
[0]: 0x55
|
||||
[1]: 0x54
|
||||
[2]: if low two bits set (& 3), [7] contains arg2, else arg2=0
|
||||
[3]: arg0 & 0xff
|
||||
[4]: arg0 >> 8
|
||||
[5]: arg1 & 0xff
|
||||
[6]: arg1 >> 8
|
||||
[7]: arg2
|
||||
[8]:
|
||||
[9]: Sum of ([1] through [8]) + 0xAA
|
||||
|
||||
--- OR ---
|
||||
Whatever (005c1edb) is doing
|
||||
From the looks of it, 0x41 is some sort of continuation byte,
|
||||
every 10 bytes.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
FQF[02x: arg0] = 11 (set frequency?)
|
||||
FQF00 = 12 (get frequency?)
|
||||
.5A[02x: touch panel effect][02x: ??] = 16 (set config?)
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
First command received:
|
||||
= Screen command 8
|
||||
[]Z[]
|
||||
01
|
||||
5A
|
||||
0D
|
||||
|
||||
Second command sent:
|
||||
= Screen command 16
|
||||
= ".5A0001"
|
||||
But the last four digits are replaced with "%02X%02X"
|
||||
|
||||
[].5AFF00[]
|
||||
01
|
||||
2E 35 41 46 46 30 30
|
||||
0D
|
||||
|
||||
*/
|
||||
|
||||
static inline void response_ok(com_device_t* lpDev, char* szResponse) {
|
||||
int nBytes = szResponse ? strlen(szResponse) : 0;
|
||||
if (nBytes > 8) nBytes = 8;
|
||||
|
||||
BYTE buffer[10];
|
||||
buffer[0] = 0x01;
|
||||
if (nBytes) memcpy(&buffer[1], szResponse, nBytes);
|
||||
buffer[nBytes + 1] = 0x0d;
|
||||
comdev_write(lpDev, buffer, (nBytes + 2) & 0xffff);
|
||||
}
|
||||
|
||||
static inline void response_two_short(com_device_t* lpDev, SHORT arg0, SHORT arg1) {
|
||||
BYTE buffer[5];
|
||||
buffer[0] = 0x80;
|
||||
buffer[1] = arg0 & 0x7f;
|
||||
buffer[2] = (arg0 >> 7) & 0x7f;
|
||||
buffer[3] = arg1 & 0x7f;
|
||||
buffer[4] = (arg1 >> 7) & 0x7f;
|
||||
comdev_write(lpDev, buffer, 5);
|
||||
}
|
||||
|
||||
static BYTE command_do[4] = {
|
||||
0xd0,
|
||||
0xce,
|
||||
0xb8,
|
||||
0xb1,
|
||||
};
|
||||
|
||||
static DWORD WINAPI ser_gacchu_guts_screen(com_device_t* dev) {
|
||||
BYTE bHead;
|
||||
BYTE buffer[256];
|
||||
puts("Gacchu screen start");
|
||||
while (1) {
|
||||
comdev_read_blocking(dev, &bHead, 1);
|
||||
if (bHead == 0x55) {
|
||||
log_error(plfGacchuGuts, "Screen binary!");
|
||||
comdev_read_blocking(dev, buffer, 7);
|
||||
continue;
|
||||
}
|
||||
if (bHead != 0x01 && bHead != 0x81) {
|
||||
log_error(plfGacchuGuts, "Screen babble: %02x", bHead);
|
||||
continue;
|
||||
}
|
||||
WORD index = 0;
|
||||
BYTE tail = bHead == 0x01 ? 0x0D : 0x8D;
|
||||
do {
|
||||
comdev_read_blocking(dev, &buffer[index++], 1);
|
||||
} while (index < _countof(buffer) && buffer[index - 1] != tail);
|
||||
|
||||
// comdev_read_blocking(dev, buffer, nBytes);
|
||||
// comdev_read_blocking(dev, &tail, 1);
|
||||
|
||||
// Done and working (hopefully!)
|
||||
if (index == 2 && memcmp(buffer, "Z", 1) == 0) {
|
||||
response_ok(dev, "0");
|
||||
}
|
||||
// Not working :(
|
||||
else if (index == 6 && memcmp(buffer, "FQF", 3) == 0) {
|
||||
BYTE value = 0;
|
||||
_snscanf_s((const char*)&buffer[3], 2, "%02hhX", &value);
|
||||
if (value == 0) {
|
||||
log_game(plfGacchuGuts, "Got FQF00 command. What now...?");
|
||||
response_ok(dev, " ");
|
||||
} else {
|
||||
log_game(plfGacchuGuts, "Got FQF[%02x] command. What now...?", value);
|
||||
response_ok(dev, "0"); // Meant to do " " vs "0" I think?
|
||||
}
|
||||
}
|
||||
|
||||
else if (index == 8 && memcmp(buffer, ".5A", 3) == 0) {
|
||||
log_game(plfGacchuGuts, "Got .5A command. What now...?");
|
||||
/*
|
||||
uVar9 = (arg0 * 1024) / (0x4000 - 1)
|
||||
*/
|
||||
|
||||
// At a guess, this is getting the display resolution.
|
||||
response_two_short(dev, 1024, 768);
|
||||
}
|
||||
|
||||
else if (index == 5 && memcmp(buffer, command_do, 4) == 0) {
|
||||
log_game(plfGacchuGuts, "Got D0 command. What now...?");
|
||||
response_ok(dev, "0"); // Probably wrong
|
||||
} else {
|
||||
log_error(plfGacchuGuts, "%ls: Got Gacchu screen: %02x(%d):[%02x]%.*s\n",
|
||||
dev->com->wName, bHead, index, buffer[0], index - 1, buffer);
|
||||
log_error(plfGacchuGuts, "%ls: Got Gacchu bytes: %02x %02x %02x %02x %02x\n",
|
||||
dev->com->wName, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void install_gacchu_guts_screen() { register_device("gacchu_guts_screen", ser_gacchu_guts_screen); }
|
@ -81,12 +81,8 @@ static DWORD WINAPI led_bd_thread(com_device_t* dev) {
|
||||
|
||||
while (1) {
|
||||
rs232c_recv_head_t head;
|
||||
if (comdev_available(dev) < sizeof head) {
|
||||
// Sleep(100);
|
||||
continue;
|
||||
}
|
||||
comdev_read(dev, (unsigned char*)&head, sizeof head);
|
||||
comdev_read(dev, extra, head.length);
|
||||
comdev_read_blocking(dev, (unsigned char*)&head, sizeof head);
|
||||
comdev_read_blocking(dev, extra, head.length);
|
||||
|
||||
// log_info(plfMaiLED, "Bound %02x->%02x", head.src, head.dst);
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
#include "../hooks/gui.h"
|
||||
#include "_devices.h"
|
||||
|
||||
static BYTE read_one(com_device_t* dev) {
|
||||
while (!comdev_available(dev)) Sleep(50);
|
||||
BYTE data;
|
||||
comdev_read(dev, &data, 1);
|
||||
return data;
|
||||
}
|
||||
static BYTE read_one(com_device_t* dev) {}
|
||||
|
||||
const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0";
|
||||
static BYTE get_touch_id(BYTE id) {
|
||||
@ -15,26 +11,130 @@ static BYTE get_touch_id(BYTE id) {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
BOOL touch_is_enabled = false;
|
||||
// High byte: index, Low byte: bitflag
|
||||
#define BUTTON_A1 0x0101
|
||||
#define BUTTON_B1 0x0102
|
||||
#define BUTTON_A2 0x0104
|
||||
#define BUTTON_B2 0x0108
|
||||
#define BUTTON_A3 0x0201
|
||||
#define BUTTON_B3 0x0202
|
||||
#define BUTTON_A4 0x0204
|
||||
#define BUTTON_B4 0x0208
|
||||
#define BUTTON_A5 0x0301
|
||||
#define BUTTON_B5 0x0302
|
||||
#define BUTTON_A6 0x0304
|
||||
#define BUTTON_B6 0x0308
|
||||
#define BUTTON_A7 0x0401
|
||||
#define BUTTON_B7 0x0402
|
||||
#define BUTTON_A8 0x0404
|
||||
#define BUTTON_B8 0x0408
|
||||
#define BUTTON_C 0x0410
|
||||
|
||||
WORD getSensorInRegion(float mX, float mY, float rX, float rY, float rW, float rH) {
|
||||
// Out of region
|
||||
if (mX < rX || mY < rY || mX > rX + rW || mY > rY + rH) return 0;
|
||||
|
||||
// i is now a position in a region from (-1,-1) to (1,1)
|
||||
float iX = ((mX - rX) / (rW / 2)) - 1;
|
||||
float iY = ((mY - rY) / (rH / 2)) - 1;
|
||||
|
||||
float r2 = iX * iX + iY * iY;
|
||||
|
||||
// Bound to a unit circle
|
||||
if (r2 > 1) return 0;
|
||||
|
||||
// Centre button
|
||||
if (r2 < (121.0f / 540.0f) * (121.0f / 540.0f)) return BUTTON_C;
|
||||
|
||||
WORD button = 0;
|
||||
|
||||
// Four quadrants
|
||||
if (iX > 0 && iY < 0) button = -iY > iX ? BUTTON_A1 : BUTTON_A2;
|
||||
if (iX > 0 && iY > 0) button = iX > iY ? BUTTON_A3 : BUTTON_A4;
|
||||
if (iX < 0 && iY > 0) button = iY > -iX ? BUTTON_A5 : BUTTON_A6;
|
||||
if (iX < 0 && iY < 0) button = -iX > -iY ? BUTTON_A7 : BUTTON_A8;
|
||||
|
||||
// Inner ring of buttons
|
||||
if (r2 < (298.0f / 540.0f) * (298.0f / 540.0f))
|
||||
button = (button & 0xff00) | ((button & 0xff) << 1);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
static BYTE g_ActiveResponse[14];
|
||||
static void populateActiveResponse() {
|
||||
// Placeholders
|
||||
g_ActiveResponse[1] = '@';
|
||||
g_ActiveResponse[2] = '@';
|
||||
g_ActiveResponse[3] = '@';
|
||||
g_ActiveResponse[4] = '@';
|
||||
//
|
||||
g_ActiveResponse[7] = '@';
|
||||
g_ActiveResponse[8] = '@';
|
||||
g_ActiveResponse[9] = '@';
|
||||
g_ActiveResponse[10] = '@';
|
||||
|
||||
if (!GetAsyncKeyState(VK_LBUTTON)) return;
|
||||
|
||||
POINT pCursor;
|
||||
GetCursorPos(&pCursor);
|
||||
if (!mainWindow) return;
|
||||
if (!ScreenToClient(mainWindow, &pCursor)) return;
|
||||
|
||||
RECT winRect;
|
||||
if (!GetWindowRect(mainWindow, &winRect)) return;
|
||||
DWORD dwStyle = GetWindowLongW(mainWindow, GWL_STYLE);
|
||||
UnadjustWindowRect(&winRect, dwStyle, FALSE);
|
||||
|
||||
int w = winRect.right - winRect.left;
|
||||
int h = winRect.bottom - winRect.top;
|
||||
|
||||
float x = (float)pCursor.x / (float)(w);
|
||||
float y = (float)pCursor.y / (float)(h);
|
||||
|
||||
// If the window is square, assume `1P_ONLY` is set
|
||||
WORD button;
|
||||
if (w == h) {
|
||||
button = getSensorInRegion(x, y, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
if (button) g_ActiveResponse[button >> 8] |= button & 0xff;
|
||||
} else {
|
||||
// 1P
|
||||
button = getSensorInRegion(x, y, 0.0f, 0.4375f, 0.5f, 0.5625f);
|
||||
if (button) g_ActiveResponse[button >> 8] |= button & 0xff;
|
||||
// 2P
|
||||
button = getSensorInRegion(x, y, 0.5f, 0.4375f, 0.5f, 0.5625f);
|
||||
if (button) g_ActiveResponse[(button >> 8) + 6] |= button & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL touch_is_enabled = TRUE; // Default on is important!
|
||||
BYTE thresh = 0x00; // Lazy caching of single value
|
||||
DWORD WINAPI touch_bd_thread(com_device_t* dev) {
|
||||
log_info(plfMaiTouch, "%ls woke up", dev->com->wName);
|
||||
|
||||
// Constant values
|
||||
g_ActiveResponse[0] = '(';
|
||||
g_ActiveResponse[5] = '@';
|
||||
g_ActiveResponse[6] = '@';
|
||||
g_ActiveResponse[11] = '@';
|
||||
g_ActiveResponse[12] = '@';
|
||||
g_ActiveResponse[13] = ')';
|
||||
|
||||
while (1) {
|
||||
if (touch_is_enabled && !comdev_available(dev)) {
|
||||
// Active mode!
|
||||
comdev_write(dev, (unsigned char*)"(@@@@@@@@@@@@)", 14);
|
||||
Sleep(100);
|
||||
populateActiveResponse();
|
||||
comdev_write(dev, g_ActiveResponse, 14);
|
||||
Sleep(5); // 200Hz should be plenty
|
||||
continue;
|
||||
}
|
||||
|
||||
while (read_one(dev) != '{') continue;
|
||||
while (comdev_available(dev) < 5) {
|
||||
log_info(plfMaiTouch, "<. .>");
|
||||
Sleep(50);
|
||||
}
|
||||
BYTE startWait;
|
||||
do {
|
||||
comdev_read_blocking(dev, &startWait, 1);
|
||||
} while (startWait != '{');
|
||||
|
||||
BYTE command[5];
|
||||
comdev_read(dev, command, 5);
|
||||
comdev_read_blocking(dev, command, 5);
|
||||
BYTE response[6];
|
||||
memcpy(response, "( )", 6);
|
||||
|
||||
|
@ -4,6 +4,53 @@
|
||||
#define SERVO_OK 0
|
||||
#define SERVO_NG 8
|
||||
|
||||
/*
|
||||
|
||||
From AndyGeezer:
|
||||
|
||||
SUD = Sega Universal Drive
|
||||
|
||||
-- sample init code --
|
||||
|
||||
|
||||
ff00007f <-- reset sud
|
||||
81307f4e <-- set init values/reset sud
|
||||
fc00205c <-- init sud
|
||||
|
||||
fd00007d
|
||||
fd00007d <-- poll until not returning 0x44
|
||||
fd00007d
|
||||
|
||||
fa001f65 <-- change echo status to return
|
||||
83600467 <-- set global power
|
||||
86010205 <-- set friction
|
||||
|
||||
move the wheel left/right to centre here..
|
||||
|
||||
|
||||
8800040c <-- set go to target point power
|
||||
f0000070 <-- set target point
|
||||
|
||||
84010005 <-- direction off
|
||||
80000000 <-- motor off
|
||||
|
||||
|
||||
8b2000ff <-- centering power
|
||||
862f00ff <-- friction power
|
||||
800001FF <-- motor on
|
||||
fd00007d <-- poll
|
||||
|
||||
|
||||
|
||||
80<param><param2><crc> = power
|
||||
|
||||
examples:
|
||||
80 00 01 = Constantly on
|
||||
80 01 01 = Run once
|
||||
80 00 00 = Motor off
|
||||
|
||||
*/
|
||||
|
||||
static DWORD WINAPI ser_servo_15069_thread(com_device_t* dev) {
|
||||
log_game(plfServo15069, "%ls woke up", dev->com->wName);
|
||||
|
||||
|
@ -43,7 +43,14 @@ static LPCSTR GetCardIdentifier(DWORD player) {
|
||||
player == 0 ? MiceConfig.aime.player1_cardfile : MiceConfig.aime.player2_cardfile;
|
||||
LPSTR cardIdentifier = player == 0 ? cardIdentifier1P : cardIdentifier2P;
|
||||
|
||||
if (_PathFileExistsA(cardFile)) {
|
||||
const size_t cSize = strlen(cardFile) + 1;
|
||||
wchar_t* wc = malloc(cSize);
|
||||
if (!wc) return NULL;
|
||||
MultiByteToWideChar(0, 0, cardFile, -1, wc, cSize + 1);
|
||||
BOOL exists = FileExistsW(wc);
|
||||
free(wc);
|
||||
|
||||
if (exists) {
|
||||
log_info(plfAime, "Reading P%d card from %s", player + 1, cardFile);
|
||||
|
||||
HANDLE hFile =
|
||||
@ -127,6 +134,13 @@ static CardType TN32GetCardInfo(LPCSTR lpIdentifier, PACCESS_CODE lpAccessCode,
|
||||
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
|
||||
nChars == 23)
|
||||
return CardType_FeliCa;
|
||||
} else if (len == 23) {
|
||||
if (sscanf_s(lpIdentifier, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx%n",
|
||||
&lpFelicaId->m_ID[0], &lpFelicaId->m_ID[1], &lpFelicaId->m_ID[2],
|
||||
&lpFelicaId->m_ID[3], &lpFelicaId->m_ID[4], &lpFelicaId->m_ID[5],
|
||||
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
|
||||
nChars == 23)
|
||||
return CardType_FeliCa;
|
||||
}
|
||||
return CardType_Unknown;
|
||||
}
|
||||
@ -160,8 +174,6 @@ static void MifarePopulate(PNFC_CARD lpCard, PACCESS_CODE lpAccessCode) {
|
||||
DWORD nSerial = AccessCodeToSerial(lpAccessCode);
|
||||
lpCard->m_Mifare.m_Uid = nSerial;
|
||||
|
||||
printf("Serial: %d\n", nSerial);
|
||||
|
||||
// Block 0: Manufacture data (only used by BNG)
|
||||
|
||||
// Block 1: Game ID information (kCARD_DETECT_KEY_B_READ_1)
|
||||
@ -536,8 +548,6 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "../../maiBackupStructs.h"
|
||||
#include "_devices.h"
|
||||
|
||||
#define EEPROM_PATH L"dev/eeprom.bin"
|
||||
#define EEPROM_PATH MiceIpcRelativePath("eeprom.bin")
|
||||
|
||||
#include "../../sysconf.h"
|
||||
|
||||
@ -52,17 +52,21 @@ void set_eeprom_static_config() {
|
||||
}
|
||||
|
||||
void build_eeprom() { // return;
|
||||
log_info(plfEeprom, "Building default EEPROM file");
|
||||
log_misc(plfEeprom, "Building default EEPROM file");
|
||||
|
||||
memset(EEPROM_DATA, 0xff, EEPROM_SIZE);
|
||||
|
||||
set_eeprom_static_config();
|
||||
|
||||
BOOL freeplay = TRUE;
|
||||
AM_SYSDATAwH_CREDIT Credit = {
|
||||
.m_Config = {
|
||||
.ChuteType = 0,
|
||||
.ServiceType = 1,
|
||||
.CreditRate = 1,
|
||||
.Operation = freeplay ? 1 : 0,
|
||||
.CoinRate = { 1, 1 },
|
||||
.BonusAdder = 0,
|
||||
.CreditRate = 1,
|
||||
.Cost = { 1, 1, 1, 1, 1, 1, 1, 1 },
|
||||
},
|
||||
};
|
||||
@ -86,29 +90,17 @@ void build_eeprom() { // return;
|
||||
fix_crc(DevConfig);
|
||||
memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_REG], &DevConfig, sizeof DevConfig);
|
||||
memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_DUP], &DevConfig, sizeof DevConfig);
|
||||
|
||||
// eeprom_dump();
|
||||
}
|
||||
|
||||
AM_SYSDATAwH_HISTORY AmHistory = {
|
||||
// By making the game ID "____" we ensure games overwrite this, letting us see what they write.
|
||||
// This is currently the best way I have found to retrieve the game ID
|
||||
.m_GameId = { '_', '_', '_', '_' },
|
||||
};
|
||||
/** Clobber EEPROM with our user settings */
|
||||
/* Clobber EEPROM with our user settings */
|
||||
void eeprom_fixup() {
|
||||
set_eeprom_static_config();
|
||||
set_eeprom_network_config();
|
||||
|
||||
// AmHistory.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8);
|
||||
// fix_crc(AmHistory);
|
||||
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &AmHistory, sizeof AmHistory);
|
||||
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_DUP], &AmHistory, sizeof AmHistory);
|
||||
}
|
||||
|
||||
void ensure_valid_eeprom() {
|
||||
if (!EEPROM_DATA) {
|
||||
BOOL isNew = !FileExists(EEPROM_PATH);
|
||||
BOOL isNew = !FileExistsA(EEPROM_PATH);
|
||||
|
||||
EEPROM_DATA =
|
||||
open_mapped_file(EEPROM_PATH, EEPROM_SIZE, &EEPROM_FILE, &EEPROM_FILE_MAPPING);
|
||||
@ -140,14 +132,14 @@ void eeprom_write(WORD addr, BYTE* data, BYTE length) {
|
||||
if (addr == AM_SYSDATAwH_HISTORY_REG && length == sizeof(AM_SYSDATAwH_HISTORY)) {
|
||||
PAM_SYSDATAwH_HISTORY pHistory = (PAM_SYSDATAwH_HISTORY)data;
|
||||
|
||||
mice_got_game_id(pHistory->m_GameId);
|
||||
_MiceGotGameId(pHistory->m_GameId);
|
||||
} else if (addr >= 0x1000 && length > 8) {
|
||||
char game_id[4];
|
||||
game_id[0] = data[7];
|
||||
game_id[1] = data[6];
|
||||
game_id[2] = data[5];
|
||||
game_id[3] = data[4];
|
||||
mice_got_game_id(game_id);
|
||||
_MiceGotGameId(game_id);
|
||||
}
|
||||
|
||||
memcpy(EEPROM_DATA + addr, data, length);
|
||||
|
@ -2,6 +2,31 @@
|
||||
|
||||
DWORD NvidiaDebugLevel = 0;
|
||||
|
||||
/* ============= AMD ============= */
|
||||
__declspec(dllexport) int amvGetAvailableDriverEx_Amd(LPVOID pGpuHandle, DWORD dwGpuHandleSize) {
|
||||
return 0;
|
||||
}
|
||||
__declspec(dllexport) int amvGetAvailableDriver_Amd() {
|
||||
return amvGetAvailableDriverEx_Amd(NULL, 4);
|
||||
}
|
||||
__declspec(dllexport) int amvSetCustomDisplaySettingEx_Amd(LPVOID pGpuHandle,
|
||||
DWORD dwGpuHandleSize,
|
||||
LPWORD NV_SetCustomDisplaySetting) {
|
||||
return 0;
|
||||
}
|
||||
__declspec(dllexport) int amvSetCustomDisplaySetting_Amd(LPVOID pGpuHandle) {
|
||||
return amvSetCustomDisplaySettingEx_Amd(NULL, 4, pGpuHandle);
|
||||
}
|
||||
|
||||
__declspec(dllexport) int amvSetDisplayModeEx_Amd(LPVOID pGpuHandle, DWORD dwGpuHandleSize,
|
||||
BYTE displayMode) {
|
||||
return 0;
|
||||
}
|
||||
__declspec(dllexport) int amvSetDisplayMode_Amd(BYTE displayMode) {
|
||||
return amvSetDisplayModeEx_Amd(NULL, 4, displayMode);
|
||||
}
|
||||
|
||||
/* ============= Nvidia ============= */
|
||||
__declspec(dllexport) int amvFinalize_Nvidia() { return 0; }
|
||||
__declspec(dllexport) int amvGetAvailableDriverEx_Nvidia(LPVOID pGpuHandle, DWORD dwGpuHandleSize) {
|
||||
return 0;
|
7
src/micetools/dll/dllStub/ati.c
Normal file
7
src/micetools/dll/dllStub/ati.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <Windows.h>
|
||||
|
||||
// TODO: ATIDL_GetGamma
|
||||
// TODO: ATIDL_SetGamma
|
||||
|
||||
__declspec(dllexport) int ATIDL_GetGamma(int a, void* p) { return 0; }
|
||||
__declspec(dllexport) int ATIDL_SetGamma(int a, void* p) { return 0; }
|
@ -1,3 +1,4 @@
|
||||
#include <detours.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "../lib/util/pid.h"
|
||||
@ -8,54 +9,12 @@
|
||||
|
||||
WCHAR exeName[MAX_PATH + 1];
|
||||
char exeNameC[MAX_PATH + 1];
|
||||
DWORD imageOffset;
|
||||
|
||||
#define WIN32_EXE_BASE 0x00400000
|
||||
|
||||
DWORD GetImageBase(void) {
|
||||
WCHAR sModulePath[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, sModulePath, MAX_PATH);
|
||||
|
||||
HANDLE hObject =
|
||||
_CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hObject == INVALID_HANDLE_VALUE) {
|
||||
log_error(plfBoot, "Failed to open %ls %03x", sModulePath, GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMAGE_DOS_HEADER dosHeader = { 0 };
|
||||
DWORD nRead;
|
||||
_SetFilePointer(hObject, 0, NULL, FILE_BEGIN);
|
||||
_ReadFile(hObject, &dosHeader, sizeof dosHeader, &nRead, NULL);
|
||||
if (nRead != sizeof dosHeader) {
|
||||
log_error(plfBoot, "Failed to read DOS header %03x", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
log_error(plfBoot, "Invalid DOS magic number: %04x", dosHeader.e_magic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS32 ntHeaders32 = { 0 };
|
||||
_SetFilePointer(hObject, dosHeader.e_lfanew, NULL, FILE_BEGIN);
|
||||
_ReadFile(hObject, &ntHeaders32, sizeof ntHeaders32, &nRead, NULL);
|
||||
if (nRead != sizeof ntHeaders32) {
|
||||
log_error(plfBoot, "Failed to read NT header %03x", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) {
|
||||
log_error(plfBoot, "Invalid NT signature: %08x", ntHeaders32.Signature);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_CloseHandle(hObject);
|
||||
return ntHeaders32.OptionalHeader.ImageBase;
|
||||
}
|
||||
size_t imageOffset;
|
||||
|
||||
void apply_patches(HMODULE hModule) {
|
||||
void* baseAddress = (void*)hModule;
|
||||
|
||||
DWORD imageBase = GetImageBase();
|
||||
DWORD imageBase = MiceGetImageBase();
|
||||
if (imageBase == 0) {
|
||||
log_error(plfBoot, "Failed to locate image base. Patches will not be applied.");
|
||||
return;
|
||||
@ -69,22 +28,22 @@ void apply_patches(HMODULE hModule) {
|
||||
|
||||
patch_t* patch = patch_list->next;
|
||||
if (patch == NULL) {
|
||||
log_warning(plfBoot, "No patches to apply. Did you forgot an amiDebug patch file?");
|
||||
log_info(plfBoot, "No patches to apply. Skipping.");
|
||||
return;
|
||||
}
|
||||
while (patch) {
|
||||
DWORD oldProt;
|
||||
VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count,
|
||||
PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
VirtualProtect((void*)(patch->address + imageOffset), patch->count, PAGE_EXECUTE_READWRITE,
|
||||
&oldProt);
|
||||
|
||||
if (memcmp(patch->match, (void*)((DWORD)patch->address + imageOffset), patch->count) != 0) {
|
||||
if (memcmp(patch->match, (void*)(patch->address + imageOffset), patch->count) != 0) {
|
||||
log_error(plfBoot, "Patch %s failed! from-value missmatch", patch->name);
|
||||
VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count, oldProt,
|
||||
&oldProt);
|
||||
VirtualProtect((void*)(patch->address + imageOffset), patch->count, oldProt, &oldProt);
|
||||
patch = patch->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy((void*)((DWORD)patch->address + imageOffset), patch->replace, patch->count);
|
||||
memcpy((void*)(patch->address + imageOffset), patch->replace, patch->count);
|
||||
log_misc(plfBoot, "Patched %d bytes at %08x (%s)", patch->count, patch->address,
|
||||
patch->name);
|
||||
|
||||
@ -111,39 +70,48 @@ void init_injection(HMODULE hModule) {
|
||||
log_info(plfBoot, "Handover complete. Now executing within %ls", exeName);
|
||||
|
||||
// Start Mice FS
|
||||
BOOL success = TRUE;
|
||||
success &= MiceFSInit();
|
||||
if (success) success &= MiceFSAddRingedgeLayers(FALSE);
|
||||
if (!success) {
|
||||
if (!MiceFSInit()) {
|
||||
log_error(plfFile, "Failed to initialise Mice FS stack: %d", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (MiceConfig.mice.original && MiceConfig.mice.original[0] == '\0') {
|
||||
CHAR szCurrentDir[MAX_PATH + 1];
|
||||
GetCurrentDirectoryA(sizeof szCurrentDir, szCurrentDir);
|
||||
MiceFSAddLayer(RING_MOUNT_ORIGINAL, szCurrentDir);
|
||||
MiceFSAddLayer(RING_MOUNT_GAME, szCurrentDir);
|
||||
BOOL success = TRUE;
|
||||
success &= MiceFSAddDevLayers();
|
||||
|
||||
CHAR szWorkPath[MAX_PATH + 1];
|
||||
if (!MiceConfig.mice.original || MiceConfig.mice.original[0] == '\0') {
|
||||
_GetCurrentDirectoryA(sizeof szWorkPath, szWorkPath);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, szWorkPath);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, szWorkPath);
|
||||
} else {
|
||||
MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceConfig.mice.original);
|
||||
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.original);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceConfig.mice.original);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.original);
|
||||
}
|
||||
if (MiceConfig.mice.patch && MiceConfig.mice.patch[0] != '\0') {
|
||||
MiceFSAddLayer(RING_MOUNT_PATCH, MiceConfig.mice.patch);
|
||||
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.patch);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_PATCH, MiceConfig.mice.patch);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.patch);
|
||||
}
|
||||
if (MiceConfig.mice.extend && MiceConfig.mice.extend[0] != '\0') {
|
||||
MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, MiceConfig.mice.extend);
|
||||
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, MiceConfig.mice.extend);
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend);
|
||||
}
|
||||
if (MiceConfig.mice.extend2 && MiceConfig.mice.extend2[0] != '\0') {
|
||||
MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, MiceConfig.mice.extend2);
|
||||
MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend2);
|
||||
}
|
||||
|
||||
if (success) success &= MiceFSAddDevLayers();
|
||||
success &= MiceFSAddRingedgeLayers(FALSE);
|
||||
|
||||
MiceFSSetCwd(RING_MOUNT_GAME "\\");
|
||||
if (!success) {
|
||||
log_error(plfFile, "Failed to add Mice FS layers: %d", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
szWorkPath[0] = '\0';
|
||||
strcat_s(szWorkPath, sizeof szWorkPath, RING_MOUNT_GAME "\\");
|
||||
if (_miceIpcData && _miceIpcData->m_LauncherIsReady)
|
||||
strcat_s(szWorkPath, sizeof szWorkPath, _miceIpcData->m_PathPrefix);
|
||||
MiceFSSetCwd(szWorkPath);
|
||||
|
||||
// Setup default COM devices
|
||||
init_com_devices();
|
||||
@ -158,7 +126,10 @@ void init_injection(HMODULE hModule) {
|
||||
// MX SuperIO: Communicate with the HW monitor chip
|
||||
if (MiceConfig.drivers.mxsuperio) setup_mxsuperio();
|
||||
// MX JVS: Interacting with JVS-based devices
|
||||
if (MiceConfig.drivers.mxjvs) setup_mxjvs();
|
||||
if (MiceConfig.drivers.mxjvs) {
|
||||
setup_mxjvs();
|
||||
load_keybind_config();
|
||||
}
|
||||
// MX HW Reset: Forcibly reboot the machine
|
||||
if (MiceConfig.drivers.mxhwreset) setup_mxhwreset();
|
||||
// MX SMBus: Communicate over the LPC bus. This contains the EEPROM, and PCA9535
|
||||
@ -177,23 +148,9 @@ void init_injection(HMODULE hModule) {
|
||||
// Must be the last thing called!
|
||||
prebind_hooks();
|
||||
|
||||
// TODO: Figure out why we're needing to call this manually (medium priority)
|
||||
if (wcscmp(exeName, L"ALLNetProc.exe") == 0) {
|
||||
log_warning(plfBoot, "Making explicit call to OPENSSL_add_all_algorithms_noconf");
|
||||
|
||||
DWORD imageBase = GetImageBase();
|
||||
imageOffset = (DWORD)hModule - imageBase;
|
||||
|
||||
// OPENSSL_add_all_algorithms_noconf (old exe)
|
||||
// ((void (*)(void))(0x00459770 + imageOffset))();
|
||||
|
||||
// OPENSSL_add_all_algorithms_noconf (pink exe)
|
||||
// ((void (*)(void))(0x00463480 + imageOffset))();
|
||||
|
||||
// TODO: Find finale offset
|
||||
}
|
||||
|
||||
setup_hooks();
|
||||
|
||||
start_devices();
|
||||
}
|
||||
|
||||
void tea_hook_test(char* fmt, ...) {
|
||||
@ -203,24 +160,63 @@ void tea_hook_test(char* fmt, ...) {
|
||||
va_end(argp);
|
||||
}
|
||||
|
||||
BOOL g_bIsInDllMain = TRUE;
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
|
||||
g_bIsInDllMain = TRUE;
|
||||
|
||||
GetModuleFileNameW(NULL, exeName, MAX_PATH);
|
||||
wcscpy_s(exeName, MAX_PATH + 1, PathFindFileNameW(exeName));
|
||||
|
||||
if (!MiceIpcSetup(FALSE)) {
|
||||
fprintf(stderr, "Failed to initialise IPC from within micelib. Bailing hard!");
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HMODULE exeModule = GetModuleHandleA(NULL);
|
||||
init_injection(exeModule);
|
||||
|
||||
if (wcscmp(exeName, L"InitialD8_GLW_RE_SBZZ_dumped_.exe") == 0) {
|
||||
CreateHook32((void*)(0x00407850), &tea_hook_test);
|
||||
// *((DWORD*)(0x00407850)) = (DWORD)(&logcb);
|
||||
_MiceGotGameId(_miceIpcData->m_GameId);
|
||||
|
||||
// InitialD 8
|
||||
if (false) {
|
||||
DWORD dword = 0;
|
||||
MiceHookPatchAtImage(exeModule, (PVOID)0x0126867c, &dword, 4);
|
||||
|
||||
BYTE movEax1[] = { 0xb8, 0x01, 0x00, 0x00, 0x00 };
|
||||
// Bypass cgGcIsProfileSupported
|
||||
MiceHookNopAtImage(exeModule, (PVOID)0xb4c9ac, 6);
|
||||
MiceHookPatchAtImage(exeModule, (PVOID)0xb4c9ac, movEax1, sizeof movEax1);
|
||||
MiceHookNopAtImage(exeModule, (PVOID)0xb4ca9f, 6);
|
||||
MiceHookPatchAtImage(exeModule, (PVOID)0xb4ca9f, movEax1, sizeof movEax1);
|
||||
|
||||
// change glProgramEnvParameters4fvNV to EXT version that works with any GPUs
|
||||
static const char* arb = "glProgramEnvParameters4fvEXT";
|
||||
MiceHookPatchAtImage(exeModule, (PVOID)0xB70E26, &arb, 4);
|
||||
// force volatile texture (driver bug(?) check) presence
|
||||
MiceHookNopAtImage(exeModule, (PVOID)(0xB6BC20 + 0x5667), 2);
|
||||
|
||||
DWORD profile;
|
||||
BOOL amd = TRUE;
|
||||
if (amd)
|
||||
profile = 6151; // CG_PROFILE_FP40
|
||||
else
|
||||
profile = 7000; // CG_PROFILE_ARBFP1
|
||||
|
||||
// Vertex shader is compiled with profile 6150
|
||||
// Pixel shader is compiled with profile 7000
|
||||
|
||||
// Change shader profile for glareGenerator
|
||||
MiceHookPatchAtImage(exeModule, (PVOID)0x7D06A8, &profile, 4);
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
void* original = (void*)0x00407850;
|
||||
DetourAttach(&original, tea_hook_test);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
// if (wcscmp(exeName, L"RingGame.exe") == 0) {
|
||||
// log_warning(plfBoot, "Bodge hook goo!");
|
||||
// CreateHook32((void*)(0x005f2580), &tea_hook_test);
|
||||
// }
|
||||
|
||||
g_bIsInDllMain = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "../lib/am/amOemstring.h"
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "../lib/mice/dmi.h"
|
||||
#include "mx.h"
|
||||
|
||||
#define DMI_HEADER_START 0x000f0000
|
||||
|
@ -4,35 +4,42 @@
|
||||
#define JVS_NODE_BROADCAST 0xff
|
||||
|
||||
#define JVS_VERSION_CMD 0x13 // A real board reports 1.1, but we support 1.3
|
||||
#define JVS_VERSION_JVS 0x20
|
||||
#define JVS_VERSION_JVS 0x30 // My board is 0x20, but SBWU needs 0x30
|
||||
#define JVS_VERSION_COMM 0x10
|
||||
|
||||
#define JVS_STATUS_OK 0x01
|
||||
#define JVS_STATUS_UKCOM 0x02
|
||||
#define JVS_STATUS_SUM 0x03
|
||||
#define JVS_STATUS_OVERFLOW 0x04
|
||||
#define JVS_STATUS_UNKNOWN 0xff // Not a spec-compliant status, but there's none for this!
|
||||
typedef enum JVS_STATUS {
|
||||
JVS_STATUS_OK = 0x01,
|
||||
JVS_STATUS_UKCOM = 0x02,
|
||||
JVS_STATUS_SUM = 0x03,
|
||||
JVS_STATUS_OVERFLOW = 0x04,
|
||||
JVS_STATUS_UNKNOWN = 0xfe, // Not a spec-compliant status, but there's none for this!
|
||||
JVS_STATUS_SILENCE = 0xff, // Pseudo-status to indicate that the response is not to be sent
|
||||
} JVS_STATUS;
|
||||
|
||||
#define JVS_REPORT_OK 0x01
|
||||
#define JVS_REPORT_PARAM_NODATA 0x02
|
||||
#define JVS_REPORT_PARAM_INVALID 0x03
|
||||
#define JVS_REPORT_BUSY 0x04
|
||||
typedef enum JVS_REPORT {
|
||||
JVS_REPORT_OK = 0x01,
|
||||
JVS_REPORT_PARAM_NODATA = 0x02,
|
||||
JVS_REPORT_PARAM_INVALID = 0x03,
|
||||
JVS_REPORT_BUSY = 0x04,
|
||||
} JVS_REPORT;
|
||||
|
||||
#define JVS_FEATURE_PAD 0x00
|
||||
#define JVS_FEATURE_EOF 0x00
|
||||
#define JVS_FEATURE_PLAYERS 0x01
|
||||
#define JVS_FEATURE_COINS 0x02
|
||||
#define JVS_FEATURE_ANALOG 0x03
|
||||
#define JVS_FEATURE_ROTARY 0x04
|
||||
#define JVS_FEATURE_KEYCODE 0x05
|
||||
#define JVS_FEATURE_SCREEN_POS 0x06
|
||||
#define JVS_FEATURE_MISC_SWITCH 0x07
|
||||
#define JVS_FEATURE_CARDS 0x10
|
||||
#define JVS_FEATURE_MEDAL_HOPPER 0x11
|
||||
#define JVS_FEATURE_GPIO 0x12
|
||||
#define JVS_FEATURE_ANALOG_OUT 0x13
|
||||
#define JVS_FEATURE_CHAR_OUT 0x14
|
||||
#define JVS_FEATURE_BACKUP 0x15
|
||||
typedef enum JVS_FEATURE {
|
||||
JVS_FEATURE_PAD = 0x00,
|
||||
JVS_FEATURE_EOF = 0x00,
|
||||
JVS_FEATURE_PLAYERS = 0x01,
|
||||
JVS_FEATURE_COINS = 0x02,
|
||||
JVS_FEATURE_ANALOG = 0x03,
|
||||
JVS_FEATURE_ROTARY = 0x04,
|
||||
JVS_FEATURE_KEYCODE = 0x05,
|
||||
JVS_FEATURE_SCREEN_POS = 0x06,
|
||||
JVS_FEATURE_MISC_SWITCH = 0x07,
|
||||
JVS_FEATURE_CARDS = 0x10,
|
||||
JVS_FEATURE_MEDAL_HOPPER = 0x11,
|
||||
JVS_FEATURE_GPIO = 0x12,
|
||||
JVS_FEATURE_ANALOG_OUT = 0x13,
|
||||
JVS_FEATURE_CHAR_OUT = 0x14,
|
||||
JVS_FEATURE_BACKUP = 0x15,
|
||||
} JVS_FEATURE;
|
||||
|
||||
#define JVS_CHARTYPE_UNKNOWN 0x00
|
||||
#define JVS_CHARTYPE_NUMBER 0x01
|
||||
|
74
src/micetools/dll/drivers/jvs_boards/jvs.h
Normal file
74
src/micetools/dll/drivers/jvs_boards/jvs.h
Normal file
@ -0,0 +1,74 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../../input.h"
|
||||
#include "../jvs.h"
|
||||
|
||||
#define JVS_IO_MAX 31
|
||||
|
||||
#define MICE_JVS_MAX 256
|
||||
// Every single byte could be masked
|
||||
#define MICE_JVS_MASKED (MICE_JVS_MAX * 2)
|
||||
|
||||
#define new(type, instance) _##type##_vftable.ctor(&instance)
|
||||
|
||||
typedef struct MICE_JVS MICE_JVS, *PMICE_JVS;
|
||||
typedef struct MICE_JVS_vftable MICE_JVS_vftable;
|
||||
|
||||
struct MICE_JVS_vftable {
|
||||
void (*ctor)(PMICE_JVS this);
|
||||
JVS_STATUS (*transact)(PMICE_JVS this, BYTE command);
|
||||
void (*readAllButtons)(PMICE_JVS this);
|
||||
};
|
||||
|
||||
extern MICE_JVS_vftable _MiceJvsBase_vftable;
|
||||
extern MICE_JVS_vftable _MiceJvs837_14572_vftable;
|
||||
extern MICE_JVS_vftable _MiceJvs837_14895_vftable;
|
||||
|
||||
struct MICE_JVS {
|
||||
MICE_JVS_vftable* vftable;
|
||||
|
||||
LPBYTE m_lpInData;
|
||||
DWORD m_nInIdx;
|
||||
LPBYTE m_lpOutData;
|
||||
DWORD m_nOutIdx;
|
||||
|
||||
BYTE m_Address;
|
||||
|
||||
LPCSTR m_BoardId;
|
||||
BYTE m_CommandVersion;
|
||||
BYTE m_JvsRevision;
|
||||
BYTE m_VersionComm;
|
||||
|
||||
BOOL m_SenseOut;
|
||||
|
||||
BYTE m_Players;
|
||||
BYTE m_ButtonsPerPlayer;
|
||||
BYTE m_Coins;
|
||||
BYTE m_NumButtons;
|
||||
LPBOOL m_ButtonStates;
|
||||
PMICE_BUTTON_BINDING m_Bindings;
|
||||
|
||||
DWORD m_CoinCounts[2];
|
||||
};
|
||||
#pragma pack(push, 1)
|
||||
typedef struct JVS_PACKET {
|
||||
BYTE m_Sync;
|
||||
BYTE m_Dst;
|
||||
BYTE m_nBytes;
|
||||
BYTE m_Data[MICE_JVS_MAX - 3];
|
||||
} JVS_PACKET, *PJVS_PACKET;
|
||||
#pragma pack(pop)
|
||||
|
||||
static inline BYTE MiceJvsRead(PMICE_JVS this) {
|
||||
if (this->m_lpInData == NULL) return 0xff;
|
||||
if (this->m_nInIdx < MICE_JVS_MAX) return this->m_lpInData[this->m_nInIdx++];
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
static inline void MiceJvsWrite(PMICE_JVS this, BYTE data) {
|
||||
if (this->m_lpOutData == NULL) return;
|
||||
if (this->m_nOutIdx < MICE_JVS_MAX) this->m_lpOutData[this->m_nOutIdx++] = data;
|
||||
}
|
||||
|
||||
extern MICE_JVS _MiceJvsBoards[JVS_IO_MAX];
|
148
src/micetools/dll/drivers/jvs_boards/jvs_837_14572.c
Normal file
148
src/micetools/dll/drivers/jvs_boards/jvs_837_14572.c
Normal file
@ -0,0 +1,148 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../../common.h"
|
||||
#include "jvs.h"
|
||||
|
||||
#define PLAYER_COUNT 2
|
||||
#define COIN_COUNTERS 2
|
||||
|
||||
#define SWITCH_BYTES 2
|
||||
#define PLAYER_SWITCH_COUNT 13 // Must be less than 8*SWITCH_BYTES !!
|
||||
|
||||
BOOL coin_solenoid = false;
|
||||
|
||||
static const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
|
||||
|
||||
static void Ctor(PMICE_JVS this) {
|
||||
_MiceJvsBase_vftable.ctor(this);
|
||||
this->vftable = &_MiceJvs837_14572_vftable;
|
||||
this->vftable->readAllButtons = _MiceJvsBase_vftable.readAllButtons;
|
||||
|
||||
this->m_BoardId = JVS_837_14572_ID;
|
||||
this->m_CommandVersion = 0x13;
|
||||
this->m_JvsRevision = 0x20;
|
||||
this->m_VersionComm = 0x10;
|
||||
|
||||
// Coin + Test + 13 switches per player
|
||||
this->m_ButtonsPerPlayer = PLAYER_SWITCH_COUNT;
|
||||
this->m_Coins = COIN_COUNTERS;
|
||||
this->m_Players = PLAYER_COUNT;
|
||||
|
||||
this->m_NumButtons = this->m_Coins + 1 + (this->m_ButtonsPerPlayer * this->m_Players);
|
||||
this->m_ButtonStates = malloc(this->m_NumButtons * sizeof *this->m_ButtonStates);
|
||||
ZeroMemory(this->m_ButtonStates, this->m_NumButtons * sizeof *this->m_ButtonStates);
|
||||
this->m_Bindings = malloc(this->m_NumButtons * sizeof *this->m_Bindings);
|
||||
ZeroMemory(this->m_Bindings, this->m_NumButtons * sizeof *this->m_Bindings);
|
||||
|
||||
ZeroMemory(this->m_CoinCounts, sizeof this->m_CoinCounts);
|
||||
}
|
||||
|
||||
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
|
||||
switch (command) {
|
||||
case JVS_CMD_READ_SW:
|
||||
BYTE players = MiceJvsRead(this);
|
||||
BYTE switch_bytes = MiceJvsRead(this);
|
||||
if (players > this->m_Players || switch_bytes != SWITCH_BYTES) {
|
||||
MiceJvsWrite(this, JVS_REPORT_PARAM_INVALID);
|
||||
return JVS_STATUS_OK;
|
||||
}
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
|
||||
this->vftable->readAllButtons(this);
|
||||
|
||||
// Test button
|
||||
MiceJvsWrite(this, this->m_ButtonStates[this->m_Coins] ? 0x80 : 0x00);
|
||||
|
||||
for (int player = 0; player < players; player++) {
|
||||
unsigned short buttons = 0x0000;
|
||||
for (int j = 0; j < this->m_ButtonsPerPlayer; j++) {
|
||||
buttons <<= 1;
|
||||
if (this->m_ButtonStates[this->m_Coins + 1 +
|
||||
(this->m_ButtonsPerPlayer * player) + j]) {
|
||||
buttons |= 1;
|
||||
}
|
||||
}
|
||||
buttons <<= (16 - this->m_ButtonsPerPlayer);
|
||||
|
||||
for (int i = switch_bytes - 1; i >= 0; i--)
|
||||
MiceJvsWrite(this, (buttons >> (i * 8)) & 0xff);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_COIN:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char coin_count;
|
||||
coin_count = MiceJvsRead(this);
|
||||
|
||||
MiceInputPollDevices();
|
||||
for (int i = 0; i < this->m_Coins; i++)
|
||||
if (MiceInputGetButtonState(&this->m_Bindings[i])) this->m_CoinCounts[i]++;
|
||||
|
||||
for (unsigned char slot = 0; slot < this->m_Coins; slot++) {
|
||||
MiceJvsWrite(this, (this->m_CoinCounts[slot] >> 8) & 0xff);
|
||||
MiceJvsWrite(this, this->m_CoinCounts[slot] & 0xff);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
// TODO: Actually emulate these (super low priority)
|
||||
unsigned char analog_count;
|
||||
analog_count = MiceJvsRead(this);
|
||||
for (int i = analog_count; i > 0; i--) {
|
||||
MiceJvsWrite(this, 0xde);
|
||||
MiceJvsWrite(this, 0xad);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_WRITE_GPIO1:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char gpio_bytes;
|
||||
gpio_bytes = MiceJvsRead(this);
|
||||
for (int i = 0; i < gpio_bytes; i++) {
|
||||
unsigned char gpio_value;
|
||||
gpio_value = MiceJvsRead(this);
|
||||
|
||||
if (i == 0) {
|
||||
if (!!(gpio_value & 0x80) != coin_solenoid) {
|
||||
coin_solenoid = !!(gpio_value & 0x80);
|
||||
log_info(plfMxJvs, "Coin solenoid: %s",
|
||||
coin_solenoid ? "Locked" : "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_WRITE_GPIO2:
|
||||
case JVS_CMD_WRITE_GPIO3:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char gpioByteIndex;
|
||||
unsigned char gpioByteData;
|
||||
gpioByteIndex = MiceJvsRead(this);
|
||||
gpioByteData = MiceJvsRead(this);
|
||||
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
||||
(command - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_COIN_DECREASE:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
|
||||
unsigned char slot;
|
||||
slot = MiceJvsRead(this);
|
||||
unsigned char cAmount[2];
|
||||
cAmount[0] = MiceJvsRead(this);
|
||||
cAmount[1] = MiceJvsRead(this);
|
||||
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
|
||||
// board->coin_counts[slot] -= sAmount;
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
default:
|
||||
return _MiceJvsBase_vftable.transact(this, command);
|
||||
}
|
||||
}
|
||||
|
||||
MICE_JVS_vftable _MiceJvs837_14572_vftable = {
|
||||
.ctor = Ctor,
|
||||
.transact = Transact,
|
||||
};
|
169
src/micetools/dll/drivers/jvs_boards/jvs_837_14895.c
Normal file
169
src/micetools/dll/drivers/jvs_boards/jvs_837_14895.c
Normal file
@ -0,0 +1,169 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../../common.h"
|
||||
#include "jvs.h"
|
||||
|
||||
#define PLAYER_COUNT 1
|
||||
#define COIN_COUNTERS 2
|
||||
#define SWITCH_BYTES 2
|
||||
|
||||
BOOL coin_solenoid = false;
|
||||
|
||||
static const char JVS_837_14895_ID[] = ";;837-14895;;;FE MODE;";
|
||||
|
||||
static void Ctor(PMICE_JVS this) {
|
||||
_MiceJvsBase_vftable.ctor(this);
|
||||
this->vftable = &_MiceJvs837_14895_vftable;
|
||||
this->vftable->readAllButtons = _MiceJvsBase_vftable.readAllButtons;
|
||||
|
||||
this->m_BoardId = JVS_837_14895_ID;
|
||||
this->m_CommandVersion = 0x13;
|
||||
this->m_JvsRevision = 0x30;
|
||||
this->m_VersionComm = 0x10;
|
||||
|
||||
// Eeh whatever I'll do this eventually
|
||||
this->m_Players = 0;
|
||||
this->m_ButtonsPerPlayer = 0;
|
||||
this->m_Coins = 0;
|
||||
this->m_NumButtons = 0;
|
||||
}
|
||||
|
||||
// TODO: Urgent: Restore buttons
|
||||
|
||||
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
|
||||
switch (command) {
|
||||
case JVS_CMD_GET_FEATURES:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
|
||||
MiceJvsWrite(this, JVS_FEATURE_PLAYERS);
|
||||
MiceJvsWrite(this, PLAYER_COUNT);
|
||||
MiceJvsWrite(this, 22); // bits per player
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
// We need at least 15 general outputs
|
||||
MiceJvsWrite(this, JVS_FEATURE_GPIO);
|
||||
MiceJvsWrite(this, 16);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
// Toss in two coin counters for good luck
|
||||
MiceJvsWrite(this, JVS_FEATURE_COINS);
|
||||
MiceJvsWrite(this, COIN_COUNTERS);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
MiceJvsWrite(this, JVS_FEATURE_EOF);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_SW:
|
||||
unsigned char players;
|
||||
unsigned char switch_bytes;
|
||||
players = MiceJvsRead(this);
|
||||
switch_bytes = MiceJvsRead(this);
|
||||
if (players > PLAYER_COUNT || switch_bytes != 3) {
|
||||
MiceJvsWrite(this, JVS_REPORT_PARAM_INVALID);
|
||||
return JVS_STATUS_OK;
|
||||
}
|
||||
|
||||
// update_jvs_buttons(board);
|
||||
|
||||
// MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
// MiceJvsWrite(this, board->last_sysbuttons);
|
||||
// for (int player = 0; player < players; player++) {
|
||||
// for (int i = switch_bytes - 1; i >= 0; i--) {
|
||||
// MiceJvsWrite(this, (board->last_buttons[player] >> (i * 8)) & 0xff);
|
||||
// }
|
||||
// }
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
MiceJvsWrite(this, 0);
|
||||
for (int player = 0; player < players; player++) {
|
||||
for (int i = switch_bytes - 1; i >= 0; i--) {
|
||||
MiceJvsWrite(this, (0x00 >> (i * 8)) & 0xff);
|
||||
}
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_COIN:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char coin_count;
|
||||
coin_count = MiceJvsRead(this);
|
||||
|
||||
// int coin1 = jvsKeybindings[board->num].buttons[0];
|
||||
// int coin2 = jvsKeybindings[board->num].buttons[1];
|
||||
|
||||
// if (coin1 && GetAsyncKeyState(coin1) & 1) board->coin_counts[0]++;
|
||||
// if (coin2 && GetAsyncKeyState(coin2) & 1) board->coin_counts[1]++;
|
||||
|
||||
// for (unsigned char slot = 0; slot < coin_count; slot++) {
|
||||
// MiceJvsWrite(this, board->coin_counts[slot] >> 8);
|
||||
// MiceJvsWrite(this, board->coin_counts[slot] & 0xff);
|
||||
// }
|
||||
|
||||
for (unsigned char slot = 0; slot < coin_count; slot++) {
|
||||
MiceJvsWrite(this, 0);
|
||||
MiceJvsWrite(this, 0);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
// TODO: Actually emulate these (super low priority)
|
||||
unsigned char analog_count;
|
||||
analog_count = MiceJvsRead(this);
|
||||
for (int i = analog_count; i > 0; i--) {
|
||||
MiceJvsWrite(this, 0xde);
|
||||
MiceJvsWrite(this, 0xad);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_WRITE_GPIO1:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char gpio_bytes;
|
||||
gpio_bytes = MiceJvsRead(this);
|
||||
for (int i = 0; i < gpio_bytes; i++) {
|
||||
unsigned char gpio_value;
|
||||
gpio_value = MiceJvsRead(this);
|
||||
|
||||
if (i == 0) {
|
||||
if (!!(gpio_value & 0x80) != coin_solenoid) {
|
||||
coin_solenoid = !!(gpio_value & 0x80);
|
||||
log_info(plfMxJvs, "Coin solenoid: %s",
|
||||
coin_solenoid ? "Locked" : "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
|
||||
}
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_WRITE_GPIO2:
|
||||
case JVS_CMD_WRITE_GPIO3:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
unsigned char gpioByteIndex;
|
||||
unsigned char gpioByteData;
|
||||
gpioByteIndex = MiceJvsRead(this);
|
||||
gpioByteData = MiceJvsRead(this);
|
||||
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
||||
(command - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_COIN_DECREASE:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
|
||||
unsigned char slot;
|
||||
slot = MiceJvsRead(this);
|
||||
unsigned char cAmount[2];
|
||||
cAmount[0] = MiceJvsRead(this);
|
||||
cAmount[1] = MiceJvsRead(this);
|
||||
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
|
||||
// board->coin_counts[slot] -= sAmount;
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
default:
|
||||
return _MiceJvsBase_vftable.transact(this, command);
|
||||
}
|
||||
}
|
||||
|
||||
MICE_JVS_vftable _MiceJvs837_14895_vftable = {
|
||||
.ctor = Ctor,
|
||||
.transact = Transact,
|
||||
};
|
115
src/micetools/dll/drivers/jvs_boards/jvs_base.c
Normal file
115
src/micetools/dll/drivers/jvs_boards/jvs_base.c
Normal file
@ -0,0 +1,115 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../../common.h"
|
||||
#include "jvs.h"
|
||||
|
||||
static void Ctor(PMICE_JVS this) {
|
||||
this->vftable = &_MiceJvsBase_vftable;
|
||||
|
||||
this->m_nInIdx = 0;
|
||||
this->m_lpInData = NULL;
|
||||
this->m_nOutIdx = 0;
|
||||
this->m_lpOutData = NULL;
|
||||
|
||||
this->m_BoardId = NULL;
|
||||
|
||||
this->m_Address = 0xff;
|
||||
|
||||
// Sane, but impractical, defaults. Boards should set better values.
|
||||
this->m_CommandVersion = 0x10;
|
||||
this->m_JvsRevision = 0x20;
|
||||
this->m_VersionComm = 0x10;
|
||||
}
|
||||
|
||||
static JVS_STATUS Transact(PMICE_JVS this, BYTE command) {
|
||||
switch (command) {
|
||||
case JVS_CMD_RESET:
|
||||
if (MiceJvsRead(this) != JVS_CMD_RESET_ASSERT) return JVS_STATUS_UKCOM;
|
||||
|
||||
this->m_Address = 0xff;
|
||||
this->m_SenseOut = TRUE;
|
||||
return JVS_STATUS_SILENCE;
|
||||
case JVS_CMD_CHANGE_COMMS:
|
||||
return JVS_STATUS_SILENCE;
|
||||
|
||||
case JVS_CMD_ASSIGN_ADDR:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
this->m_SenseOut = FALSE;
|
||||
// we don't bother remembering the address because at the moment we only simulate
|
||||
// a single board in the JVS chain.
|
||||
MiceJvsRead(this);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_READ_ID:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
if (this->m_BoardId == NULL)
|
||||
MiceJvsWrite(this, 0x00);
|
||||
else
|
||||
for (size_t i = 0; i < strlen(this->m_BoardId); i++)
|
||||
MiceJvsWrite(this, this->m_BoardId[i]);
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_GET_CMD_VERSION:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
MiceJvsWrite(this, this->m_CommandVersion);
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_GET_JVS_VERSION:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
MiceJvsWrite(this, this->m_JvsRevision);
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_GET_COMM_VERSION:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
MiceJvsWrite(this, this->m_VersionComm);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_GET_FEATURES:
|
||||
MiceJvsWrite(this, JVS_REPORT_OK);
|
||||
|
||||
MiceJvsWrite(this, JVS_FEATURE_PLAYERS);
|
||||
MiceJvsWrite(this, this->m_Players);
|
||||
MiceJvsWrite(this, this->m_ButtonsPerPlayer);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
MiceJvsWrite(this, JVS_FEATURE_COINS);
|
||||
MiceJvsWrite(this, this->m_Coins);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
// TODO: Make this based on `this`
|
||||
MiceJvsWrite(this, JVS_FEATURE_ANALOG);
|
||||
MiceJvsWrite(this, 8); // 8 ADC channels
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD); // ?? (was "10" prior)
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
// TODO: Make this based on `this`
|
||||
MiceJvsWrite(this, JVS_FEATURE_GPIO);
|
||||
MiceJvsWrite(this, 6); // 6 ports
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
MiceJvsWrite(this, JVS_FEATURE_PAD);
|
||||
|
||||
MiceJvsWrite(this, JVS_FEATURE_EOF);
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_RECEIVE_MAIN_ID:
|
||||
unsigned char tempRead = 0xff;
|
||||
while (tempRead != 0) tempRead = MiceJvsRead(this);
|
||||
// TODO: Do we need to report here?
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
default:
|
||||
log_error(plfMxJvs, "Unknown command: 0x%02x", command);
|
||||
return JVS_STATUS_UKCOM;
|
||||
}
|
||||
}
|
||||
|
||||
static void ReadAllButtons(PMICE_JVS this) {
|
||||
MiceInputPollDevices();
|
||||
|
||||
for (DWORD i = 0; i < this->m_NumButtons; i++) {
|
||||
this->m_ButtonStates[i] = MiceInputGetButtonState(&(this->m_Bindings[i]));
|
||||
}
|
||||
}
|
||||
|
||||
MICE_JVS_vftable _MiceJvsBase_vftable = {
|
||||
.ctor = Ctor,
|
||||
.transact = Transact,
|
||||
.readAllButtons = ReadAllButtons,
|
||||
};
|
@ -7,4 +7,8 @@ drivers_files = files(
|
||||
'mxsram.c',
|
||||
'mxsuperio.c',
|
||||
'htsysmnt.c',
|
||||
|
||||
'jvs_boards/jvs_base.c',
|
||||
'jvs_boards/jvs_837_14572.c',
|
||||
'jvs_boards/jvs_837_14895.c',
|
||||
)
|
@ -2,290 +2,22 @@
|
||||
|
||||
#include "../comdevice.h"
|
||||
#include "../common.h"
|
||||
#include "../input.h"
|
||||
#include "../key_config.h"
|
||||
#include "jvs.h"
|
||||
#include "jvs_boards/jvs.h"
|
||||
#include "mx.h"
|
||||
|
||||
BOOL JVS_SENSE = false;
|
||||
BOOL coin_solenoid = false;
|
||||
BOOL test_btn = false;
|
||||
#define JVS_SENSE (MiceConfig.keys.board_count == 0 ? FALSE : _MiceJvsBoards[0].m_SenseOut)
|
||||
|
||||
#define PLAYER_COUNT 2
|
||||
#define COIN_COUNTERS 2
|
||||
#define SWITCH_BYTES 2
|
||||
|
||||
// const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-14572 ;Ver1.00;98/10";
|
||||
const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
|
||||
|
||||
typedef struct _jvs_board {
|
||||
int num;
|
||||
unsigned short coin_counts[COIN_COUNTERS];
|
||||
|
||||
unsigned char (*handler)(struct _jvs_board* board, unsigned char* inData, short inCount,
|
||||
unsigned char* outData, unsigned char* outCount);
|
||||
const char* id;
|
||||
|
||||
unsigned char last_sysbuttons;
|
||||
unsigned short last_buttons[PLAYER_COUNT];
|
||||
} jvs_board_t;
|
||||
#define JVS_FLAG_NONE 0
|
||||
#define JVS_FLAG_NC 1
|
||||
#define JVS_FLAG_INVERT 2
|
||||
|
||||
jvs_board_t jvs_boards[JVS_IO_MAX] = { 0 };
|
||||
|
||||
short jvs_unpad(unsigned char* paddedData, short length, unsigned char* unpaddedData) {
|
||||
short index = 0;
|
||||
bool escape = false;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (escape) {
|
||||
unpaddedData[index++] = paddedData[i] + 1;
|
||||
escape = false;
|
||||
} else if (paddedData[i] == JVS_MARK)
|
||||
escape = true;
|
||||
else
|
||||
unpaddedData[index++] = paddedData[i];
|
||||
JVS_STATUS MiceJvsWrapper(PMICE_JVS this, DWORD nMaxRead) {
|
||||
JVS_STATUS status = JVS_STATUS_OK;
|
||||
// -1, because we don't want to treat the checksum as a command!
|
||||
while (this->m_nInIdx < nMaxRead - 1) {
|
||||
JVS_STATUS subStatus = this->vftable->transact(this, MiceJvsRead(this));
|
||||
if (subStatus > status) status = subStatus;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
short jvs_pad(unsigned char* unpaddedData, short length, unsigned char* paddedData,
|
||||
short paddedMax) {
|
||||
short index = 0;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (i > paddedMax) return -1;
|
||||
|
||||
if (i != 0 && (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC)) {
|
||||
paddedData[index++] = JVS_MARK;
|
||||
paddedData[index++] = unpaddedData[i] - 1;
|
||||
} else {
|
||||
paddedData[index++] = unpaddedData[i];
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void update_jvs_buttons(jvs_board_t* board) {
|
||||
unsigned char sysButtons = 0x00;
|
||||
if (GetAsyncKeyState(jvsKeybindings[board->num].test) < 0) sysButtons |= 0x80;
|
||||
board->last_sysbuttons = sysButtons;
|
||||
|
||||
for (int player = 0; player < PLAYER_COUNT; player++) {
|
||||
unsigned short buttons = 0x0000;
|
||||
for (int i = 0; i < SWITCH_BYTES * 8; i++) {
|
||||
buttons <<= 1;
|
||||
if (i < 14) {
|
||||
int scancode = jvsKeybindings[board->num].buttons[(i + 1) * 2 + player];
|
||||
bool invert = jvsKeybindings[board->num].invert[(i + 1) * 2 + player];
|
||||
|
||||
if (scancode == 0) continue;
|
||||
|
||||
if (invert)
|
||||
buttons |= (GetAsyncKeyState(scancode) >= 0); // << i;
|
||||
else
|
||||
buttons |= (GetAsyncKeyState(scancode) < 0); // << i;
|
||||
}
|
||||
|
||||
// 0x80 == push 3
|
||||
|
||||
// buttons |= 1;
|
||||
// buttons |= 0x80;
|
||||
}
|
||||
board->last_buttons[player] = buttons;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCount,
|
||||
unsigned char* response, unsigned char* outCount) {
|
||||
short jvsIndex = 0;
|
||||
unsigned char respIndex = 0;
|
||||
|
||||
#define jvs_read(x) \
|
||||
if (jvsIndex >= inCount) { \
|
||||
return JVS_STATUS_OVERFLOW; \
|
||||
} else { \
|
||||
(x) = inData[jvsIndex++]; \
|
||||
}
|
||||
#define jvs_write(x) response[respIndex++] = (x);
|
||||
|
||||
static bool flipflop = false;
|
||||
|
||||
while (jvsIndex < inCount) {
|
||||
unsigned char cmd;
|
||||
jvs_read(cmd);
|
||||
|
||||
// log_info(plfMxJvs, "CMD: %02x", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case JVS_CMD_RESET:
|
||||
unsigned char reset_assert;
|
||||
jvs_read(reset_assert);
|
||||
if (reset_assert != JVS_CMD_RESET_ASSERT) return JVS_STATUS_UKCOM;
|
||||
|
||||
JVS_SENSE = true;
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return JVS_STATUS_OK;
|
||||
case JVS_CMD_CHANGE_COMMS:
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return JVS_STATUS_OK;
|
||||
|
||||
case JVS_CMD_ASSIGN_ADDR:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
JVS_SENSE = false;
|
||||
// we don't bother remembering the address because at the moment we only simulate
|
||||
// a single board in the JVS chain.
|
||||
unsigned char _;
|
||||
jvs_read(_);
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ID:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
for (size_t i = 0; i < strlen(board->id); i++) jvs_write(board->id[i]);
|
||||
break;
|
||||
case JVS_CMD_GET_CMD_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_CMD);
|
||||
break;
|
||||
case JVS_CMD_GET_JVS_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_JVS);
|
||||
break;
|
||||
case JVS_CMD_GET_COMM_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_COMM);
|
||||
break;
|
||||
|
||||
case JVS_CMD_GET_FEATURES:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
|
||||
jvs_write(JVS_FEATURE_PLAYERS);
|
||||
jvs_write(PLAYER_COUNT);
|
||||
jvs_write(13); // bits per player
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_COINS);
|
||||
jvs_write(COIN_COUNTERS);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_ANALOG);
|
||||
jvs_write(8); // 8 ADC channels
|
||||
jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior)
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_GPIO);
|
||||
jvs_write(6); // 6 ports
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
|
||||
jvs_write(JVS_FEATURE_EOF);
|
||||
|
||||
break;
|
||||
case JVS_CMD_RECEIVE_MAIN_ID:
|
||||
unsigned char tempRead = 0xff;
|
||||
while (tempRead != 0) jvs_read(tempRead);
|
||||
// TODO: Do we need to report here?
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_SW:
|
||||
unsigned char players;
|
||||
unsigned char switch_bytes;
|
||||
jvs_read(players);
|
||||
jvs_read(switch_bytes);
|
||||
if (players > PLAYER_COUNT || switch_bytes != 2) {
|
||||
jvs_write(JVS_REPORT_PARAM_INVALID);
|
||||
break;
|
||||
}
|
||||
update_jvs_buttons(board);
|
||||
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(board->last_sysbuttons);
|
||||
for (int player = 0; player < players; player++) {
|
||||
for (int i = switch_bytes - 1; i >= 0; i--) {
|
||||
jvs_write((board->last_buttons[player] >> (i * 8)) & 0xff);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_COIN:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char coin_count;
|
||||
jvs_read(coin_count);
|
||||
|
||||
int coin1 = jvsKeybindings[board->num].buttons[0];
|
||||
int coin2 = jvsKeybindings[board->num].buttons[1];
|
||||
|
||||
if (coin1 && GetAsyncKeyState(coin1) & 1) board->coin_counts[0]++;
|
||||
if (coin2 && GetAsyncKeyState(coin2) & 1) board->coin_counts[1]++;
|
||||
|
||||
for (unsigned char slot = 0; slot < coin_count; slot++) {
|
||||
jvs_write(board->coin_counts[slot] >> 8);
|
||||
jvs_write(board->coin_counts[slot] & 0xff);
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
// TODO: Actually emulate these (super low priority)
|
||||
unsigned char analog_count;
|
||||
jvs_read(analog_count);
|
||||
for (int i = analog_count; i > 0; i--) {
|
||||
jvs_write(0xde);
|
||||
jvs_write(0xad);
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_WRITE_GPIO1:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char gpio_bytes;
|
||||
jvs_read(gpio_bytes);
|
||||
for (int i = 0; i < gpio_bytes; i++) {
|
||||
unsigned char gpio_value;
|
||||
jvs_read(gpio_value);
|
||||
|
||||
if (i == 0) {
|
||||
if (!!(gpio_value & 0x80) != coin_solenoid) {
|
||||
coin_solenoid = !!(gpio_value & 0x80);
|
||||
log_info(plfMxJvs, "Coin solenoid: %s",
|
||||
coin_solenoid ? "Locked" : "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
// log_warning(plfMxJvs, "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
|
||||
}
|
||||
break;
|
||||
case JVS_CMD_WRITE_GPIO2:
|
||||
case JVS_CMD_WRITE_GPIO3:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char gpioByteIndex;
|
||||
unsigned char gpioByteData;
|
||||
jvs_read(gpioByteIndex);
|
||||
jvs_read(gpioByteData);
|
||||
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
||||
(cmd - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
|
||||
break;
|
||||
|
||||
case JVS_CMD_COIN_DECREASE:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
|
||||
unsigned char slot;
|
||||
jvs_read(slot);
|
||||
unsigned char cAmount[2];
|
||||
jvs_read(cAmount[0]);
|
||||
jvs_read(cAmount[1]);
|
||||
unsigned short sAmount = cAmount[0] << 8 | cAmount[1];
|
||||
board->coin_counts[slot] -= sAmount;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error(plfMxJvs, "Unknown command: 0x%02x", cmd);
|
||||
return JVS_STATUS_UKCOM;
|
||||
}
|
||||
}
|
||||
#undef jvs_read
|
||||
#undef jvs_write
|
||||
|
||||
*outCount = respIndex;
|
||||
return JVS_STATUS_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
void jvs_send_status(unsigned char status, unsigned char* outData, LPDWORD outCount) {
|
||||
@ -306,78 +38,116 @@ void jvs_send_status(unsigned char status, unsigned char* outData, LPDWORD outCo
|
||||
}
|
||||
}
|
||||
|
||||
void mxjvs_handle(unsigned char* paddedIn, short inCount, unsigned char* outData, short maxOut,
|
||||
LPDWORD outCount) {
|
||||
*outCount = 0;
|
||||
|
||||
unsigned char* inData = malloc(inCount);
|
||||
inCount = jvs_unpad(paddedIn, inCount, inData);
|
||||
BYTE jvsInUnmasked[MICE_JVS_MAX];
|
||||
BYTE jvsOutUnmasked[MICE_JVS_MAX];
|
||||
BYTE jvsOutMasked[MICE_JVS_MASKED];
|
||||
void mxjvs_handle(unsigned char* lpMaskedIn, short nMaskedCount, unsigned char* outData,
|
||||
short maxOut, LPDWORD outCount) {
|
||||
SHORT nIn = 0;
|
||||
BOOL wasMark = FALSE;
|
||||
for (int i = 0; i < nMaskedCount; i++) {
|
||||
if (lpMaskedIn[i] == JVS_MARK) {
|
||||
wasMark = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (wasMark)
|
||||
jvsInUnmasked[nIn++] = lpMaskedIn[i] + 1;
|
||||
else
|
||||
jvsInUnmasked[nIn++] = lpMaskedIn[i];
|
||||
}
|
||||
PJVS_PACKET lpPacket = (PJVS_PACKET)jvsInUnmasked;
|
||||
|
||||
// JVS frame is 4 bytes in total
|
||||
if (inCount < 4) {
|
||||
log_error(plfMxJvs, "inCount impossibly small: %d", inCount);
|
||||
if (nIn < 4) {
|
||||
log_error(plfMxJvs, "inCount impossibly small: %d", nIn);
|
||||
jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount);
|
||||
free(inData);
|
||||
return;
|
||||
}
|
||||
// This isn't a JVS packet
|
||||
if (inData[0] != JVS_SYNC) {
|
||||
log_error(plfMxJvs, "SYNC missing. Saw 0x%02x", inData[0]);
|
||||
// This isn't a JVS packet. We should scan for SYNC, but I don't think we'll ever need to
|
||||
if (lpPacket->m_Sync != JVS_SYNC) {
|
||||
log_error(plfMxJvs, "SYNC missing. Saw 0x%02x", lpPacket->m_Sync);
|
||||
jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount);
|
||||
free(inData);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the checksum before proceeding
|
||||
unsigned char sum = 0;
|
||||
bool escape = false;
|
||||
for (int i = 1; i < inCount - 1; i++) sum += inData[i];
|
||||
if (sum != inData[inCount - 1]) {
|
||||
for (int i = 1; i < nIn - 1; i++) sum += jvsInUnmasked[i];
|
||||
if (sum != jvsInUnmasked[nIn - 1]) {
|
||||
log_error(plfMxJvs, "Checksum failed. Computed 0x%02x, expected 0x%02x", sum,
|
||||
inData[inCount - 1]);
|
||||
jvsInUnmasked[nIn - 1]);
|
||||
jvs_send_status(JVS_STATUS_SUM, outData, outCount);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char destination = inData[1];
|
||||
// Not broadcast, not master-bound, and within bounds
|
||||
if (destination != 0xff && (destination == 0 || destination > MiceConfig.keys.board_count))
|
||||
return;
|
||||
DWORD nBoardCount = MiceConfig.keys.board_count;
|
||||
if (nBoardCount > _countof(_MiceJvsBoards)) nBoardCount = _countof(_MiceJvsBoards);
|
||||
|
||||
unsigned char* response = malloc(maxOut);
|
||||
unsigned char packetSize = 0;
|
||||
unsigned char status = JVS_STATUS_UNKNOWN;
|
||||
if (destination == 0xff) {
|
||||
for (int i = 0; i < MiceConfig.keys.board_count; i++) {
|
||||
jvs_board_t* board = &jvs_boards[i];
|
||||
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
|
||||
if (packetSize != 0) break;
|
||||
// Not broadcast, not master-bound, and within bounds
|
||||
if (lpPacket->m_Dst != 0xff && (lpPacket->m_Dst == 0 || lpPacket->m_Dst > nBoardCount)) {
|
||||
log_warning(plfMxJvs, "JVS bound for %02x ignored", lpPacket->m_Dst);
|
||||
*outCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
JVS_STATUS status = JVS_STATUS_UNKNOWN;
|
||||
DWORD nBytesWrote = 0;
|
||||
if (lpPacket->m_Dst == 0xff) {
|
||||
for (DWORD i = 0; i < nBoardCount; i++) {
|
||||
PMICE_JVS lpMiceJvs = &_MiceJvsBoards[i];
|
||||
|
||||
lpMiceJvs->m_lpInData = jvsInUnmasked;
|
||||
lpMiceJvs->m_lpOutData = jvsOutUnmasked;
|
||||
lpMiceJvs->m_nInIdx = 3;
|
||||
lpMiceJvs->m_nOutIdx = 4;
|
||||
|
||||
status = MiceJvsWrapper(lpMiceJvs, nIn);
|
||||
if (lpMiceJvs->m_nOutIdx > 4) {
|
||||
nBytesWrote = lpMiceJvs->m_nOutIdx - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
jvs_board_t* board = &jvs_boards[MiceConfig.keys.board_count - destination];
|
||||
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
|
||||
PMICE_JVS lpMiceJvs = &_MiceJvsBoards[nBoardCount - lpPacket->m_Dst];
|
||||
|
||||
lpMiceJvs->m_lpInData = jvsInUnmasked;
|
||||
lpMiceJvs->m_lpOutData = jvsOutUnmasked;
|
||||
lpMiceJvs->m_nInIdx = 3;
|
||||
lpMiceJvs->m_nOutIdx = 4;
|
||||
|
||||
status = MiceJvsWrapper(lpMiceJvs, nIn);
|
||||
nBytesWrote = lpMiceJvs->m_nOutIdx - 4;
|
||||
}
|
||||
|
||||
if (status == JVS_STATUS_SILENCE) {
|
||||
*outCount = 0;
|
||||
return;
|
||||
}
|
||||
free(inData);
|
||||
|
||||
if (status == JVS_STATUS_OK) {
|
||||
if (packetSize == 0) return;
|
||||
|
||||
response[0] = JVS_SYNC;
|
||||
response[1] = JVS_NODE_MASTER;
|
||||
response[2] = packetSize + 2;
|
||||
response[3] = status;
|
||||
((PJVS_PACKET)&jvsOutUnmasked)->m_Dst = JVS_NODE_MASTER;
|
||||
((PJVS_PACKET)&jvsOutUnmasked)->m_nBytes = (nBytesWrote + 2) & 0xff;
|
||||
jvsOutUnmasked[3] = status;
|
||||
|
||||
sum = 0;
|
||||
for (int i = 1; i < packetSize + 4; i++) sum += response[i];
|
||||
response[packetSize + 4] = sum;
|
||||
for (DWORD i = 1; i < nBytesWrote + 4; i++) sum += jvsOutUnmasked[i];
|
||||
jvsOutUnmasked[nBytesWrote + 4] = sum;
|
||||
|
||||
short paddedLength = jvs_pad(response, packetSize + 5, outData, maxOut);
|
||||
*outCount = (paddedLength == -1) ? 0 : paddedLength;
|
||||
DWORD nPadded = 1;
|
||||
jvsOutMasked[0] = JVS_SYNC;
|
||||
for (DWORD i = 1; i <= nBytesWrote + 4; i++) {
|
||||
if (i == JVS_MARK || i == JVS_SYNC) {
|
||||
jvsOutMasked[nPadded++] = JVS_MARK;
|
||||
jvsOutMasked[nPadded++] = jvsOutUnmasked[i] - 1;
|
||||
} else
|
||||
jvsOutMasked[nPadded++] = jvsOutUnmasked[i];
|
||||
}
|
||||
|
||||
free(response);
|
||||
*outCount = nPadded;
|
||||
memcpy_s(outData, maxOut, jvsOutMasked, nPadded);
|
||||
} else {
|
||||
log_error(plfMxJvs, "JVS board %d returned status %d", destination, status);
|
||||
free(response);
|
||||
log_error(plfMxJvs, "JVS board %d returned status %d", lpPacket->m_Dst, status);
|
||||
jvs_send_status(status, outData, outCount);
|
||||
}
|
||||
}
|
||||
@ -410,7 +180,7 @@ BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
|
||||
|
||||
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
|
||||
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
|
||||
*lpModelStat = JVS_SENSE ? 0 : MS_DSR_ON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -423,10 +193,12 @@ BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
|
||||
}
|
||||
|
||||
void init_jvs_boards() {
|
||||
for (int i = 0; i < _countof(jvs_boards); i++) {
|
||||
jvs_boards[i].num = i;
|
||||
jvs_boards[i].id = JVS_837_14572_ID;
|
||||
jvs_boards[i].handler = &jvs_exchange;
|
||||
// new (MiceJvs837_14895, _MiceJvsBoards[0]);
|
||||
new (MiceJvs837_14572, _MiceJvsBoards[0]);
|
||||
|
||||
// Init all the others
|
||||
for (int i = 1; i < _countof(_MiceJvsBoards); i++) {
|
||||
new (MiceJvs837_14572, _MiceJvsBoards[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,11 +227,16 @@ DWORD __stdcall mxjvs_comdev_thread(com_device_t* com) {
|
||||
|
||||
short packetSize = (bufferPtr - inBuffer) & 0xFFFF;
|
||||
mxjvs_handle(inBuffer, packetSize, outBuffer, _countof(outBuffer), &bytesReturned);
|
||||
com->modemStatus = !JVS_SENSE ? MS_DSR_ON : 0;
|
||||
com->modemStatus = JVS_SENSE ? 0 : MS_DSR_ON;
|
||||
comdev_write(com, outBuffer, bytesReturned & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL_SERIAL_DEVICE jvsSerialDevice = {
|
||||
.m_Name = "JVS",
|
||||
.m_Entrypoint = mxjvs_comdev_thread,
|
||||
};
|
||||
|
||||
void setup_mxjvs() {
|
||||
init_jvs_boards();
|
||||
|
||||
@ -479,6 +256,5 @@ void setup_mxjvs() {
|
||||
|
||||
mxjvs->com_hook = jvscom;
|
||||
|
||||
// TODO: Looks like some things might use JVS on COM4. We should setup a comdevice for this!
|
||||
attach_com_device(4, mxjvs_comdev_thread);
|
||||
attach_com_device(4, &jvsSerialDevice);
|
||||
}
|
||||
|
@ -167,19 +167,19 @@ void init_nv_storage() {
|
||||
|
||||
void dump_nv_storage() {
|
||||
FILE* fp;
|
||||
if (fopen_s(&fp, "dev/kc/nvram.bin", "wb")) {
|
||||
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\nvram.bin"), "wb")) {
|
||||
log_error(plfMxParallel, "Failed to open nvram.bin");
|
||||
return;
|
||||
}
|
||||
fwrite(nvram, 1, sizeof nvram, fp);
|
||||
fclose(fp);
|
||||
if (fopen_s(&fp, "dev/kc/eeprom.bin", "wb")) {
|
||||
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\eeprom.bin"), "wb")) {
|
||||
log_error(plfMxParallel, "Failed to open eeprom.bin");
|
||||
return;
|
||||
}
|
||||
fwrite(eeprom, 1, sizeof eeprom, fp);
|
||||
fclose(fp);
|
||||
if (fopen_s(&fp, "dev/kc/flash.bin", "wb")) {
|
||||
if (fopen_s(&fp, MiceIpcRelativePath("keychip\\flash.bin"), "wb")) {
|
||||
log_error(plfMxParallel, "Failed to open flash.bin");
|
||||
return;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "../hooks/setupapi_.h"
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "../../lib/mice/dmi.h"
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include "../../maiBackupStructs.h"
|
||||
#include "mx.h"
|
||||
|
||||
#define SRAM_PATH L"dev/sram.bin"
|
||||
#define SRAM_SIZE 1024 * 2084
|
||||
// The size of RingEdge[2], which is larger than RingWide needs
|
||||
#define SRAM_SIZE_MAX 1024 * 2084
|
||||
LPBYTE SRAM_DATA = NULL;
|
||||
HANDLE SRAM_FILE = INVALID_HANDLE_VALUE;
|
||||
HANDLE SRAM_FILE_MAPPING = INVALID_HANDLE_VALUE;
|
||||
@ -20,9 +20,9 @@ HANDLE SRAM_FILE_MAPPING = INVALID_HANDLE_VALUE;
|
||||
} while (0)
|
||||
|
||||
void build_sram() {
|
||||
log_info(plfMxSram, "Building default SRAM file");
|
||||
log_warning(plfMxSram, "Building default SRAM file");
|
||||
|
||||
memset(SRAM_DATA, 0xff, SRAM_SIZE);
|
||||
memset(SRAM_DATA, 0xff, SRAM_SIZE_MAX);
|
||||
|
||||
// TODO: Do we want to re-enable this with actual values
|
||||
#if false
|
||||
@ -52,12 +52,12 @@ void build_sram() {
|
||||
|
||||
void ensure_valid_sram() {
|
||||
if (!SRAM_DATA) {
|
||||
BOOL isNew = !FileExists(SRAM_PATH);
|
||||
BOOL isNew = !FileExistsA(SRAM_PATH);
|
||||
|
||||
SRAM_DATA = open_mapped_file(SRAM_PATH, SRAM_SIZE, &SRAM_FILE, &SRAM_FILE_MAPPING);
|
||||
SRAM_DATA = open_mapped_file(SRAM_PATH, SRAM_SIZE_MAX, &SRAM_FILE, &SRAM_FILE_MAPPING);
|
||||
if (SRAM_DATA == NULL) {
|
||||
log_error(plfMxSram, "SRAM will be memory-backed and not syncronised!");
|
||||
SRAM_DATA = malloc(SRAM_SIZE);
|
||||
SRAM_DATA = malloc(SRAM_SIZE_MAX);
|
||||
}
|
||||
|
||||
if (isNew) build_sram();
|
||||
@ -68,7 +68,7 @@ BOOL WINAPI mxsram_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, L
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
DWORD SRAM_VERSION = 0x01000001;
|
||||
DWORD SRAM_SECTOR_SIZE = 4; // Max is 0x800
|
||||
DWORD SRAM_SECTOR_SIZE = MiceConfig.sysconf.platform == MICE_PLATFORM_RINGEDGE2 ? 4 : 512;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSRAM_PING: // Get version
|
||||
@ -88,6 +88,8 @@ BOOL WINAPI mxsram_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, L
|
||||
|
||||
PDISK_GEOMETRY out = (PDISK_GEOMETRY)lpOutBuffer;
|
||||
memset(out, 0, sizeof *out);
|
||||
// I'm unsure how these values change specifically for RW, RE1, RE2
|
||||
// I'm also unsure (ie highly doubtful) it truly matters.
|
||||
out->Cylinders.QuadPart = 256;
|
||||
out->MediaType = FixedMedia;
|
||||
out->TracksPerCylinder = 2;
|
||||
@ -119,8 +121,8 @@ BOOL mxsram_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfByte
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(plfMxSram, "sram write 0x%04x bytes at 0x%04x", nNumberOfBytesToWrite,
|
||||
ctx->m_Pointer.LowPart);
|
||||
if (ctx->m_Pointer.LowPart + nNumberOfBytesToWrite >= SRAM_SIZE) {
|
||||
nNumberOfBytesToWrite = SRAM_SIZE - ctx->m_Pointer.LowPart;
|
||||
if (ctx->m_Pointer.LowPart + nNumberOfBytesToWrite >= SRAM_SIZE_MAX) {
|
||||
nNumberOfBytesToWrite = SRAM_SIZE_MAX - ctx->m_Pointer.LowPart;
|
||||
}
|
||||
ensure_valid_sram();
|
||||
memcpy(SRAM_DATA + ctx->m_Pointer.LowPart, lpBuffer, nNumberOfBytesToWrite);
|
||||
@ -132,8 +134,8 @@ BOOL mxsram_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesT
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(plfMxSram, "sram read 0x%04x bytes at 0x%04x", nNumberOfBytesToRead,
|
||||
ctx->m_Pointer.LowPart);
|
||||
if (ctx->m_Pointer.LowPart + nNumberOfBytesToRead >= SRAM_SIZE) {
|
||||
nNumberOfBytesToRead = SRAM_SIZE - ctx->m_Pointer.LowPart;
|
||||
if (ctx->m_Pointer.LowPart + nNumberOfBytesToRead >= SRAM_SIZE_MAX) {
|
||||
nNumberOfBytesToRead = SRAM_SIZE_MAX - ctx->m_Pointer.LowPart;
|
||||
}
|
||||
ensure_valid_sram();
|
||||
memcpy((LPVOID)lpBuffer, SRAM_DATA + ctx->m_Pointer.LowPart, nNumberOfBytesToRead);
|
||||
|
@ -1,14 +1,166 @@
|
||||
#include "common.h"
|
||||
#include "devices/_devices.h"
|
||||
#include "drivers/jvs_boards/jvs.h"
|
||||
#include "input.h"
|
||||
#include "key_config.h"
|
||||
|
||||
#define IS_GAME(match) (strncmp(game_id, #match, 4) == 0)
|
||||
|
||||
void mice_got_game_id(char game_id[4]) {
|
||||
static char last_game_id[4] = { '_', '_', '_', '_' };
|
||||
MICE_BUTTON_BINDING maimaiDefaultBindings[31] = {
|
||||
// Coins
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '1' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '2' },
|
||||
// Test
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
// 1P
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'E' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'W' },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'D' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'C' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'X' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'Z' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'A' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = 'Q' },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
// 2P
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD9 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD8 },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD6 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD3 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD2 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD1 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD4 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = TRUE, .m_AsyncKey.m_Key = VK_NUMPAD7 },
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
};
|
||||
MICE_BUTTON_BINDING apmDefaultBindings[31] = {
|
||||
// Coins
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_F1 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_F2 },
|
||||
// Test
|
||||
{ .m_Type = MICE_BB_TYPE_UNBOUND },
|
||||
// 1P
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_RETURN },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '*' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_UP },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_DOWN },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_LEFT },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_RIGHT },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = '1' }, // 1P Light
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = '2' }, // 1P Middle
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = '3' }, // 1P Heavy
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '4' }, // 1P Exs
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '5' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '6' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
|
||||
|
||||
if (memcmp(game_id, last_game_id, 4) == 0) return;
|
||||
memcpy(last_game_id, game_id, 4);
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_BACK },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = '-' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD8 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD2 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD4 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = VK_NUMPAD6 },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'Q' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'W' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'E' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'R' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'T' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY, .m_Invert = FALSE, .m_AsyncKey.m_Key = 'Y' },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
|
||||
{ .m_Type = MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
.m_Invert = FALSE,
|
||||
.m_AsyncKey.m_Key = MICE_BB_TYPE_UNBOUND },
|
||||
};
|
||||
|
||||
void _MiceSetupMaimai() {
|
||||
MiceConfig.devices.com1 = "";
|
||||
MiceConfig.devices.com2 = "aime_tn32msec";
|
||||
MiceConfig.devices.com3 = "maitouch";
|
||||
MiceConfig.devices.com5 = "";
|
||||
MiceConfig.devices.com6 = "mailed";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "mailed";
|
||||
|
||||
// Maimai is going to keep checking COM5 and COM7; we don't care.
|
||||
MiceConfig.devices.add_idlers = false;
|
||||
|
||||
MiceConfig.sysconf.dipsw = 0b01111000;
|
||||
MiceConfig.window.nosize = true;
|
||||
|
||||
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
|
||||
|
||||
free(_MiceJvsBoards[0].m_Bindings);
|
||||
_MiceJvsBoards[0].m_Bindings = malloc(sizeof maimaiDefaultBindings);
|
||||
memcpy(_MiceJvsBoards[0].m_Bindings, maimaiDefaultBindings, sizeof maimaiDefaultBindings);
|
||||
_MiceJvsBoards[0].m_NumButtons = _countof(maimaiDefaultBindings);
|
||||
_MiceJvsBoards[0].m_Coins = 2;
|
||||
_MiceJvsBoards[0].m_Players = 2;
|
||||
_MiceJvsBoards[0].m_ButtonsPerPlayer = 14;
|
||||
free(_MiceJvsBoards[0].m_ButtonStates);
|
||||
_MiceJvsBoards[0].m_ButtonStates =
|
||||
malloc(_countof(maimaiDefaultBindings) * sizeof *_MiceJvsBoards[0].m_ButtonStates);
|
||||
|
||||
// Maimai is going to check if these exist. They do, now.
|
||||
make_dirs(MiceIpcRelativePath("dev\\w\\maimai"));
|
||||
make_dirs(MiceIpcRelativePath("dev\\v\\maimai"));
|
||||
make_dirs(MiceIpcRelativePath("dev\\y\\maimai_deliver\\maimai"));
|
||||
}
|
||||
void _MiceSetupApm() {
|
||||
MiceConfig.devices.com1 = "";
|
||||
MiceConfig.devices.com2 = "";
|
||||
MiceConfig.devices.com3 = "";
|
||||
MiceConfig.devices.com5 = "";
|
||||
MiceConfig.devices.com6 = "";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "";
|
||||
|
||||
MiceConfig.sysconf.dipsw = 0b01000000; // 720p
|
||||
|
||||
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
|
||||
|
||||
free(_MiceJvsBoards[0].m_Bindings);
|
||||
_MiceJvsBoards[0].m_Bindings = malloc(sizeof apmDefaultBindings);
|
||||
memcpy(_MiceJvsBoards[0].m_Bindings, apmDefaultBindings, sizeof apmDefaultBindings);
|
||||
_MiceJvsBoards[0].m_NumButtons = _countof(apmDefaultBindings);
|
||||
_MiceJvsBoards[0].m_Coins = 2;
|
||||
_MiceJvsBoards[0].m_Players = 2;
|
||||
_MiceJvsBoards[0].m_ButtonsPerPlayer = 14;
|
||||
free(_MiceJvsBoards[0].m_ButtonStates);
|
||||
_MiceJvsBoards[0].m_ButtonStates =
|
||||
malloc(_countof(apmDefaultBindings) * sizeof *_MiceJvsBoards[0].m_ButtonStates);
|
||||
}
|
||||
|
||||
void _MiceGotGameId(char game_id[4]) {
|
||||
static bool gotGameId = false;
|
||||
if (gotGameId) return;
|
||||
if (game_id[0] != 'S') return;
|
||||
if (game_id[1] < 'A' || game_id[1] > 'Z') return;
|
||||
if (game_id[2] < 'A' || game_id[2] > 'Z') return;
|
||||
if (game_id[3] < 'A' || game_id[3] > 'Z') return;
|
||||
gotGameId = true;
|
||||
|
||||
if (!MiceConfig.devices.do_auto) return;
|
||||
|
||||
@ -18,79 +170,47 @@ void mice_got_game_id(char game_id[4]) {
|
||||
IS_GAME(SDDZ /* maimai MiLK [PLUS] */) || IS_GAME(SDEY /* maimai FiNALE */) ||
|
||||
IS_GAME(SBYC /* maimai china */)) {
|
||||
log_info(plfBoot, "Detect game MaiMai");
|
||||
|
||||
MiceConfig.devices.com1 = "";
|
||||
MiceConfig.devices.com2 = "aime_tn32msec";
|
||||
MiceConfig.devices.com3 = "maitouch";
|
||||
MiceConfig.devices.com5 = "";
|
||||
MiceConfig.devices.com6 = "mailed";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "mailed";
|
||||
|
||||
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
|
||||
|
||||
if (!jvsKeybindings[0].notdefault) {
|
||||
// Zero and invert all buttons
|
||||
memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
|
||||
memset(&jvsKeybindings[0].invert[3 * 2], 1, 12 * 2);
|
||||
|
||||
// Setup default keybinds
|
||||
jvsKeybindings[0].buttons[6 * 2] = 'A'; // 1P1
|
||||
jvsKeybindings[0].buttons[5 * 2] = 'Q'; // 1P2
|
||||
jvsKeybindings[0].buttons[8 * 2] = 'W'; // 1P3
|
||||
jvsKeybindings[0].buttons[9 * 2] = 'E'; // 1P4
|
||||
jvsKeybindings[0].buttons[10 * 2] = 'D'; // 1P5
|
||||
jvsKeybindings[0].buttons[11 * 2] = 'C'; // 1P6
|
||||
jvsKeybindings[0].buttons[12 * 2] = 'X'; // 1P7
|
||||
jvsKeybindings[0].buttons[13 * 2] = 'Z'; // 1P8
|
||||
|
||||
jvsKeybindings[0].buttons[6 * 2 + 1] = VK_NUMPAD4; // 2P1
|
||||
jvsKeybindings[0].buttons[5 * 2 + 1] = VK_NUMPAD7; // 2P2
|
||||
jvsKeybindings[0].buttons[8 * 2 + 1] = VK_NUMPAD8; // 2P3
|
||||
jvsKeybindings[0].buttons[9 * 2 + 1] = VK_NUMPAD9; // 2P4
|
||||
jvsKeybindings[0].buttons[10 * 2 + 1] = VK_NUMPAD6; // 2P5
|
||||
jvsKeybindings[0].buttons[11 * 2 + 1] = VK_NUMPAD3; // 2P6
|
||||
jvsKeybindings[0].buttons[12 * 2 + 1] = VK_NUMPAD2; // 2P7
|
||||
jvsKeybindings[0].buttons[13 * 2 + 1] = VK_NUMPAD1; // 2P8
|
||||
}
|
||||
} else if (IS_GAME(SBYG /* APM2 */)) {
|
||||
_MiceSetupMaimai();
|
||||
} else if (IS_GAME(SBYG /* APM2 */) || IS_GAME(SDCM /* UNIB */)) {
|
||||
log_info(plfBoot, "Detect game APM2");
|
||||
|
||||
MiceConfig.devices.com1 = "";
|
||||
MiceConfig.devices.com2 = "";
|
||||
MiceConfig.devices.com3 = "";
|
||||
MiceConfig.devices.com5 = "";
|
||||
MiceConfig.devices.com6 = "";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "";
|
||||
_MiceSetupApm();
|
||||
|
||||
if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
|
||||
// MiceConfig.devices.com1 = "";
|
||||
// MiceConfig.devices.com2 = "";
|
||||
// MiceConfig.devices.com3 = "";
|
||||
// MiceConfig.devices.com5 = "";
|
||||
// MiceConfig.devices.com6 = "";
|
||||
// MiceConfig.devices.com7 = "";
|
||||
// MiceConfig.devices.com8 = "";
|
||||
|
||||
if (!jvsKeybindings[0].notdefault) {
|
||||
puts("!!");
|
||||
// if (MiceConfig.keys.board_count == 0) MiceConfig.keys.board_count = 1;
|
||||
|
||||
// Zero all buttons
|
||||
memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
|
||||
memset(&jvsKeybindings[0].invert[3 * 2], 0, 12 * 2);
|
||||
// if (!jvsKeybindings[0].notdefault) {
|
||||
// puts("!!");
|
||||
|
||||
jvsKeybindings[0].buttons[0 * 2] = VK_BACK;
|
||||
jvsKeybindings[0].buttons[1 * 2] = VK_RETURN;
|
||||
// // Zero all buttons
|
||||
// memset(&jvsKeybindings[0].buttons[3 * 2], 0, 12 * 2);
|
||||
// memset(&jvsKeybindings[0].invert[3 * 2], 0, 12 * 2);
|
||||
|
||||
jvsKeybindings[0].buttons[3 * 2] = VK_UP;
|
||||
jvsKeybindings[0].buttons[4 * 2] = VK_DOWN;
|
||||
jvsKeybindings[0].buttons[5 * 2] = VK_LEFT;
|
||||
jvsKeybindings[0].buttons[6 * 2] = VK_RIGHT;
|
||||
// jvsKeybindings[0].buttons[0 * 2] = VK_BACK;
|
||||
// jvsKeybindings[0].buttons[1 * 2] = VK_RETURN;
|
||||
|
||||
jvsKeybindings[0].buttons[7 * 2] = 'Q';
|
||||
jvsKeybindings[0].buttons[8 * 2] = 'W';
|
||||
jvsKeybindings[0].buttons[9 * 2] = 'E';
|
||||
jvsKeybindings[0].buttons[10 * 2] = 'A';
|
||||
jvsKeybindings[0].buttons[11 * 2] = 'S';
|
||||
jvsKeybindings[0].buttons[12 * 2] = 'D';
|
||||
// jvsKeybindings[0].buttons[3 * 2] = VK_UP;
|
||||
// jvsKeybindings[0].buttons[4 * 2] = VK_DOWN;
|
||||
// jvsKeybindings[0].buttons[5 * 2] = VK_LEFT;
|
||||
// jvsKeybindings[0].buttons[6 * 2] = VK_RIGHT;
|
||||
|
||||
// 2P is unbound by default, as a (nice) keymap with both
|
||||
// will probably also involve changing 1P too.
|
||||
}
|
||||
// jvsKeybindings[0].buttons[7 * 2] = 'Q';
|
||||
// jvsKeybindings[0].buttons[8 * 2] = 'W';
|
||||
// jvsKeybindings[0].buttons[9 * 2] = 'E';
|
||||
// jvsKeybindings[0].buttons[10 * 2] = 'A';
|
||||
// jvsKeybindings[0].buttons[11 * 2] = 'S';
|
||||
// jvsKeybindings[0].buttons[12 * 2] = 'D';
|
||||
|
||||
// // 2P is unbound by default, as a (nice) keymap with both
|
||||
// // will probably also involve changing 1P too.
|
||||
// }
|
||||
} else if (IS_GAME(SBVH /* Sega & Sonic All-Stars Racing Arcade */)) {
|
||||
log_info(plfBoot, "Detect game Sega & Sonic All-Stars Racing Arcade");
|
||||
|
||||
@ -101,6 +221,15 @@ void mice_got_game_id(char game_id[4]) {
|
||||
MiceConfig.devices.com6 = "";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "";
|
||||
} else if (IS_GAME(SBWU)) {
|
||||
log_info(plfBoot, "Detect game Gacchu Guts");
|
||||
MiceConfig.devices.com1 = "gacchu_guts_card";
|
||||
MiceConfig.devices.com2 = "gacchu_guts_screen";
|
||||
MiceConfig.devices.com3 = "gacchu_guts_screen";
|
||||
MiceConfig.devices.com5 = "";
|
||||
MiceConfig.devices.com6 = "";
|
||||
MiceConfig.devices.com7 = "";
|
||||
MiceConfig.devices.com8 = "";
|
||||
} else {
|
||||
if (game_id[0] != '\0') {
|
||||
log_warning(plfBoot, "Unknown game ID: %.4s", game_id);
|
||||
@ -109,6 +238,8 @@ void mice_got_game_id(char game_id[4]) {
|
||||
return;
|
||||
}
|
||||
|
||||
save_current_config();
|
||||
MiceConfig.devices.do_auto = false;
|
||||
|
||||
save_current_config(true);
|
||||
start_devices();
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
|
||||
#endif
|
||||
#include "../devices/smb_at24c64an.h"
|
||||
#include "../drivers/jvs_boards/jvs.h"
|
||||
#include "../key_config.h"
|
||||
#include "cimgui.h"
|
||||
#include "imgui/backends/GL/freeglut.h"
|
||||
@ -15,15 +16,20 @@ const ImVec4 DISABLED_COL = { .7f, .7f, .7f, 1.0f };
|
||||
const ImVec4 WARN_COL = { 1.0f, 1.0f, .1f, 1.0f };
|
||||
const ImVec4 DANGER_COL = { 1.0f, .1f, .1f, 1.0f };
|
||||
|
||||
struct {
|
||||
typedef struct JVS_BUTTON_NAME {
|
||||
const char* name;
|
||||
int index;
|
||||
int pinNum;
|
||||
} JVS_BUTTON_NAMES[JVS_BUTTON_PAIR_COUNT] = {
|
||||
} JVS_BUTTON_NAME, *PJVS_BUTTON_NAME;
|
||||
JVS_BUTTON_NAME JVS_BUTTON_NAMES[JVS_BUTTON_PAIR_COUNT] = {
|
||||
{ "Coin", 45 }, { "Start", 17 }, { "Service", 41 }, { "UP", 23 }, { "DOWN", 25 },
|
||||
{ "LEFT", 21 }, { "RIGHT", 19 }, { "Push 1", 27 }, { "Push 2", 29 }, { "Push 3", 31 },
|
||||
{ "Push 4", 33 }, { "Push 5", 35 }, { "Push 6", 37 }, { "Push 7", 39 }, { "Push 8", 47 },
|
||||
};
|
||||
JVS_BUTTON_NAME JVS_BUTTON_NAMES_MAIMAI[14] = {
|
||||
{ "Coin" }, { "Button 1" }, { "Button 2" }, { "Button 3" }, { "Button 4" },
|
||||
{ "Button 5" }, { "Button 6" }, { "Button 7" }, { "Button 8" },
|
||||
};
|
||||
|
||||
const char* RESOLUTION_NAMES[] = {
|
||||
"Unspecified", "640x480", "1024x600", "1024x768",
|
||||
@ -176,11 +182,10 @@ void hud_eeprom(ImGuiKey open_key) {
|
||||
if (igIsKeyPressed_Bool(open_key, false)) showEeprom = !showEeprom;
|
||||
|
||||
// TODO: Less hacky :)
|
||||
extern BYTE EEPROM_DATA[0x2000];
|
||||
extern LPBYTE EEPROM_DATA;
|
||||
|
||||
editor.Open = showEeprom;
|
||||
if (showEeprom)
|
||||
MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, sizeof EEPROM_DATA, 0x000);
|
||||
if (showEeprom) MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, 0x2000, 0x000);
|
||||
}
|
||||
void hud_sram(ImGuiKey open_key) {
|
||||
static MemoryEditor editor;
|
||||
@ -239,7 +244,7 @@ bool AddSettingBool(const char* name, const char* help, bool* value) {
|
||||
igNextColumn();
|
||||
igPopID();
|
||||
|
||||
if (changed) save_current_config();
|
||||
if (changed) save_current_config(false);
|
||||
return changed;
|
||||
}
|
||||
|
||||
@ -257,7 +262,7 @@ bool AddSettingString(const char* name, const char* help, char** value) {
|
||||
int newLen = strlen(buffer) + 1;
|
||||
*value = realloc(*value, newLen);
|
||||
memcpy(*value, buffer, newLen);
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igNextColumn();
|
||||
@ -283,7 +288,7 @@ bool AddSettingIPv4(const char* name, const char* help, unsigned int* value) {
|
||||
if (sscanf(buffer, "%hhu.%hhu.%hhu.%hhu%n", &a, &b, &c, &d, &n) == 4 &&
|
||||
n == strlen(buffer)) {
|
||||
*value = (a << 24) | (b << 16) | (c << 8) | d;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
} else {
|
||||
changed = false;
|
||||
}
|
||||
@ -349,6 +354,8 @@ bool igDipsw(const char* label, bool* value) {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
#define SERIAL_HELP \
|
||||
"This value was automatically generated for you and uniquely identifies your computer"
|
||||
void tab_settings_system() {
|
||||
igColumns(2, "SettingsSystem", true);
|
||||
igTextUnformatted("Name", NULL);
|
||||
@ -374,7 +381,7 @@ void tab_settings_system() {
|
||||
if (igRadioButton_Bool("##JPN", MiceConfig.sysconf.region == 1)) {
|
||||
MiceConfig.sysconf.region = 1;
|
||||
staticChanged = true;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igSameLine(0.0, -1.0);
|
||||
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
@ -384,7 +391,7 @@ void tab_settings_system() {
|
||||
if (igRadioButton_Bool("##USA", MiceConfig.sysconf.region == 2)) {
|
||||
MiceConfig.sysconf.region = 2;
|
||||
staticChanged = true;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igSameLine(0.0, -1.0);
|
||||
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
@ -394,7 +401,7 @@ void tab_settings_system() {
|
||||
if (igRadioButton_Bool("##EXP", MiceConfig.sysconf.region == 4)) {
|
||||
MiceConfig.sysconf.region = 4;
|
||||
staticChanged = true;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igSameLine(0.0, -1.0);
|
||||
igSeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
@ -404,16 +411,29 @@ void tab_settings_system() {
|
||||
if (igRadioButton_Bool("##", MiceConfig.sysconf.region == 8)) {
|
||||
MiceConfig.sysconf.region = 8;
|
||||
staticChanged = true;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igNextColumn();
|
||||
igPopID();
|
||||
}
|
||||
staticChanged |= AddSettingBool("Rental", NULL, &MiceConfig.sysconf.rental);
|
||||
staticChanged |=
|
||||
AddSettingString("Serial", "Main board serial number", &MiceConfig.sysconf.serial);
|
||||
if (staticChanged) build_eeprom();
|
||||
|
||||
// The 'M' prefix isn't technically foolproof, but it's good enough for a simple help message
|
||||
staticChanged |= AddSettingString(
|
||||
"PCB serial number",
|
||||
(MiceConfig.sysconf.serial && MiceConfig.sysconf.serial[0] == 'M' ? SERIAL_HELP : NULL),
|
||||
&MiceConfig.sysconf.serial);
|
||||
if (staticChanged) {
|
||||
build_eeprom();
|
||||
save_current_config(false);
|
||||
}
|
||||
if (AddSettingString(
|
||||
"Keychip serial number",
|
||||
(MiceConfig.sysconf.keyid && MiceConfig.sysconf.keyid[0] == 'M' ? SERIAL_HELP : NULL),
|
||||
&MiceConfig.sysconf.keyid)) {
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igSeparator();
|
||||
|
||||
@ -428,7 +448,7 @@ void tab_settings_system() {
|
||||
vec0)) {
|
||||
MiceConfig.sysconf.dipsw =
|
||||
((MiceConfig.sysconf.dipsw & 0b1'000'1111) | (i << 4)) & 0xff;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
if (is_selected) igSetItemDefaultFocus();
|
||||
}
|
||||
@ -445,7 +465,7 @@ void tab_settings_system() {
|
||||
vec0)) {
|
||||
MiceConfig.sysconf.dipsw =
|
||||
((MiceConfig.sysconf.dipsw & 0b1111'0'111) | (i << 3)) & 0xff;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
if (is_selected) igSetItemDefaultFocus();
|
||||
}
|
||||
@ -461,7 +481,7 @@ void tab_settings_system() {
|
||||
if (i != 0) igSameLine(0.0, 2);
|
||||
if (igDipsw("", &val)) {
|
||||
MiceConfig.sysconf.dipsw = (MiceConfig.sysconf.dipsw & ~(1 << i)) | (val << i);
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igPopID();
|
||||
}
|
||||
@ -503,7 +523,7 @@ void tab_settings_window() {
|
||||
igEndDisabled();
|
||||
igEndDisabled();
|
||||
|
||||
if (changed) save_current_config();
|
||||
if (changed) save_current_config(false);
|
||||
|
||||
igEndColumns();
|
||||
}
|
||||
@ -518,6 +538,11 @@ void tab_settings_network() {
|
||||
igSeparator();
|
||||
|
||||
bool networkChanged = false;
|
||||
networkChanged |=
|
||||
AddSettingIPv4("Real Upstream DNS",
|
||||
"When not set to 0.0.0.0, used in place of any system configured servers.",
|
||||
&MiceConfig.network.upstream_dns_server);
|
||||
igSeparator();
|
||||
networkChanged |= AddSettingIPv4("IP Address", NULL, &MiceConfig.network.ip_address);
|
||||
networkChanged |= AddSettingIPv4("Subnet Mask", NULL, &MiceConfig.network.subnet_mask);
|
||||
networkChanged |= AddSettingIPv4("Gateway", NULL, &MiceConfig.network.gateway);
|
||||
@ -538,7 +563,7 @@ void tab_settings_network() {
|
||||
changed |= AddSettingIPv4("bbrouter.loc", NULL, &MiceConfig.network.bbrouter_loc);
|
||||
changed |= AddSettingIPv4("mobirouter.loc", NULL, &MiceConfig.network.mobirouter_loc);
|
||||
changed |= AddSettingIPv4("dslrouter.loc", NULL, &MiceConfig.network.dslrouter_loc);
|
||||
if (changed) save_current_config();
|
||||
if (changed) save_current_config(false);
|
||||
igSeparator();
|
||||
|
||||
{
|
||||
@ -557,7 +582,7 @@ void tab_settings_network() {
|
||||
NULL, NULL)) {
|
||||
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
|
||||
MiceConfig.network.mac = (MiceConfig.network.mac & 0x00FFFF) | ((scan & 0xff) << 16);
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igSameLine(0.0, 0);
|
||||
igTextUnformatted(":", NULL);
|
||||
@ -568,7 +593,7 @@ void tab_settings_network() {
|
||||
NULL, NULL)) {
|
||||
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
|
||||
MiceConfig.network.mac = (MiceConfig.network.mac & 0xFF00FF) | ((scan & 0xff) << 8);
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
igSameLine(0.0, 0);
|
||||
igTextUnformatted(":", NULL);
|
||||
@ -579,7 +604,7 @@ void tab_settings_network() {
|
||||
NULL, NULL)) {
|
||||
_snscanf_s(buffer, _countof(buffer), "%02x", &scan);
|
||||
MiceConfig.network.mac = (MiceConfig.network.mac & 0xFFFF00) | (scan & 0xff);
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igPopStyleVar(1);
|
||||
@ -641,7 +666,7 @@ void tab_settings_adavanced() {
|
||||
|
||||
igEndColumns();
|
||||
|
||||
if (changed) save_current_config();
|
||||
if (changed) save_current_config(false);
|
||||
}
|
||||
|
||||
void tab_main_settings() {
|
||||
@ -691,90 +716,102 @@ bool igKeyBindPopup(const char* name, int* boundKey) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool igKeyBindPopup_New(const char* name, PMICE_BUTTON_BINDING binding) {
|
||||
if (igBeginPopupModal(name, NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
igText("Press any button");
|
||||
if (igButton("Cancel", vec0)) {
|
||||
igCloseCurrentPopup();
|
||||
igEndPopup();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddSettingButton(int board, int id) {
|
||||
if (MiceInputGetNewBinding(binding)) {
|
||||
igCloseCurrentPopup();
|
||||
igEndPopup();
|
||||
return true;
|
||||
}
|
||||
|
||||
igEndPopup();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddSettingButton(PMICE_JVS board, int player, int button) {
|
||||
char keyName[32];
|
||||
static int currentlyBinding;
|
||||
|
||||
char pinInfo[32];
|
||||
snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[id].pinNum,
|
||||
JVS_BUTTON_NAMES[id].pinNum + 1);
|
||||
AddSetting(JVS_BUTTON_NAMES[id].name, pinInfo);
|
||||
if (jvsKeybindings[board].buttons[id * 2] == 0) {
|
||||
igTextColored(DISABLED_COL, "None");
|
||||
} else {
|
||||
GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2], MAPVK_VK_TO_VSC) << 16,
|
||||
keyName, _countof(keyName));
|
||||
igTextUnformatted(keyName, NULL);
|
||||
int index = player * board->m_ButtonsPerPlayer + button + board->m_Coins + 1;
|
||||
|
||||
PMICE_BUTTON_BINDING bind = &(board->m_Bindings[index]);
|
||||
|
||||
switch (bind->m_Type) {
|
||||
case MICE_BB_TYPE_UNBOUND:
|
||||
igTextColored(DISABLED_COL, "None");
|
||||
break;
|
||||
case MICE_BB_TYPE_DI_JOY:
|
||||
switch (bind->m_DIJoy.m_ButtonMajor) {
|
||||
case MICE_BUTTON_MAJOR_AXIS:
|
||||
igTextColored(DISABLED_COL, "Axis");
|
||||
break;
|
||||
case MICE_BUTTON_MAJOR_DPAD:
|
||||
igText("D-Pad %s", bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_UP ? "Up"
|
||||
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_DOWN ? "Down"
|
||||
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_LEFT ? "Left"
|
||||
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_RIGHT ? "Right"
|
||||
: "??");
|
||||
break;
|
||||
case MICE_BUTTON_MAJOR_BUTTON:
|
||||
igText("Button %d", bind->m_DIJoy.m_ButtonMinor + 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MICE_BB_TYPE_GET_ASYNC_KEY:
|
||||
GetKeyNameTextA(MapVirtualKey(bind->m_AsyncKey.m_Key, MAPVK_VK_TO_VSC) << 16, keyName,
|
||||
_countof(keyName));
|
||||
igTextUnformatted(keyName, NULL);
|
||||
break;
|
||||
}
|
||||
igNextColumn();
|
||||
|
||||
char name[16];
|
||||
char name2[16];
|
||||
char clear[16];
|
||||
char clear2[16];
|
||||
char invertName[16];
|
||||
char invertName2[16];
|
||||
snprintf(name, _countof(name), "Bind##Bind%d", id);
|
||||
snprintf(name2, _countof(name2), "Bind##Bind2p%d", id);
|
||||
snprintf(clear, _countof(clear), "Clear##Bind%d", id);
|
||||
snprintf(clear2, _countof(clear2), "Clear##Bind2p%d", id);
|
||||
snprintf(invertName, _countof(invertName), "##Invert%d", id);
|
||||
snprintf(invertName2, _countof(invertName2), "##Invert2p%d", id);
|
||||
snprintf(name, _countof(name), "Bind##Bind%d", index);
|
||||
snprintf(clear, _countof(clear), "Clear##Bind%d", index);
|
||||
snprintf(invertName, _countof(invertName), "##Invert%d", index);
|
||||
|
||||
if (igButton(name, vec0)) {
|
||||
currentlyBinding = 1;
|
||||
MiceInputGetNewBinding(NULL);
|
||||
igOpenPopup_Str(name, ImGuiPopupFlags_None);
|
||||
}
|
||||
if (jvsKeybindings[board].buttons[id * 2]) {
|
||||
|
||||
if (bind->m_Type != MICE_BB_TYPE_UNBOUND) {
|
||||
igSameLine(0, -1);
|
||||
if (igButton(clear, vec0)) {
|
||||
jvsKeybindings[board].buttons[id * 2] = 0;
|
||||
save_current_config();
|
||||
bind->m_Type = MICE_BB_TYPE_UNBOUND;
|
||||
save_current_config(false);
|
||||
}
|
||||
}
|
||||
igNextColumn();
|
||||
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2]);
|
||||
if (igCheckbox(invertName, &jvsKeybindings[board].invert[id * 2])) save_current_config();
|
||||
igBeginDisabled(bind->m_Type == MICE_BB_TYPE_UNBOUND);
|
||||
if (igCheckbox(invertName, (bool*)&bind->m_Invert)) save_current_config(false);
|
||||
igEndDisabled();
|
||||
igNextColumn();
|
||||
|
||||
if (jvsKeybindings[board].buttons[id * 2 + 1] == 0) {
|
||||
igTextColored(DISABLED_COL, "None");
|
||||
} else {
|
||||
GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2 + 1], MAPVK_VK_TO_VSC)
|
||||
<< 16,
|
||||
keyName, _countof(keyName));
|
||||
igTextUnformatted(keyName, NULL);
|
||||
}
|
||||
if (igKeyBindPopup_New(name, bind)) save_current_config(false);
|
||||
}
|
||||
|
||||
igNextColumn();
|
||||
if (igButton(name2, vec0)) {
|
||||
currentlyBinding = 2;
|
||||
igOpenPopup_Str(name, ImGuiPopupFlags_None);
|
||||
}
|
||||
if (jvsKeybindings[board].buttons[id * 2 + 1]) {
|
||||
igSameLine(0, -1);
|
||||
if (igButton(clear2, vec0)) {
|
||||
jvsKeybindings[board].buttons[id * 2 + 1] = 0;
|
||||
save_current_config();
|
||||
void AddButtonsForBoard(PMICE_JVS board) {
|
||||
for (DWORD button = 0; button < board->m_ButtonsPerPlayer; button++) {
|
||||
char pinInfo[32];
|
||||
snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[button].pinNum,
|
||||
JVS_BUTTON_NAMES[button].pinNum + 1);
|
||||
AddSetting(JVS_BUTTON_NAMES[button].name, pinInfo);
|
||||
|
||||
for (DWORD player = 0; player < board->m_Players; player++) {
|
||||
AddSettingButton(board, player, button);
|
||||
}
|
||||
}
|
||||
igNextColumn();
|
||||
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2 + 1]);
|
||||
if (igCheckbox(invertName2, &jvsKeybindings[board].invert[id * 2 + 1])) save_current_config();
|
||||
igEndDisabled();
|
||||
|
||||
igNextColumn();
|
||||
|
||||
int boundKey;
|
||||
if (igKeyBindPopup(name, &boundKey)) {
|
||||
if (boundKey != -1) {
|
||||
jvsKeybindings[board].buttons[id * 2 + (currentlyBinding - 1)] = boundKey;
|
||||
jvsKeybindings[board].notdefault = 1;
|
||||
save_current_config();
|
||||
}
|
||||
currentlyBinding = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void tab_jvs_board(int num) {
|
||||
@ -804,7 +841,7 @@ void tab_jvs_board(int num) {
|
||||
|
||||
igSeparator();
|
||||
|
||||
for (int i = 0; i < _countof(JVS_BUTTON_NAMES); i++) AddSettingButton(num, i);
|
||||
AddButtonsForBoard(&_MiceJvsBoards[0]);
|
||||
|
||||
igSeparator();
|
||||
AddSetting("Test", NULL);
|
||||
@ -822,14 +859,14 @@ void tab_jvs_board(int num) {
|
||||
igSameLine(0, -1);
|
||||
if (igButton("Clear##ClearJvsTest", vec0)) {
|
||||
jvsKeybindings[num].test = 0;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
}
|
||||
int boundKey;
|
||||
if (igKeyBindPopup("BindJvsTest", &boundKey))
|
||||
if (boundKey != -1) {
|
||||
jvsKeybindings[num].test = boundKey;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igEndColumns();
|
||||
@ -865,14 +902,14 @@ void tab_system_buttons() {
|
||||
igSameLine(0, -1);
|
||||
if (igButton("Clear##ClearTest", vec0)) {
|
||||
MiceConfig.keys.test = 0;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
}
|
||||
igNextColumn();
|
||||
if (igKeyBindPopup("BindSysTest", &boundKey))
|
||||
if (boundKey != -1) {
|
||||
MiceConfig.keys.test = boundKey;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
igTextUnformatted("System Service", NULL);
|
||||
@ -891,14 +928,14 @@ void tab_system_buttons() {
|
||||
igSameLine(0, -1);
|
||||
if (igButton("Clear##ClearService", vec0)) {
|
||||
MiceConfig.keys.service = 0;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
}
|
||||
igNextColumn();
|
||||
if (igKeyBindPopup("BindSysService", &boundKey))
|
||||
if (boundKey != -1) {
|
||||
MiceConfig.keys.service = boundKey;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -907,7 +944,7 @@ void tab_main_keybinds() {
|
||||
ImGuiInputTextFlags_None)) {
|
||||
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
|
||||
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
|
||||
save_current_config();
|
||||
save_current_config(false);
|
||||
}
|
||||
|
||||
if (igBeginTabBar("JVSBoards", 0)) {
|
||||
@ -929,7 +966,8 @@ void tab_main_keybinds() {
|
||||
|
||||
void tab_main_aime_cards() {
|
||||
igText(
|
||||
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can be "
|
||||
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can "
|
||||
"be "
|
||||
"specified as either an NFC ID or an access code.\nIf a card file is present, it will be "
|
||||
"used preferentially.");
|
||||
|
||||
@ -944,7 +982,7 @@ void tab_main_aime_cards() {
|
||||
|
||||
igEndColumns();
|
||||
|
||||
if (changed) save_current_config();
|
||||
if (changed) save_current_config(false);
|
||||
}
|
||||
|
||||
void hud_control(ImGuiKey open_key) {
|
||||
|
@ -1,47 +1,132 @@
|
||||
#include "drive.h"
|
||||
|
||||
physical_disk_t SSD = {
|
||||
.m_SerialNumber = 0x00144DB0,
|
||||
/* ================ BOOT SSD ================ */
|
||||
|
||||
// 60GB SSD used by maimai and Project Diva
|
||||
physical_disk_t SSD_60GB = {
|
||||
.m_SerialNumber = 0x4d696365,
|
||||
|
||||
.m_BusType = BusTypeAta,
|
||||
.m_BootPartition = 1,
|
||||
.m_HasSegaboot = TRUE,
|
||||
.m_BlockSize = BLOCK_SIZE_HDD,
|
||||
// Number of physical sectors. 59.9885 GiB
|
||||
.m_TotalSize = 125805015, // = (sum of parts) + (n * 63)
|
||||
.m_DiskType = DiskType_HardDisk,
|
||||
.m_IsFormatted = true,
|
||||
.m_Partitions = {
|
||||
// 1.5GB boot partition
|
||||
{ .m_Size = 0x300B85, .m_Filesystem = MBR_FS_NTFS },
|
||||
// 1.5GB recovery partition
|
||||
{ .m_Size = 0x300BC4, .m_Filesystem = MBR_FS_NTFS },
|
||||
},
|
||||
.m_Extended = {
|
||||
// 512MB OS update
|
||||
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
|
||||
// 2GB patch0
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
|
||||
// 2GB patch1
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
|
||||
// 40GB appdata
|
||||
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
|
||||
// 16GB original0
|
||||
{ 0x20014aa, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
|
||||
{ 0 },
|
||||
},
|
||||
};
|
||||
// 30GB SSD used by all other RingEdge and RingEdge2 games
|
||||
physical_disk_t SSD_30GB = {
|
||||
.m_SerialNumber = 0x4d696365,
|
||||
|
||||
.m_BusType = BusTypeAta,
|
||||
.m_BootPartition = 1,
|
||||
.m_HasSegaboot = TRUE,
|
||||
.m_BlockSize = BLOCK_SIZE_HDD,
|
||||
// Number of physical sectors. 29.9902 GiB
|
||||
// TODO: Recapture these images! My numbers miss-match with Nibs', and neither decrypt
|
||||
// My size: 62894080 (lack 395: Failed reading the last chunk of sectors and gave up)
|
||||
// Nibs's size: 62894471 (lack 4 : Ignored locked sectors)
|
||||
// The following number is theorhetical
|
||||
.m_TotalSize = 62894475, // = (sum of parts) + (n * 63)
|
||||
.m_DiskType = DiskType_HardDisk,
|
||||
.m_IsFormatted = true,
|
||||
.m_Partitions = {
|
||||
// 1GB boot partition
|
||||
{ .m_Size = 0x201c84, .m_Filesystem = MBR_FS_NTFS },
|
||||
// 1GB recovery partition
|
||||
{ .m_Size = 0x201cc3, .m_Filesystem = MBR_FS_NTFS },
|
||||
},
|
||||
.m_Extended = {
|
||||
// 512MB OS update
|
||||
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
|
||||
// 2GB patch0
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
|
||||
// 2GB patch1
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
|
||||
// 15.5GB appdata
|
||||
{ 0x1eead23, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
|
||||
// 8GB original0
|
||||
{ 0x1002996, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
|
||||
{ 0 },
|
||||
},
|
||||
};
|
||||
// 7.5GB SSD used by RingWide games (we're calling that 8GB for naming convenience)
|
||||
physical_disk_t SSD_8GB = {
|
||||
.m_SerialNumber = 0x4d696365,
|
||||
|
||||
.m_BusType = BusTypeAta,
|
||||
.m_BootPartition = 1,
|
||||
.m_HasSegaboot = TRUE,
|
||||
.m_BlockSize = BLOCK_SIZE_HDD,
|
||||
// Number of physical sectors. (Allocated) + (Disk slack)
|
||||
.m_TotalSize = 15711570 + 17070,
|
||||
.m_DiskType = DiskType_HardDisk,
|
||||
.m_IsFormatted = true,
|
||||
.m_Partitions = {
|
||||
// 1GB boot partition
|
||||
{ .m_Size = 0x201c84, .m_Filesystem = MBR_FS_NTFS },
|
||||
// 1GB recovery partition
|
||||
{ .m_Size = 0x201cc3, .m_Filesystem = MBR_FS_NTFS },
|
||||
},
|
||||
.m_Extended = {
|
||||
// 512MB OS update
|
||||
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS },
|
||||
// 1GB patch0
|
||||
{ 0x1f6041, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 },
|
||||
// 1GB patch1
|
||||
{ 0x1f6041, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL },
|
||||
// 337MB appdata
|
||||
{ 0xa8a2c, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL },
|
||||
// 2.7GB original0
|
||||
{ 0x560a60, MBR_FS_FAT16, SPD_Original0, .m_ReadFunc = &ReadFunc_Original0, .m_WriteFunc = &WriteFunc_Original0 },
|
||||
{ 0 },
|
||||
},
|
||||
};
|
||||
|
||||
/* ================ EXTRA HDD ================ */
|
||||
// TODO: Get real sizes for this
|
||||
physical_disk_t APM_HDD = {
|
||||
.m_BusType = BusTypeUsb,
|
||||
.m_HasSegaboot = false,
|
||||
.m_BlockSize = BLOCK_SIZE_HDD,
|
||||
.m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD),
|
||||
.m_DiskType = DiskType_HardDisk,
|
||||
.m_IsFormatted = true,
|
||||
.m_Partitions = {
|
||||
// 1.5GB boot partitions
|
||||
// ~64GB big block
|
||||
{
|
||||
.m_Size = 0x300B85,
|
||||
.m_Filesystem = MBR_FS_NTFS,
|
||||
},
|
||||
// 1.5GB recovery partitions
|
||||
{
|
||||
.m_Size = 0x300BC4,
|
||||
.m_Size = 0x801eb80,
|
||||
.m_Filesystem = MBR_FS_NTFS,
|
||||
.m_Volume = {
|
||||
.m_Name = "APM",
|
||||
.m_MountPoint = 'I', // the APM loader mounts this for us
|
||||
}
|
||||
},
|
||||
},
|
||||
.m_Extended = {
|
||||
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles, .m_WriteFunc = &WriteFunc_OS }, // 512MB OS update
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = &ReadFunc_Patch0, .m_WriteFunc = &WriteFunc_Patch0 }, // 2GB patch0
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL }, // 2GB patch1
|
||||
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL }, // 40GB something
|
||||
{
|
||||
// 16GB partition for the game
|
||||
// The real value here should be "0x20014aa,"
|
||||
0x20014aa, // 16GB, FiNALE
|
||||
|
||||
// Instead, we're going to just allocate ~8GB, the exact size of SDCQ
|
||||
// 0xeafc00, // ~8GB. Lol. Lmao.
|
||||
MBR_FS_FAT16,
|
||||
SPD_Original0,
|
||||
.m_ReadFunc = &ReadFunc_Original0,
|
||||
.m_WriteFunc = &WriteFunc_Original0,
|
||||
},
|
||||
{ 0 },
|
||||
},
|
||||
.m_Extended = {{ 0 }},
|
||||
};
|
||||
|
||||
/* ================ ASSORTED USBS ================ */
|
||||
physical_disk_t UPDATE_USB = {
|
||||
.m_BusType = BusTypeUsb,
|
||||
.m_VID = "13FE",
|
||||
@ -124,6 +209,8 @@ physical_disk_t MAI_USB_DONGLE = {
|
||||
},
|
||||
.m_Extended = {{ 0 }},
|
||||
};
|
||||
|
||||
/* ================ DVD DRIVES ================ */
|
||||
physical_disk_t ALPHA_DVD = {
|
||||
.m_BusType = BusTypeScsi,
|
||||
.m_DeviceType = DeviceTypeCdRom,
|
||||
@ -142,35 +229,20 @@ physical_disk_t ALPHA_DVD = {
|
||||
} },
|
||||
};
|
||||
|
||||
physical_disk_t APM_HDD = {
|
||||
.m_BusType = BusTypeUsb,
|
||||
.m_HasSegaboot = false,
|
||||
.m_BlockSize = BLOCK_SIZE_HDD,
|
||||
.m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD),
|
||||
.m_DiskType = DiskType_HardDisk,
|
||||
.m_IsFormatted = true,
|
||||
.m_Partitions = {
|
||||
// ~64GB big block
|
||||
{
|
||||
.m_Size = 0x801eb80,
|
||||
.m_Filesystem = MBR_FS_NTFS,
|
||||
.m_Volume = {
|
||||
.m_Name = "APM",
|
||||
.m_MountPoint = 'I', // the APM loader mounts this for us
|
||||
}
|
||||
},
|
||||
},
|
||||
.m_Extended = {{ 0 }},
|
||||
};
|
||||
|
||||
physical_disk_t* PHYSICAL_DISKS[] = {
|
||||
&SSD,
|
||||
// &UPDATE_USB,
|
||||
// &DOWNLOAD_USB,
|
||||
// &APM_HDD,
|
||||
|
||||
// &MAI_USB_DONGLE,
|
||||
|
||||
// &LOG_USB,
|
||||
// &ALPHA_DVD,
|
||||
virtual_disk_t AVAILABLE_DISKS[] = {
|
||||
// IMPORTANT: Only one of these can be selected!
|
||||
{ &SSD_60GB, "60GB Boot SSD", TRUE },
|
||||
{ &SSD_30GB, "30GB Boot SSD", FALSE },
|
||||
{ &SSD_8GB, "7.5GB Boot SSD", FALSE },
|
||||
// Extra HDD
|
||||
{ &APM_HDD, "APM Secondary HDD", FALSE },
|
||||
// USBs
|
||||
{ &UPDATE_USB, "Game update USB (SEGA_INS)", FALSE },
|
||||
{ &DOWNLOAD_USB, "Game download USB (SEGA_DL)", FALSE },
|
||||
{ &LOG_USB, "Debug log USB", FALSE },
|
||||
{ &MAI_USB_DONGLE, "maimai bootstrap USB", FALSE },
|
||||
// DVDs
|
||||
{ &ALPHA_DVD, "Alpha DVD", FALSE },
|
||||
|
||||
{ NULL, NULL, FALSE },
|
||||
};
|
||||
|
@ -7,9 +7,10 @@ typedef struct _physical_disk physical_disk_t;
|
||||
typedef struct _disk_partition disk_partition_t;
|
||||
typedef struct _disk_volume disk_volume_t;
|
||||
typedef struct _disk_raw disk_raw_t;
|
||||
typedef struct _virtual_disk virtual_disk_t;
|
||||
|
||||
#define MAX_DISKS 32
|
||||
extern physical_disk_t* PHYSICAL_DISKS[MAX_DISKS];
|
||||
extern virtual_disk_t AVAILABLE_DISKS[MAX_DISKS];
|
||||
|
||||
typedef BOOL(mice_partition_read_function_t)(DWORD nOffset, LPVOID lpBuffer,
|
||||
DWORD nNumberOfBytesToRead,
|
||||
@ -80,3 +81,10 @@ struct _physical_disk {
|
||||
disk_partition_t m_Partitions[4];
|
||||
disk_partition_t m_Extended[];
|
||||
};
|
||||
|
||||
struct _virtual_disk {
|
||||
physical_disk_t* m_Disk;
|
||||
LPCSTR m_Name;
|
||||
BOOL m_Installed;
|
||||
BOOL m_Attached;
|
||||
};
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "../../util/_util.h"
|
||||
#include "../files.h"
|
||||
|
||||
static DWORD _AttachedPhysicalDisks = 0;
|
||||
|
||||
/*
|
||||
First 512 bytes of SPD_Original0:
|
||||
LOADER::LoadBootIDHeader
|
||||
@ -46,10 +48,17 @@ BYTE Original0BootIDHeader[512] = {
|
||||
0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB,
|
||||
};
|
||||
|
||||
physical_disk_t* _GetDisk0() {
|
||||
for (int i = 0; i < MAX_DISKS; i++) {
|
||||
if (AVAILABLE_DISKS[i].m_Installed) return AVAILABLE_DISKS[i].m_Disk;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL ReadFunc_Original0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead) {
|
||||
*lpNumberOfBytesRead = 0;
|
||||
if (!_PathFileExistsA(ORIGINAL0_PATH)) {
|
||||
if (!FileExistsA(ORIGINAL0_PATH)) {
|
||||
log_error(plfDrive, "Failed to open %s (does not exist)", ORIGINAL0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
@ -60,8 +69,11 @@ BOOL ReadFunc_Original0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
|
||||
log_error(plfDrive, "Failed to open %s", ORIGINAL0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
physical_disk_t* lpSsd = _GetDisk0();
|
||||
if (lpSsd == NULL) return FALSE;
|
||||
|
||||
LARGE_INTEGER seekTo;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
|
||||
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
|
||||
BOOL ret = _ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
|
||||
if (!ret) log_error(plfDrive, "Failed to read to %s: %03x", ORIGINAL0_PATH, GetLastError());
|
||||
@ -78,8 +90,11 @@ BOOL WriteFunc_Original0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesTo
|
||||
log_error(plfDrive, "Failed to open %s", ORIGINAL0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
physical_disk_t* lpSsd = _GetDisk0();
|
||||
if (lpSsd == NULL) return FALSE;
|
||||
|
||||
LARGE_INTEGER seekTo;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
|
||||
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
|
||||
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
|
||||
if (!ret) log_error(plfDrive, "Failed to write to %s: %03x", ORIGINAL0_PATH, GetLastError());
|
||||
@ -90,7 +105,7 @@ BOOL WriteFunc_Original0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesTo
|
||||
BOOL ReadFunc_Patch0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead) {
|
||||
*lpNumberOfBytesRead = 0;
|
||||
if (!_PathFileExistsA(PATCH0_PATH)) {
|
||||
if (!FileExistsA(PATCH0_PATH)) {
|
||||
log_error(plfDrive, "Failed to open %s (does not exist)", PATCH0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
@ -101,8 +116,11 @@ BOOL ReadFunc_Patch0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
log_error(plfDrive, "Failed to open %s", PATCH0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
physical_disk_t* lpSsd = _GetDisk0();
|
||||
if (lpSsd == NULL) return FALSE;
|
||||
|
||||
LARGE_INTEGER seekTo;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
|
||||
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
|
||||
BOOL ret = _ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
|
||||
if (!ret) log_error(plfDrive, "Failed to read to %s: %03x", PATCH0_PATH, GetLastError());
|
||||
@ -119,8 +137,11 @@ BOOL WriteFunc_Patch0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesToWri
|
||||
log_error(plfDrive, "Failed to open %s", PATCH0_PATH);
|
||||
return FALSE;
|
||||
}
|
||||
physical_disk_t* lpSsd = _GetDisk0();
|
||||
if (lpSsd == NULL) return FALSE;
|
||||
|
||||
LARGE_INTEGER seekTo;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
|
||||
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)lpSsd->m_BlockSize;
|
||||
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
|
||||
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
|
||||
if (!ret) log_error(plfDrive, "Failed to write to %s: %03x", PATCH0_PATH, GetLastError());
|
||||
@ -217,6 +238,7 @@ BOOL WINAPI x_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode,
|
||||
}
|
||||
}
|
||||
|
||||
extern physical_disk_t ALPHA_DVD; // Bit hacky, but good enough for now
|
||||
BOOL WINAPI q_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
@ -379,14 +401,17 @@ disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName, DWORD match) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (size_t disk = 0; disk < MAX_DISKS && PHYSICAL_DISKS[disk] != NULL; disk++) {
|
||||
for (size_t disk = 0; disk < MAX_DISKS && AVAILABLE_DISKS[disk].m_Disk != NULL; disk++) {
|
||||
if (!AVAILABLE_DISKS[disk].m_Installed) continue;
|
||||
|
||||
for (size_t part = 0; part < 4; part++) {
|
||||
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume);
|
||||
disk_volume_t* volume = &(AVAILABLE_DISKS[disk].m_Disk->m_Partitions[part].m_Volume);
|
||||
if (matchVolume(volume, lpRootPathName, match)) return volume;
|
||||
}
|
||||
|
||||
for (size_t part = 0; PHYSICAL_DISKS[disk]->m_Extended[part].m_PartitionNumber; part++) {
|
||||
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume);
|
||||
for (size_t part = 0; AVAILABLE_DISKS[disk].m_Disk->m_Extended[part].m_PartitionNumber;
|
||||
part++) {
|
||||
disk_volume_t* volume = &(AVAILABLE_DISKS[disk].m_Disk->m_Extended[part].m_Volume);
|
||||
if (matchVolume(volume, lpRootPathName, match)) return volume;
|
||||
}
|
||||
}
|
||||
@ -646,10 +671,41 @@ void init_pd(physical_disk_t* pd) {
|
||||
hook_file(hook);
|
||||
}
|
||||
|
||||
BOOL attach_disk(virtual_disk_t* lpDisk) {
|
||||
if (lpDisk->m_Disk->m_DriveNumber != (DWORD)-1) return FALSE;
|
||||
if (lpDisk->m_Attached) return TRUE;
|
||||
lpDisk->m_Attached = TRUE;
|
||||
|
||||
lpDisk->m_Disk->m_DriveNumber = _AttachedPhysicalDisks++;
|
||||
lpDisk->m_Disk->m_DeviceName[0] = '\0';
|
||||
lpDisk->m_Disk->m_DosDeviceName[0] = '\0';
|
||||
init_pd(lpDisk->m_Disk);
|
||||
return TRUE;
|
||||
}
|
||||
BOOL detach_disk(virtual_disk_t* lpDisk) {
|
||||
if (lpDisk->m_Disk->m_DriveNumber == (DWORD)-1) return FALSE;
|
||||
if (!lpDisk->m_Attached) return TRUE;
|
||||
|
||||
wchar_t hookPath[21];
|
||||
swprintf_s(hookPath, _countof(hookPath), L"\\\\.\\%ls", lpDisk->m_Disk->m_DosDeviceName);
|
||||
|
||||
file_hook_t* hook = unhook_file(hookPath);
|
||||
if (hook == NULL) return FALSE;
|
||||
|
||||
lpDisk->m_Disk->m_DriveNumber = (DWORD)-1;
|
||||
lpDisk->m_Attached = FALSE;
|
||||
free((void*)hook->filename);
|
||||
free(hook);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void init_all_pd() {
|
||||
for (int i = 0; i < MAX_DISKS && PHYSICAL_DISKS[i] != NULL; i++) {
|
||||
PHYSICAL_DISKS[i]->m_DriveNumber = i;
|
||||
init_pd(PHYSICAL_DISKS[i]);
|
||||
for (int i = 0; i < MAX_DISKS && AVAILABLE_DISKS[i].m_Disk != NULL; i++) {
|
||||
AVAILABLE_DISKS[i].m_Disk->m_DriveNumber = (DWORD)-1;
|
||||
AVAILABLE_DISKS[i].m_Attached = FALSE;
|
||||
}
|
||||
for (int i = 0; i < MAX_DISKS && AVAILABLE_DISKS[i].m_Disk != NULL; i++) {
|
||||
if (AVAILABLE_DISKS[i].m_Installed) attach_disk(&AVAILABLE_DISKS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -704,11 +760,6 @@ void hook_drives() {
|
||||
q_drive->DeviceIoControl = &q_drive_DeviceIoControl;
|
||||
q_drive->ReadFile = &q_drive_ReadFile;
|
||||
hook_file(q_drive);
|
||||
// TODO: ewwwwwwwwwwwwwwwwww
|
||||
file_hook_t* q_drive_lower = new_file_hook(L"\\\\.\\q:");
|
||||
q_drive_lower->DeviceIoControl = &q_drive_DeviceIoControl;
|
||||
q_drive_lower->ReadFile = &q_drive_ReadFile;
|
||||
hook_file(q_drive_lower);
|
||||
|
||||
hook("Kernel32.dll", "FindFirstVolumeW", &FakeFindFirstVolumeW, NULL);
|
||||
hook("Kernel32.dll", "FindNextVolumeW", &FakeFindNextVolumeW, NULL);
|
||||
@ -734,14 +785,15 @@ void hook_drives() {
|
||||
|
||||
hook("Winmm.dll", "mciSendStringA", &Fake_mciSendStringA, NULL);
|
||||
|
||||
make_dirs(DISK_PATH);
|
||||
make_dirs(DISK_PATH));
|
||||
|
||||
SegaBootRecordDefault.crc =
|
||||
amiCrc32RCalc(sizeof SegaBootRecordDefault - 4, &SegaBootRecordDefault.version, 0);
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD numberOfBytesRead;
|
||||
if (_PathFileExistsA(SBR0_PATH)) {
|
||||
|
||||
if (FileExistsA(SBR0_PATH)) {
|
||||
hFile =
|
||||
_CreateFileA(SBR0_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
@ -755,7 +807,7 @@ void hook_drives() {
|
||||
// memcpy(&SegaBootRecord0, &SegaBootRecordDefault, sizeof SegaBootRecord0);
|
||||
}
|
||||
|
||||
if (_PathFileExistsA(SBR1_PATH)) {
|
||||
if (FileExistsA(SBR1_PATH)) {
|
||||
hFile =
|
||||
_CreateFileA(SBR1_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
|
@ -15,17 +15,12 @@
|
||||
#include "disks.h"
|
||||
#include "irb.h"
|
||||
|
||||
#define DISK_PATH "dev/disk/"
|
||||
#define SPD_PATH (DISK_PATH "spd.bin")
|
||||
#define SBR0_PATH (DISK_PATH "sbr0.bin")
|
||||
#define SBR1_PATH (DISK_PATH "sbr1.bin")
|
||||
#define ORIGINAL0_PATH (DISK_PATH "original0.bin")
|
||||
#define PATCH0_PATH (DISK_PATH "patch0.bin")
|
||||
|
||||
extern physical_disk_t SSD;
|
||||
extern physical_disk_t UPDATE_USB;
|
||||
extern physical_disk_t LOG_USB;
|
||||
extern physical_disk_t ALPHA_DVD;
|
||||
#define DISK_PATH MiceIpcRelativePath("disk\\"
|
||||
#define SPD_PATH DISK_PATH "spd.bin")
|
||||
#define SBR0_PATH DISK_PATH "sbr0.bin")
|
||||
#define SBR1_PATH DISK_PATH "sbr1.bin")
|
||||
#define ORIGINAL0_PATH DISK_PATH "original0.bin")
|
||||
#define PATCH0_PATH DISK_PATH "patch0.bin")
|
||||
|
||||
extern sbr_t SegaBootRecordDefault;
|
||||
extern sbr_t SegaBootRecord0;
|
||||
@ -35,6 +30,9 @@ extern sbr_t SegaBootRecord1;
|
||||
void init_volume(disk_volume_t* vol);
|
||||
void init_pd(physical_disk_t* pd);
|
||||
void init_all_pd();
|
||||
BOOL attach_disk(virtual_disk_t* lpDisk);
|
||||
BOOL detach_disk(virtual_disk_t* lpDisk);
|
||||
physical_disk_t* _GetDisk0();
|
||||
|
||||
mice_partition_read_function_t ReadFunc_Original0;
|
||||
mice_partition_write_function_t WriteFunc_Original0;
|
||||
|
@ -9,12 +9,17 @@ disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
|
||||
if (find_index == NULL) return NULL;
|
||||
|
||||
while (1) {
|
||||
if (find_index->disk >= MAX_DISKS || PHYSICAL_DISKS[find_index->disk] == NULL) {
|
||||
if (find_index->disk >= MAX_DISKS || AVAILABLE_DISKS[find_index->disk].m_Disk == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!AVAILABLE_DISKS[find_index->disk].m_Installed) {
|
||||
find_index->disk++;
|
||||
find_index->partition = 0;
|
||||
continue;
|
||||
}
|
||||
if (find_index->partition > 3) {
|
||||
if (PHYSICAL_DISKS[find_index->disk]
|
||||
if (AVAILABLE_DISKS[find_index->disk].m_Disk
|
||||
->m_Extended[find_index->partition - 4]
|
||||
.m_PartitionNumber == 0) {
|
||||
find_index->disk++;
|
||||
@ -22,18 +27,18 @@ disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return &(PHYSICAL_DISKS[find_index->disk]
|
||||
return &(AVAILABLE_DISKS[find_index->disk].m_Disk
|
||||
->m_Extended[(find_index->partition++) - 4]
|
||||
.m_Volume);
|
||||
}
|
||||
if (PHYSICAL_DISKS[find_index->disk]
|
||||
if (AVAILABLE_DISKS[find_index->disk].m_Disk
|
||||
->m_Partitions[find_index->partition]
|
||||
.m_PartitionNumber == 0) {
|
||||
find_index->partition = 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
return &(PHYSICAL_DISKS[find_index->disk]->m_Partitions[find_index->partition++].m_Volume);
|
||||
return &(AVAILABLE_DISKS[find_index->disk].m_Disk->m_Partitions[find_index->partition++].m_Volume);
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,7 +338,7 @@ BOOL WINAPI FakeGetDiskFreeSpaceExA(LPCSTR lpDirectoryName,
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// We're going to be remapping the drive to ./dev/, so the free bytes are whatever the current
|
||||
// We're going to be remapping the drive to ./mice/dev/, so the free bytes are whatever the current
|
||||
// real drive has free. No point claiming we have more than we do!
|
||||
return TrueGetDiskFreeSpaceExA(NULL, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes,
|
||||
lpTotalNumberOfFreeBytes);
|
||||
|
@ -72,8 +72,11 @@ BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOI
|
||||
log_error(plfDrive, "Unimeplemented ATA %02X command: %02x", command, data);
|
||||
return FALSE;
|
||||
case IOCTL_DISK_GET_LENGTH_INFO:
|
||||
physical_disk_t* lpSsd = _GetDisk0();
|
||||
if (lpSsd == NULL) return FALSE;
|
||||
|
||||
PGET_LENGTH_INFORMATION pLi = (PGET_LENGTH_INFORMATION)lpOutBuffer;
|
||||
pLi->Length.QuadPart = SSD.m_TotalSize * (long long)SSD.m_BlockSize;
|
||||
pLi->Length.QuadPart = lpSsd->m_TotalSize * (long long)lpSsd->m_BlockSize;
|
||||
*lpBytesReturned = sizeof *pLi;
|
||||
return TRUE;
|
||||
}
|
||||
@ -81,6 +84,8 @@ BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOI
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: File-backed
|
||||
BYTE SEGABOOT_DATA_CACHE[512 * 60] = { 0xff };
|
||||
BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
|
||||
@ -126,7 +131,7 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
}
|
||||
if (ptrLBA <= MBR_LBA_GAP) {
|
||||
// Read within the 63 extra tracks
|
||||
log_error(plfDrive, "Read failed");
|
||||
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -139,7 +144,8 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
DWORD readOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA;
|
||||
|
||||
if (pd->m_Partitions[i].m_ReadFunc == NULL) {
|
||||
log_error(plfDrive, "Attempted read in %d/%d at block offset %08x; No read function",
|
||||
log_error(plfDrive,
|
||||
"Attempted read in %d/%d at block offset %08x; No read function",
|
||||
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset);
|
||||
return FALSE;
|
||||
}
|
||||
@ -230,12 +236,21 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
*lpNumberOfBytesRead = sizeof SegaBootRecord1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (ptrLBA >= headerLBA && ptrLBA < headerLBA + EXT_HEADER_GAP) {
|
||||
DWORD nDataOffset = (ptrLBA - headerLBA - 4) * pd->m_BlockSize;
|
||||
if (nNumberOfBytesToRead > sizeof SEGABOOT_DATA_CACHE - nDataOffset) {
|
||||
nNumberOfBytesToRead = sizeof SEGABOOT_DATA_CACHE - nDataOffset;
|
||||
}
|
||||
memcpy(lpBuffer, SEGABOOT_DATA_CACHE, nNumberOfBytesToRead);
|
||||
*lpNumberOfBytesRead = nNumberOfBytesToRead;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP &&
|
||||
ptrLBA < pd->m_Extended[i].m_PhysicalLBA) {
|
||||
if (ptrLBA >= headerLBA && ptrLBA < headerLBA + EXT_HEADER_GAP) {
|
||||
// Read within the 63 extra tracks
|
||||
log_error(plfDrive, "Read failed");
|
||||
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -244,7 +259,8 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
DWORD readOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA;
|
||||
|
||||
if (pd->m_Extended[i].m_ReadFunc == NULL) {
|
||||
log_error(plfDrive, "Attempted read in %d/%d at block offset %08x; No read function",
|
||||
log_error(plfDrive,
|
||||
"Attempted read in %d/%d at block offset %08x; No read function",
|
||||
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset);
|
||||
return FALSE;
|
||||
}
|
||||
@ -262,7 +278,7 @@ BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRea
|
||||
}
|
||||
}
|
||||
|
||||
log_error(plfDrive, "Read failed");
|
||||
log_error(plfDrive, "Read failed (%08x)", ptrLBA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
#include "../util/_util.h"
|
||||
|
||||
static const bool ALLOW_FILE_PASSTHROUGH = true;
|
||||
|
||||
// TODO: This should be part of MiceFS I think
|
||||
file_hook_t* MiceFSLocateHookW(_In_ LPCWSTR lpFileName);
|
||||
file_hook_t* MiceFSLocateHookW(LPCWSTR lpFileName) {
|
||||
file_hook_t* file_hook = file_hook_list;
|
||||
while (file_hook != NULL) {
|
||||
if (wcscmp(lpFileName, file_hook->filename) == 0 ||
|
||||
(file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) {
|
||||
if (_wcsicmp(lpFileName, file_hook->filename) == 0 ||
|
||||
(file_hook->altFilename != NULL && _wcsicmp(lpFileName, file_hook->altFilename) == 0)) {
|
||||
return file_hook;
|
||||
}
|
||||
file_hook = file_hook->next;
|
||||
@ -19,6 +21,7 @@ file_hook_t* MiceFSLocateHookW(LPCWSTR lpFileName) {
|
||||
|
||||
HANDLE open_hook(file_hook_t* file_hook) {
|
||||
open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t));
|
||||
if (opened == NULL) return INVALID_HANDLE_VALUE;
|
||||
ZeroMemory(opened, sizeof *opened);
|
||||
|
||||
opened->hook = file_hook;
|
||||
@ -51,7 +54,25 @@ void hook_file(file_hook_t* hook) {
|
||||
file_hook_t* hl = file_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
}
|
||||
file_hook_t* unhook_file(LPCWSTR lpFilename) {
|
||||
file_hook_t* hl = file_hook_list;
|
||||
if (hl == NULL) return NULL;
|
||||
file_hook_t* previous = NULL;
|
||||
do {
|
||||
if (_wcsicmp(hl->filename, lpFilename) == 0 || _wcsicmp(hl->altFilename, lpFilename) == 0) {
|
||||
if (previous == NULL)
|
||||
file_hook_list = hl->next;
|
||||
else
|
||||
previous->next = hl->next;
|
||||
return hl;
|
||||
}
|
||||
|
||||
previous = hl;
|
||||
hl = hl->next;
|
||||
} while (hl != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct buffer_file {
|
||||
LPBYTE buffer;
|
||||
@ -116,23 +137,35 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile) {
|
||||
size_t len = wcslen(lpFileName);
|
||||
if (wcscmp(&lpFileName[len - 4], L".dbg") == 0 || wcscmp(&lpFileName[len - 4], L".pdb") == 0) {
|
||||
return TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
}
|
||||
|
||||
file_hook_t* found_fh = MiceFSLocateHookW(lpFileName);
|
||||
if (found_fh != NULL) {
|
||||
HANDLE handle = open_hook(found_fh);
|
||||
log_info(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
if (!ALLOW_FILE_PASSTHROUGH) {
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
HANDLE handle;
|
||||
|
||||
MiceFSRedirectPathW(lpFileName, &lpFileName);
|
||||
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
log_warning(plfHooks, "CreateFileW(%ls) failed", lpFileName);
|
||||
else
|
||||
log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
if (!(_wcsicmp(lpFileName, L"C:\\windows\\system32\\atipblag.dat") == 0 ||
|
||||
wcsncmp(lpFileName, L"\\\\?\\hid#", 8) == 0))
|
||||
log_warning(plfHooks, "CreateFileW(%ls) failed", lpFileName);
|
||||
} else {
|
||||
log_info(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
@ -148,35 +181,31 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
|
||||
log_info(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
if (!ALLOW_FILE_PASSTHROUGH) {
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
MiceFSRedirectPathA(lpFileName, &lpFileName);
|
||||
HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
log_warning(plfHooks, "CreateFileA(%s) failed", lpFileName);
|
||||
else
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
if (_stricmp(lpFileName, "C:\\windows\\system32\\atipblag.dat") != 0)
|
||||
log_warning(plfHooks, "CreateFileA(%s) failed", lpFileName);
|
||||
} else
|
||||
log_misc(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) {
|
||||
MiceFSRedirectPathA(pszPath, &pszPath);
|
||||
BOOL ret = TruePathFileExistsA(pszPath);
|
||||
log_misc(plfHooks, "PathFileExistsA(%s) = %d", pszPath, ret);
|
||||
return ret;
|
||||
}
|
||||
BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) {
|
||||
MiceFSRedirectPathW(pszPath, &pszPath);
|
||||
BOOL ret = TruePathFileExistsW(pszPath);
|
||||
log_misc(plfHooks, "PathFileExistsW(%ls) = %d", pszPath, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeDeleteFileA(LPCSTR pszPath) {
|
||||
if (!ALLOW_FILE_PASSTHROUGH) return FALSE;
|
||||
|
||||
MiceFSRedirectPathA(pszPath, &pszPath);
|
||||
return TrueDeleteFileA(pszPath);
|
||||
}
|
||||
BOOL WINAPI FakeDeleteFileW(LPCWSTR pszPath) {
|
||||
if (!ALLOW_FILE_PASSTHROUGH) return FALSE;
|
||||
|
||||
MiceFSRedirectPathW(pszPath, &pszPath);
|
||||
return TrueDeleteFileW(pszPath);
|
||||
}
|
||||
@ -186,9 +215,6 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
open_hook_t* pHData = GetDataForHandle(hDevice, HDATA_FILE);
|
||||
if (pHData == NULL) {
|
||||
// log_trace(plfHooks, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice,
|
||||
// dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
||||
nOutBufferSize, lpBytesReturned, lpOverlapped);
|
||||
}
|
||||
@ -326,7 +352,6 @@ BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
|
||||
return TrueCloseHandle(hObject);
|
||||
}
|
||||
|
||||
|
||||
void FileTimeToTimet(__time64_t* t, LPFILETIME pft) {
|
||||
ULARGE_INTEGER time_value;
|
||||
time_value.HighPart = pft->dwHighDateTime;
|
||||
@ -405,8 +430,7 @@ void hook_io() {
|
||||
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile);
|
||||
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx);
|
||||
|
||||
hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA);
|
||||
hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW);
|
||||
// PathIsDirectory, PathFileExists, etc just call GetFileAttributes under the hood
|
||||
hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA);
|
||||
hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW);
|
||||
hook("Kernel32.dll", "GetCurrentDirectoryA", FakeGetCurrentDirectoryA,
|
||||
@ -420,10 +444,8 @@ void hook_io() {
|
||||
(void**)&TrueGetFileAttributesA);
|
||||
hook("Kernel32.dll", "GetFileAttributesW", FakeGetFileAttributesW,
|
||||
(void**)&TrueGetFileAttributesW);
|
||||
hook("Kernel32.dll", "CreateDirectoryA", FakeCreateDirectoryA,
|
||||
(void**)&TrueCreateDirectoryA);
|
||||
hook("Kernel32.dll", "CreateDirectoryW", FakeCreateDirectoryW,
|
||||
(void**)&TrueCreateDirectoryW);
|
||||
hook("Kernel32.dll", "CreateDirectoryA", FakeCreateDirectoryA, (void**)&TrueCreateDirectoryA);
|
||||
hook("Kernel32.dll", "CreateDirectoryW", FakeCreateDirectoryW, (void**)&TrueCreateDirectoryW);
|
||||
|
||||
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32);
|
||||
}
|
||||
|
@ -47,8 +47,6 @@ _MICE_FILES BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNum
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
|
||||
_MICE_FILES BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
|
||||
_MICE_FILES BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject);
|
||||
_MICE_FILES BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath);
|
||||
_MICE_FILES BOOL(WINAPI* TruePathFileExistsW)(LPCWSTR pszPath);
|
||||
_MICE_FILES BOOL(WINAPI* TrueDeleteFileA)(LPCSTR lpFileName);
|
||||
_MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName);
|
||||
_MICE_FILES HANDLE(WINAPI* TrueFindFirstFileA)(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
|
||||
@ -93,7 +91,8 @@ static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
|
||||
#define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA)
|
||||
#define _SetFilePointer (TrueSetFilePointer ? TrueSetFilePointer : SetFilePointer)
|
||||
#define _SetFilePointerEx (TrueSetFilePointerEx ? TrueSetFilePointerEx : SetFilePointerEx)
|
||||
#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA)
|
||||
#define _GetFileAttributesW (TrueGetFileAttributesW ? TrueGetFileAttributesW : GetFileAttributesW)
|
||||
// GetFileAttributesA internally calls (hooked)GetFileAttributesW
|
||||
#define _GetCurrentDirectoryA \
|
||||
(TrueGetCurrentDirectoryA ? TrueGetCurrentDirectoryA : GetCurrentDirectoryA)
|
||||
#define _GetCurrentDirectoryW \
|
||||
@ -137,3 +136,4 @@ file_hook_t* new_file_hook(LPCWSTR filename);
|
||||
void hook_file(file_hook_t* hook);
|
||||
void hook_io();
|
||||
void hook_file_with_buffer(LPCWSTR filename, LPBYTE buffer, DWORD nBytes, DWORD access);
|
||||
file_hook_t* unhook_file(LPCWSTR lpFilename);
|
||||
|
@ -1,8 +1,12 @@
|
||||
#include "gui.h"
|
||||
|
||||
#include <detours.h>
|
||||
|
||||
#include "../input.h"
|
||||
|
||||
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
HWND mainWindow;
|
||||
HWND mainWindow = NULL;
|
||||
|
||||
static unsigned int hookType;
|
||||
|
||||
@ -22,41 +26,61 @@ HWND GetProcessWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
BOOL UnFrameWindow(HWND hwnd) {
|
||||
static const LONG frameFlags = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
|
||||
LONG UnFrameWindow(HWND hwnd) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
||||
if (GetLastError() != ERROR_SUCCESS) return style;
|
||||
|
||||
RECT rect;
|
||||
if (!GetClientRect(hwnd, &rect)) return FALSE;
|
||||
if (!GetClientRect(hwnd, &rect)) return style;
|
||||
|
||||
style &= ~(WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU);
|
||||
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
|
||||
// Nothing to style
|
||||
if ((style & frameFlags) == 0) return style;
|
||||
|
||||
SetWindowLongW(hwnd, GWL_STYLE, style);
|
||||
LONG newStyle = style & ~(frameFlags);
|
||||
if (!AdjustWindowRect(&rect, newStyle, FALSE)) return style;
|
||||
|
||||
SetWindowLongW(hwnd, GWL_STYLE, newStyle);
|
||||
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
return style;
|
||||
return newStyle;
|
||||
}
|
||||
|
||||
BOOL FrameWindow(HWND hwnd) {
|
||||
LONG FrameWindow(HWND hwnd) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
||||
if (GetLastError() != ERROR_SUCCESS) return style;
|
||||
|
||||
// Nothing to do
|
||||
if ((style & frameFlags) == frameFlags) return style;
|
||||
|
||||
RECT rect;
|
||||
if (!GetClientRect(hwnd, &rect)) return FALSE;
|
||||
if (!GetClientRect(hwnd, &rect)) return style;
|
||||
|
||||
style |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
|
||||
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
|
||||
LONG newStyle = style | frameFlags;
|
||||
if (!AdjustWindowRect(&rect, newStyle, FALSE)) return style;
|
||||
|
||||
SetWindowLongW(hwnd, GWL_STYLE, style);
|
||||
SetWindowLongW(hwnd, GWL_STYLE, newStyle);
|
||||
|
||||
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
return style;
|
||||
return newStyle;
|
||||
}
|
||||
|
||||
BOOL UnadjustWindowRect(LPRECT prc, DWORD dwStyle, BOOL fMenu) {
|
||||
RECT rc;
|
||||
SetRectEmpty(&rc);
|
||||
BOOL fRc = AdjustWindowRect(&rc, dwStyle, fMenu);
|
||||
if (fRc) {
|
||||
prc->left -= rc.left;
|
||||
prc->top -= rc.top;
|
||||
prc->right -= rc.right;
|
||||
prc->bottom -= rc.bottom;
|
||||
}
|
||||
return fRc;
|
||||
}
|
||||
|
||||
BOOL GetD3D9Device(void** pTable, size_t Size) {
|
||||
@ -155,12 +179,19 @@ void post_win_create(HWND hWnd) {
|
||||
if (hookType == UI_HOOK_DX9) {
|
||||
void* d3d9Device[119];
|
||||
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) {
|
||||
*((PVOID*)&TrueEndScene) = CreateHook32((PVOID)d3d9Device[42], (PVOID)hkEndScene);
|
||||
TrueEndScene = d3d9Device[42];
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach((PVOID*)&TrueEndScene, hkEndScene);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) {
|
||||
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (UINT_PTR)&WndProc, (DWORD_PTR)NULL)) {
|
||||
log_error(plfGUI, "failed to SetWindowSubclass(%d)", GetLastError());
|
||||
}
|
||||
} else {
|
||||
MiceInputInit(hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +206,8 @@ BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMoni
|
||||
}
|
||||
|
||||
void SetupWindowPosition(LPRECT lpRect, DWORD dwStyle) {
|
||||
UnadjustWindowRect(lpRect, dwStyle, FALSE);
|
||||
|
||||
int x = lpRect->left;
|
||||
int y = lpRect->top;
|
||||
int w = lpRect->right - x;
|
||||
@ -191,6 +224,17 @@ void SetupWindowPosition(LPRECT lpRect, DWORD dwStyle) {
|
||||
if (MiceConfig.window.centre) {
|
||||
x = ((monitorRect.right - monitorRect.left) - w) / 2;
|
||||
y = ((monitorRect.bottom - monitorRect.top) - h) / 2;
|
||||
|
||||
// if ((dwStyle & frameFlags) == frameFlags) {
|
||||
// RECT adjustedRect;
|
||||
// memcpy(&adjustedRect, lpRect, sizeof *lpRect);
|
||||
// UnadjustWindowRect(&adjustedRect, dwStyle, FALSE);
|
||||
// // We're going to only adjust y, on the assumption x is unchanged, and even if it is
|
||||
// // it'll be symmetic. y has the titlebar to worry about.
|
||||
// int outerH = adjustedRect.bottom - adjustedRect.top;
|
||||
|
||||
// y += (outerH - h) / 2;
|
||||
// }
|
||||
} else {
|
||||
x = MiceConfig.window.x;
|
||||
y = MiceConfig.window.y;
|
||||
@ -284,12 +328,16 @@ HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDE
|
||||
Adapter = MiceConfig.window.adaptor;
|
||||
|
||||
RECT winRect;
|
||||
GetWindowRect(hFocusWindow, &winRect);
|
||||
DWORD dwStyle = GetWindowLongW(hFocusWindow, GWL_STYLE);
|
||||
SetupWindowPosition(&winRect, dwStyle);
|
||||
if (!GetWindowRect(hFocusWindow, &winRect)) {
|
||||
log_error(plfGUI, "GetWindowRect failed: %d", GetLastError());
|
||||
} else {
|
||||
DWORD dwStyle = GetWindowLongW(hFocusWindow, GWL_STYLE);
|
||||
SetupWindowPosition(&winRect, dwStyle);
|
||||
|
||||
SetWindowPos(hFocusWindow, HWND_TOP, winRect.left, winRect.top, winRect.right - winRect.left,
|
||||
winRect.bottom - winRect.top, 0);
|
||||
// I have no idea why, but this is causing crashes???
|
||||
SetWindowPos(hFocusWindow, HWND_TOP, winRect.left, winRect.top,
|
||||
winRect.right - winRect.left, winRect.bottom - winRect.top, 0);
|
||||
}
|
||||
|
||||
HRESULT res = TrueCreateDevice(this, Adapter, DeviceType, hFocusWindow, BehaviorFlags,
|
||||
pPresentationParameters, ppReturnedDeviceInterface);
|
||||
@ -313,6 +361,9 @@ HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDE
|
||||
}
|
||||
}
|
||||
log_info(plfD3D9, "Device created: %d", res);
|
||||
|
||||
MiceInputInit(hFocusWindow);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -337,12 +388,12 @@ IDirect3D9* WINAPI FakeDirect3DCreate9(UINT SDKVersion) {
|
||||
hookType = UI_HOOK_DX9;
|
||||
|
||||
TrueCreateDevice = pD3D->lpVtbl->CreateDevice;
|
||||
DWORD patch = (DWORD)&FakeCreateDevice;
|
||||
patch_at(&pD3D->lpVtbl->CreateDevice, (char*)&patch, 4);
|
||||
size_t patch = (size_t)&FakeCreateDevice;
|
||||
MiceHookPatchAt(&pD3D->lpVtbl->CreateDevice, (char*)&patch, sizeof patch);
|
||||
|
||||
TrueEnumAdapterModes = pD3D->lpVtbl->EnumAdapterModes;
|
||||
patch = (DWORD)&FakeEnumAdapterModes;
|
||||
patch_at(&pD3D->lpVtbl->EnumAdapterModes, (char*)&patch, 4);
|
||||
patch = (size_t)&FakeEnumAdapterModes;
|
||||
MiceHookPatchAt(&pD3D->lpVtbl->EnumAdapterModes, (char*)&patch, sizeof patch);
|
||||
|
||||
return pD3D;
|
||||
};
|
||||
@ -423,7 +474,7 @@ void hook_gui() {
|
||||
hook("User32.dll", "ChangeDisplaySettingsExA", FakeChangeDisplaySettingsExA, NULL);
|
||||
hook("User32.dll", "SetCursor", FakeSetCursor, (void**)&TrueSetCursor);
|
||||
|
||||
if (PathFileExistsA("FREEGLUT.DLL")) {
|
||||
if (PathFileExistsA("FREEGLUT.DLL") && FALSE) {
|
||||
// Hooked as a way to identify use of GLUT
|
||||
hook("FREEGLUT.DLL", "glutInitDisplayMode", Fake_glutInitDisplayMode,
|
||||
(void**)&True_glutInitDisplayMode);
|
||||
|
@ -43,5 +43,6 @@ void register_gui_hook(FnEndScene* end_scene);
|
||||
void hook_gui();
|
||||
void setup_hud_gui();
|
||||
|
||||
BOOL UnadjustWindowRect(LPRECT prc, DWORD dwStyle, BOOL fMenu);
|
||||
extern HWND mainWindow;
|
||||
extern DWORD changeCursorState;
|
||||
|
@ -89,7 +89,7 @@ BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD
|
||||
case EVENTLOG_INFORMATION_TYPE:
|
||||
default:
|
||||
for (int i = 0; i < wNumStrings; i++)
|
||||
log_info(plfEvtlog, trim_string((char*)lpStrings[i]));
|
||||
log_game(plfEvtlog, trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
@ -97,16 +97,17 @@ BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD
|
||||
|
||||
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
|
||||
|
||||
// static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
|
||||
// VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s",
|
||||
// lpOutputString); }
|
||||
VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) {
|
||||
log_game(plfDebugLog, "%s", lpOutputString);
|
||||
}
|
||||
|
||||
void hook_logging() {
|
||||
// hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf);
|
||||
// hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf);
|
||||
// hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s);
|
||||
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf);
|
||||
// hook("MSVCR90.DLL", "fprintf_s"\z, Fakefprintf_s, (void**)&Truefprintf_s);
|
||||
// hook("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_s);
|
||||
|
||||
hook("Kernel32.dll", "OutputDebugStringA", FakeOutputDebugStringA, NULL);
|
||||
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA,
|
||||
(void**)&TrueRegisterEventSourceA);
|
||||
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA);
|
||||
|
@ -1,11 +1,73 @@
|
||||
#include "network.h"
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#pragma comment(lib, "Dnsapi.lib")
|
||||
|
||||
#define IP(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
||||
#define NAOMINET IP(14, 128, 27, 15)
|
||||
#define IB_NAOMINET IP(14, 128, 27, 9)
|
||||
#define AIME_NAOMINET IP(112, 137, 187, 91)
|
||||
|
||||
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
|
||||
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
|
||||
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
|
||||
// Poorly exclude nxauth and mxgcatcher.
|
||||
// TODO: better
|
||||
if (port != 40190 && port != 40110 && port != 40102 && port != 40103) {
|
||||
|
||||
if (addr == NAOMINET || addr == IB_NAOMINET || addr == AIME_NAOMINET) {
|
||||
log_error(
|
||||
plfNetwork,
|
||||
"DANGER!! Game is attempting to connect to SEGA services! Check your configuration!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr == IP(127, 0, 0, 1)) {
|
||||
switch (port) {
|
||||
case 40100:
|
||||
case 40101:
|
||||
log_info(plfNetwork, "connect(master)");
|
||||
break;
|
||||
case 40102:
|
||||
case 40103:
|
||||
log_info(plfNetwork, "connect(installer)");
|
||||
break;
|
||||
case 40104:
|
||||
case 40105:
|
||||
log_info(plfNetwork, "connect(network)");
|
||||
break;
|
||||
case 40106:
|
||||
case 40107:
|
||||
log_info(plfNetwork, "connect(keychip)");
|
||||
break;
|
||||
case 40108:
|
||||
case 40112:
|
||||
log_info(plfNetwork, "connect(gdeliver)");
|
||||
break;
|
||||
case 40110:
|
||||
case 40113:
|
||||
log_info(plfNetwork, "connect(gcatcher)");
|
||||
break;
|
||||
case 40114:
|
||||
case 40115:
|
||||
log_info(plfNetwork, "connect(storage)");
|
||||
break;
|
||||
case 40190:
|
||||
case 40191:
|
||||
case 40192:
|
||||
case 40193:
|
||||
// nxAuth
|
||||
break;
|
||||
case 40194:
|
||||
case 40195:
|
||||
log_info(plfNetwork, "connect(nxmount)");
|
||||
break;
|
||||
case 40196:
|
||||
case 40197:
|
||||
log_info(plfNetwork, "connect(nxrelay)");
|
||||
break;
|
||||
default:
|
||||
log_info(plfNetwork, "connect(localhost:%hu)", port);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
log_info(plfNetwork, "connect(%hhu.%hhu.%hhu.%hhu:%hu)", (addr >> 24) & 0xff,
|
||||
(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, port);
|
||||
}
|
||||
@ -94,11 +156,40 @@ dns INTERCEPT_DNS[] = {
|
||||
|
||||
DNS_RECORDA dummy_record;
|
||||
|
||||
static BOOL _DoDnsLookup(PCSTR pszName, DWORD* lpResolved) {
|
||||
DNS_STATUS status;
|
||||
PDNS_RECORDA pDnsRecord = NULL;
|
||||
|
||||
if (MiceConfig.network.upstream_dns_server) {
|
||||
IP4_ARRAY upstreamDns;
|
||||
upstreamDns.AddrCount = 1;
|
||||
upstreamDns.AddrArray[0] = _byteswap_ulong(MiceConfig.network.upstream_dns_server);
|
||||
status = TrueDnsQuery_A(pszName, DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, &upstreamDns,
|
||||
&pDnsRecord, NULL);
|
||||
} else {
|
||||
status = TrueDnsQuery_A(pszName, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL);
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
log_error(plfNetwork, "DNS(%s):FAILED", pszName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pDnsRecord == NULL || pDnsRecord->wType != DNS_TYPE_A) {
|
||||
log_error(plfNetwork, "DNS(%s):NXRECORD", pszName);
|
||||
return FALSE;
|
||||
}
|
||||
if (lpResolved) *lpResolved = _byteswap_ulong(pDnsRecord->Data.A.IpAddress);
|
||||
DnsRecordListFree(pDnsRecord, DnsFreeRecordListDeep);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra,
|
||||
PDNS_RECORDA* ppQueryResults, PVOID* pReserved) {
|
||||
if (ppQueryResults) {
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
|
||||
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
|
||||
strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
|
||||
printf("%08x\n", MiceConfig.network.naominet_jp);
|
||||
|
||||
log_info(plfNetwork, "DNS Replacing %s with %08x", pszName,
|
||||
@ -115,21 +206,42 @@ DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID
|
||||
}
|
||||
}
|
||||
log_info(plfNetwork, "DNS passthrough for %s", pszName);
|
||||
|
||||
if (MiceConfig.network.upstream_dns_server) {
|
||||
IP4_ARRAY upstreamDns;
|
||||
upstreamDns.AddrCount = 1;
|
||||
upstreamDns.AddrArray[0] = _byteswap_ulong(MiceConfig.network.upstream_dns_server);
|
||||
return TrueDnsQuery_A(pszName, wType, DNS_QUERY_BYPASS_CACHE, &upstreamDns, ppQueryResults,
|
||||
pReserved);
|
||||
}
|
||||
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
|
||||
};
|
||||
}
|
||||
|
||||
INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
|
||||
LPWSAPROTOCOL_INFOA lpProtocolInfo, LPSOCKADDR lpAddress,
|
||||
LPINT lpAddressLength) {
|
||||
log_misc(plfNetwork, "WSA DNS lookup for %s", AddressString);
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
|
||||
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString,
|
||||
*INTERCEPT_DNS[i].address);
|
||||
if (AddressFamily == AF_INET) {
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
|
||||
strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
|
||||
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString,
|
||||
*INTERCEPT_DNS[i].address);
|
||||
|
||||
lpAddress->sa_family = AF_INET;
|
||||
PULONG addr = &(((SOCKADDR_IN*)lpAddress)->sin_addr.S_un.S_addr);
|
||||
*addr = _byteswap_ulong(*INTERCEPT_DNS[i].address);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD nResolved;
|
||||
if (_DoDnsLookup(AddressString, &nResolved)) {
|
||||
log_info(plfNetwork, "WSA DNS Replacing %s with %08x", AddressString, nResolved);
|
||||
|
||||
lpAddress->sa_family = AF_INET;
|
||||
PULONG addr = &(((SOCKADDR_IN*)lpAddress)->sin_addr.S_un.S_addr);
|
||||
*addr = _byteswap_ulong(*INTERCEPT_DNS[i].address);
|
||||
*addr = _byteswap_ulong(nResolved);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -140,11 +252,13 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
|
||||
|
||||
INT WINAPI Fake_getaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints,
|
||||
PADDRINFOA* ppResult) {
|
||||
char szNewAddress[16];
|
||||
|
||||
if (!pNodeName) return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
|
||||
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(pNodeName, INTERCEPT_DNS[i].name) == 0) {
|
||||
char szNewAddress[16];
|
||||
if (INTERCEPT_DNS[i].address && *INTERCEPT_DNS[i].address &&
|
||||
strcmp(pNodeName, INTERCEPT_DNS[i].name) == 0) {
|
||||
sprintf_s(szNewAddress, sizeof szNewAddress, "%d.%d.%d.%d",
|
||||
(*INTERCEPT_DNS[i].address >> 24) & 0xff,
|
||||
(*INTERCEPT_DNS[i].address >> 16) & 0xff,
|
||||
@ -159,8 +273,19 @@ INT WINAPI Fake_getaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA
|
||||
|
||||
// Exclude a few known services
|
||||
if (strcmp(pNodeName, "0.0.0.0") != 0 && strcmp(pNodeName, "127.0.0.0") != 0 &&
|
||||
strcmp(pNodeName, "240.0.0.0") != 0)
|
||||
strcmp(pNodeName, "240.0.0.0") != 0) {
|
||||
// Try doing a lookup using our upstream DNS service
|
||||
DWORD nResolved;
|
||||
if (_DoDnsLookup(pNodeName, &nResolved)) {
|
||||
sprintf_s(szNewAddress, sizeof szNewAddress, "%d.%d.%d.%d", (nResolved >> 24) & 0xff,
|
||||
(nResolved >> 16) & 0xff, (nResolved >> 8) & 0xff, nResolved & 0xff);
|
||||
szNewAddress[sizeof szNewAddress - 1] = '\0';
|
||||
|
||||
return True_getaddrinfo(szNewAddress, pServiceName, pHints, ppResult);
|
||||
}
|
||||
|
||||
log_info(plfNetwork, "GAI DNS passthrough for %s:%s", pNodeName, pServiceName);
|
||||
}
|
||||
return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
|
||||
}
|
||||
|
||||
@ -235,7 +360,7 @@ void hook_network() {
|
||||
hook("Ws2_32.dll", "socket", Fake_socket, (void**)&True_socket);
|
||||
hook("Ws2_32.dll", "bind", Fake_bind, (void**)&True_bind);
|
||||
hook("Ws2_32.dll", "getaddrinfo", Fake_getaddrinfo, (void**)&True_getaddrinfo);
|
||||
// hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
|
||||
hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
|
||||
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA,
|
||||
(void**)&TrueWSAStringToAddressA);
|
||||
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "processes.h"
|
||||
|
||||
#include "../lib/mice/ipc.h"
|
||||
|
||||
BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
|
||||
@ -14,6 +16,9 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
||||
lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||||
lpProcessInformation);
|
||||
}
|
||||
// Bind everything to our one single console
|
||||
dwCreationFlags &= ~CREATE_NEW_CONSOLE;
|
||||
dwCreationFlags |= CREATE_NO_WINDOW;
|
||||
|
||||
if (lpCommandLine &&
|
||||
(strcmp(lpCommandLine, "s:\\mxkeychip.exe") == 0 ||
|
||||
@ -41,8 +46,15 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
||||
MiceFSRedirectPathA(lpApplicationName, &lpApplicationName);
|
||||
log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine);
|
||||
|
||||
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine, MICELIB, FALSE,
|
||||
0, NULL, 0, lpProcessInformation);
|
||||
if (!_miceIpcData->m_LauncherIsReady || _miceIpcData->m_MiceDll[0] == '\0') {
|
||||
log_error(plfProcesses, "MiceLIB not provided via IPC!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
log_info(plfProcesses, "Spawning \"%s\" %s", lpApplicationName, lpCommandLine);
|
||||
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine,
|
||||
_miceIpcData->m_MiceDll, FALSE, 0, NULL, dwCreationFlags,
|
||||
lpProcessInformation);
|
||||
}
|
||||
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
@ -50,23 +62,26 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
|
||||
// if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0 ||
|
||||
// wcscmp(lpCommandLine, L"ALLNetProc_Win.exe") == 0 ||
|
||||
// wcscmp(lpCommandLine, L"ALLNetProc_Ring.exe") == 0 ||
|
||||
// wcscmp(lpCommandLine, L"ALLNetProc.exe") == 0)) {
|
||||
if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0)) {
|
||||
if (lpCommandLine && (_wcsnicmp(lpCommandLine, L"chkdsk.exe", 10) == 0)) {
|
||||
if (lpProcessInformation) {
|
||||
lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL);
|
||||
lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
// Bind everything to our one single console
|
||||
dwCreationFlags &= ~CREATE_NEW_CONSOLE;
|
||||
dwCreationFlags |= CREATE_NO_WINDOW;
|
||||
|
||||
int nMultiChars = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, NULL, 0, NULL, NULL);
|
||||
LPSTR commandLine = malloc(nMultiChars);
|
||||
LPSTR commandLine = malloc(nMultiChars + 1);
|
||||
commandLine[0] = '\0';
|
||||
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, nMultiChars, NULL, NULL);
|
||||
commandLine[nMultiChars] = '\0';
|
||||
|
||||
CHAR szApplicationName[MAX_PATH + 1];
|
||||
LPCSTR lpApplicationNameA;
|
||||
@ -88,8 +103,16 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
}
|
||||
|
||||
MiceFSRedirectPathA(lpApplicationNameA, &lpApplicationNameA);
|
||||
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationNameA, commandLine, MICELIB, FALSE,
|
||||
0, NULL, 0, lpProcessInformation);
|
||||
|
||||
if (!_miceIpcData->m_LauncherIsReady || _miceIpcData->m_MiceDll[0] == '\0') {
|
||||
log_error(plfProcesses, "MiceLIB not provided via IPC!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
log_info(plfProcesses, "Spawning \"%s\" %s", lpApplicationNameA, commandLine);
|
||||
return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationNameA, commandLine,
|
||||
_miceIpcData->m_MiceDll, FALSE, 0, NULL, dwCreationFlags,
|
||||
lpProcessInformation);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
|
||||
|
@ -71,13 +71,13 @@ BOOL WINAPI FakeSetupDiGetDeviceInterfaceDetailA(HDEVINFO DeviceInfoSet, PSP_DEV
|
||||
log_misc(plfSetupAPI, "Intercepted SetupDiGetDeviceInterfaceDetailA");
|
||||
|
||||
const WCHAR* res = (WCHAR*)DeviceInterfaceData->Reserved;
|
||||
int new_len = (wcslen(res) + 1) * (sizeof *res);
|
||||
size_t new_len = (wcslen(res) + 1) * (sizeof *res);
|
||||
char* new_res = (char*)malloc(new_len);
|
||||
size_t convertedChars = 0;
|
||||
wcstombs_s(&convertedChars, new_res, new_len, res, _TRUNCATE);
|
||||
|
||||
size_t len = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + convertedChars;
|
||||
if (RequiredSize) *RequiredSize = len;
|
||||
if (RequiredSize) *RequiredSize = len & 0xffffffff;
|
||||
if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize < len) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
|
@ -66,7 +66,9 @@ LONG WINAPI FakeRtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation) {
|
||||
|
||||
// TODO: We should probably handle libamv_amd.dll at some point too
|
||||
HMODULE WINAPI FakeLoadLibraryA(LPCSTR lpLibFileName) {
|
||||
if (strcmp(lpLibFileName, "libamv_nvidia.dll") == 0) {
|
||||
if (_stricmp(lpLibFileName, "libamv_nvidia.dll") == 0 ||
|
||||
_stricmp(lpLibFileName, "libamv_amd.dll") == 0 ||
|
||||
_stricmp(lpLibFileName, "atipdlxx.dll") == 0) {
|
||||
return TrueLoadLibraryA(MICELIB);
|
||||
}
|
||||
return TrueLoadLibraryA(lpLibFileName);
|
||||
@ -74,7 +76,9 @@ HMODULE WINAPI FakeLoadLibraryA(LPCSTR lpLibFileName) {
|
||||
#define WIDEN2(x) L##x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
HMODULE WINAPI FakeLoadLibraryW(LPCWSTR lpLibFileName) {
|
||||
if (wcscmp(lpLibFileName, L"libamv_nvidia.dll") == 0) {
|
||||
if (_wcsicmp(lpLibFileName, L"libamv_nvidia.dll") == 0 ||
|
||||
_wcsicmp(lpLibFileName, L"libamv_amd.dll") == 0 ||
|
||||
_wcsicmp(lpLibFileName, L"atipdlxx.dll") == 0) {
|
||||
return TrueLoadLibraryW(WIDEN(MICELIB));
|
||||
}
|
||||
return TrueLoadLibraryW(lpLibFileName);
|
||||
|
230
src/micetools/dll/input.c
Normal file
230
src/micetools/dll/input.c
Normal file
@ -0,0 +1,230 @@
|
||||
#include "input.h"
|
||||
#pragma comment(lib, "dinput8.lib")
|
||||
#pragma comment(lib, "dxguid.lib")
|
||||
#include <GuidDef.h>
|
||||
#include <Objbase.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/log.h"
|
||||
|
||||
static PMICE_DI_DEVICE _MiceDIDevices = NULL;
|
||||
static LPDIRECTINPUT8A _MiceDI = NULL;
|
||||
|
||||
void MiceInputPollDevices(void) {
|
||||
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
|
||||
while (lpDevice != NULL) {
|
||||
lpDevice->m_lpInput->lpVtbl->Poll(lpDevice->m_lpInput);
|
||||
|
||||
switch (lpDevice->m_dwType) {
|
||||
case DI8DEVTYPE_JOYSTICK:
|
||||
case DI8DEVTYPE_GAMEPAD:
|
||||
lpDevice->m_lpInput->lpVtbl->GetDeviceState(lpDevice->m_lpInput,
|
||||
sizeof lpDevice->m_State.m_Joystate,
|
||||
&lpDevice->m_State.m_Joystate);
|
||||
break;
|
||||
}
|
||||
|
||||
lpDevice = lpDevice->m_Next;
|
||||
}
|
||||
}
|
||||
void MiceInputFreeDevices(void) {
|
||||
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
|
||||
while (lpDevice != NULL) {
|
||||
lpDevice->m_lpInput->lpVtbl->Unacquire(lpDevice->m_lpInput);
|
||||
lpDevice->m_lpInput->lpVtbl->Release(lpDevice->m_lpInput);
|
||||
|
||||
PMICE_DI_DEVICE next = lpDevice->m_Next;
|
||||
free(lpDevice);
|
||||
lpDevice = next;
|
||||
}
|
||||
_MiceDIDevices = NULL;
|
||||
}
|
||||
|
||||
BOOL MiceInputGetNewBinding(PMICE_BUTTON_BINDING lpBinding) {
|
||||
MiceInputPollDevices();
|
||||
|
||||
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
|
||||
while (lpDevice != NULL) {
|
||||
PMICE_DI_STATE state = &lpDevice->m_State;
|
||||
PMICE_DI_STATE lastState = &lpDevice->m_LastState;
|
||||
if (lpBinding != NULL) {
|
||||
switch (lpDevice->m_dwType) {
|
||||
case DI8DEVTYPE_JOYSTICK:
|
||||
case DI8DEVTYPE_GAMEPAD:
|
||||
for (int button = 0; button < 32; button++) {
|
||||
if (state->m_Joystate.rgbButtons[button] &&
|
||||
!lastState->m_Joystate.rgbButtons[button]) {
|
||||
lpBinding->m_Type = MICE_BB_TYPE_DI_JOY;
|
||||
lpBinding->m_DIJoy.m_lpDeviceGuid = lpDevice->m_GUID;
|
||||
lpBinding->m_DIJoy.m_ButtonMajor = MICE_BUTTON_MAJOR_BUTTON;
|
||||
lpBinding->m_DIJoy.m_ButtonMinor = button;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->m_Joystate.rgdwPOV[0] != lastState->m_Joystate.rgdwPOV[0]) {
|
||||
BOOL bound = FALSE;
|
||||
int to = -1;
|
||||
if (state->m_Joystate.rgdwPOV[0] == 0) {
|
||||
to = MICE_DPAD_UP;
|
||||
bound = TRUE;
|
||||
} else if (state->m_Joystate.rgdwPOV[0] == 18000) {
|
||||
to = MICE_DPAD_DOWN;
|
||||
bound = TRUE;
|
||||
} else if (state->m_Joystate.rgdwPOV[0] == 27000) {
|
||||
to = MICE_DPAD_LEFT;
|
||||
bound = TRUE;
|
||||
} else if (state->m_Joystate.rgdwPOV[0] == 9000) {
|
||||
to = MICE_DPAD_RIGHT;
|
||||
bound = TRUE;
|
||||
}
|
||||
if (bound) {
|
||||
lpBinding->m_Type = MICE_BB_TYPE_DI_JOY;
|
||||
lpBinding->m_DIJoy.m_lpDeviceGuid = lpDevice->m_GUID;
|
||||
lpBinding->m_DIJoy.m_ButtonMajor = MICE_BUTTON_MAJOR_DPAD;
|
||||
lpBinding->m_DIJoy.m_ButtonMinor = to;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Axes
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(lastState, state, sizeof *lastState);
|
||||
|
||||
lpDevice = lpDevice->m_Next;
|
||||
}
|
||||
|
||||
// Skip the mouse buttons
|
||||
for (int i = 8; i < 0xff; i++) {
|
||||
if (GetAsyncKeyState(i) < 0) {
|
||||
lpBinding->m_AsyncKey.m_Key = (CHAR)i;
|
||||
lpBinding->m_Type = MICE_BB_TYPE_GET_ASYNC_KEY;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK _DInputEnum(LPDIDEVICEINSTANCEA lpddi, LPVOID data) {
|
||||
PMICE_DI_DEVICE lpTail = _MiceDIDevices;
|
||||
PMICE_DI_DEVICE lpNew;
|
||||
if (lpTail == NULL) {
|
||||
lpNew = _MiceDIDevices = malloc(sizeof *lpNew);
|
||||
} else {
|
||||
while (lpTail->m_Next != NULL) lpTail = lpTail->m_Next;
|
||||
lpNew = lpTail->m_Next = malloc(sizeof *lpNew);
|
||||
}
|
||||
|
||||
ZeroMemory(lpNew, sizeof *lpNew);
|
||||
lpNew->m_GUID = lpddi->guidInstance;
|
||||
lpNew->m_dwType = lpddi->dwDevType & 0xff;
|
||||
memcpy_s(lpNew->m_szName, sizeof lpNew->m_szName, lpddi->tszProductName,
|
||||
sizeof lpddi->tszProductName);
|
||||
lpNew->m_szName[sizeof lpNew->m_szName - 1] = '\0';
|
||||
|
||||
printf("Found device: %s\n", lpNew->m_szName);
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
int MiceInputGrabDevices(HWND hWnd) {
|
||||
if (_MiceDI == NULL) return -2;
|
||||
|
||||
// The first argument here is throwing warnings
|
||||
#pragma warning(disable : 4090 4028)
|
||||
_MiceDI->lpVtbl->EnumDevices(_MiceDI, DI8DEVTYPE_JOYSTICK, _DInputEnum, NULL,
|
||||
DIEDFL_ATTACHEDONLY);
|
||||
_MiceDI->lpVtbl->EnumDevices(_MiceDI, DI8DEVTYPE_GAMEPAD, _DInputEnum, NULL,
|
||||
DIEDFL_ATTACHEDONLY);
|
||||
#pragma warning(default : 4090 4028)
|
||||
|
||||
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
|
||||
while (lpDevice != NULL) {
|
||||
_MiceDI->lpVtbl->CreateDevice(_MiceDI, &lpDevice->m_GUID, &lpDevice->m_lpInput, NULL);
|
||||
|
||||
switch (lpDevice->m_dwType) {
|
||||
case DI8DEVTYPE_GAMEPAD:
|
||||
case DI8DEVTYPE_JOYSTICK:
|
||||
lpDevice->m_lpInput->lpVtbl->SetCooperativeLevel(
|
||||
lpDevice->m_lpInput, hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
|
||||
lpDevice->m_lpInput->lpVtbl->SetDataFormat(lpDevice->m_lpInput, &c_dfDIJoystick);
|
||||
lpDevice->m_lpInput->lpVtbl->Acquire(lpDevice->m_lpInput);
|
||||
break;
|
||||
}
|
||||
lpDevice = lpDevice->m_Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL _MiceInputHasInit = FALSE;
|
||||
int MiceInputInit(HWND hWnd) {
|
||||
if (_MiceInputHasInit) return 0;
|
||||
_MiceInputHasInit = TRUE;
|
||||
|
||||
if (_MiceDI == NULL)
|
||||
if (!(SUCCEEDED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
|
||||
&IID_IDirectInput8, (void **)&_MiceDI, NULL)))) {
|
||||
log_error(plfMisc, "DirectInput8Create failed: %d", GetLastError());
|
||||
_MiceDI = NULL;
|
||||
return -1;
|
||||
}
|
||||
return MiceInputGrabDevices(hWnd);
|
||||
}
|
||||
void MiceInputDestroy(void) {
|
||||
MiceInputFreeDevices();
|
||||
|
||||
_MiceDI->lpVtbl->Release(_MiceDI);
|
||||
_MiceDI = NULL;
|
||||
_MiceInputHasInit = FALSE;
|
||||
}
|
||||
|
||||
BOOL MiceInputGetButtonState(PMICE_BUTTON_BINDING lpBinding) {
|
||||
BOOL pressed = FALSE;
|
||||
switch (lpBinding->m_Type) {
|
||||
case MICE_BB_TYPE_GET_ASYNC_KEY: {
|
||||
pressed = (GetAsyncKeyState(lpBinding->m_AsyncKey.m_Key) < 0);
|
||||
break;
|
||||
}
|
||||
case MICE_BB_TYPE_DI_JOY: {
|
||||
PMICE_DI_DEVICE lpDevice = _MiceDIDevices;
|
||||
while (lpDevice != NULL) {
|
||||
if (IsEqualGUID(&lpDevice->m_GUID, &lpBinding->m_DIJoy.m_lpDeviceGuid)) break;
|
||||
lpDevice = lpDevice->m_Next;
|
||||
}
|
||||
if (lpDevice == NULL) break;
|
||||
|
||||
switch (lpBinding->m_DIJoy.m_ButtonMajor) {
|
||||
case MICE_BUTTON_MAJOR_AXIS:
|
||||
break;
|
||||
case MICE_BUTTON_MAJOR_DPAD: {
|
||||
DWORD pov = lpDevice->m_State.m_Joystate.rgdwPOV[0];
|
||||
switch (lpBinding->m_DIJoy.m_ButtonMinor) {
|
||||
case MICE_DPAD_UP:
|
||||
pressed = pov == 0 || pov == 4500 || pov == 31500;
|
||||
break;
|
||||
case MICE_DPAD_DOWN:
|
||||
pressed = pov == 18000 || pov == 22500 || pov == 13500;
|
||||
break;
|
||||
case MICE_DPAD_LEFT:
|
||||
pressed = pov == 27000 || pov == 31500 || pov == 22500;
|
||||
break;
|
||||
case MICE_DPAD_RIGHT:
|
||||
pressed = pov == 9000 || pov == 4500 || pov == 13500;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MICE_BUTTON_MAJOR_BUTTON: {
|
||||
DWORD button = lpBinding->m_DIJoy.m_ButtonMinor;
|
||||
if (button <= 32) pressed = lpDevice->m_State.m_Joystate.rgbButtons[button] > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lpBinding->m_Invert) pressed = !pressed;
|
||||
return pressed;
|
||||
}
|
61
src/micetools/dll/input.h
Normal file
61
src/micetools/dll/input.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#define CINTERFACE
|
||||
#define INITGUID
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
|
||||
typedef enum MICE_BUTTON_BINDING_TYPE {
|
||||
MICE_BB_TYPE_UNBOUND,
|
||||
MICE_BB_TYPE_GET_ASYNC_KEY,
|
||||
MICE_BB_TYPE_DI_JOY,
|
||||
} MICE_BUTTON_BINDING_TYPE;
|
||||
typedef enum MICE_BUTTON_MAJOR {
|
||||
MICE_BUTTON_MAJOR_AXIS,
|
||||
MICE_BUTTON_MAJOR_DPAD,
|
||||
MICE_BUTTON_MAJOR_BUTTON,
|
||||
} MICE_BUTTON_MAJOR;
|
||||
#define MICE_DPAD_UP 0 // POV == 0
|
||||
#define MICE_DPAD_DOWN 1 // POV = 18000
|
||||
#define MICE_DPAD_LEFT 2 // POV == 27000
|
||||
#define MICE_DPAD_RIGHT 3 // POV == 9000
|
||||
|
||||
typedef struct MICE_BUTTON_BINDING {
|
||||
MICE_BUTTON_BINDING_TYPE m_Type;
|
||||
BOOL m_Invert;
|
||||
union {
|
||||
struct {
|
||||
CHAR m_Key;
|
||||
} m_AsyncKey;
|
||||
struct {
|
||||
GUID m_lpDeviceGuid;
|
||||
MICE_BUTTON_MAJOR m_ButtonMajor;
|
||||
DWORD m_ButtonMinor;
|
||||
} m_DIJoy;
|
||||
};
|
||||
} MICE_BUTTON_BINDING, *PMICE_BUTTON_BINDING;
|
||||
|
||||
typedef union MICE_DI_STATE {
|
||||
DIJOYSTATE m_Joystate;
|
||||
} MICE_DI_STATE, *PMICE_DI_STATE;
|
||||
|
||||
typedef struct MICE_DI_DEVICE {
|
||||
LPDIRECTINPUTDEVICE8A m_lpInput;
|
||||
GUID m_GUID;
|
||||
CHAR m_szName[MAX_PATH];
|
||||
DWORD m_dwType;
|
||||
MICE_DI_STATE m_State;
|
||||
MICE_DI_STATE m_LastState;
|
||||
struct MICE_DI_DEVICE* m_Next;
|
||||
} MICE_DI_DEVICE, *PMICE_DI_DEVICE;
|
||||
|
||||
int MiceInputInit(HWND hWnd);
|
||||
void MiceInputDestroy(void);
|
||||
|
||||
int MiceInputGrabDevices(HWND hWnd);
|
||||
void MiceInputPollDevices(void);
|
||||
void MiceInputFreeDevices(void);
|
||||
|
||||
BOOL MiceInputGetButtonState(PMICE_BUTTON_BINDING lpBinding);
|
||||
BOOL MiceInputGetNewBinding(PMICE_BUTTON_BINDING lpBinding);
|
@ -4,11 +4,12 @@ subdir('hooks')
|
||||
subdir('gui')
|
||||
|
||||
shared_library(
|
||||
'mice',
|
||||
get_option('win64') ? 'mice64' : 'mice',
|
||||
name_prefix: '',
|
||||
vs_module_defs: 'mice.def',
|
||||
vs_module_defs: get_option('win64') ? 'mice64.def' : 'mice.def',
|
||||
sources: [
|
||||
'amvStub/amv.c',
|
||||
'dllStub/amv.c',
|
||||
'dllStub/ati.c',
|
||||
|
||||
'util/misc.c',
|
||||
'util/hook.c',
|
||||
@ -21,11 +22,12 @@ shared_library(
|
||||
|
||||
'comdevice.c',
|
||||
'games.c',
|
||||
'input.c',
|
||||
'micefs.c',
|
||||
|
||||
'dllmain.c',
|
||||
],
|
||||
link_with: [
|
||||
dmi_lib,
|
||||
mice_lib,
|
||||
amiTimer,
|
||||
amiMd5,
|
||||
@ -37,6 +39,7 @@ shared_library(
|
||||
],
|
||||
dependencies: [
|
||||
cimgui.get_variable('cimgui_dep'),
|
||||
detours.get_variable('detours_dep'),
|
||||
# freeglut_lib, # forces the use of freeglut.dll!
|
||||
]
|
||||
)
|
||||
|
1
src/micetools/dll/mice64.def
Normal file
1
src/micetools/dll/mice64.def
Normal file
@ -0,0 +1 @@
|
||||
LIBRARY mice64
|
@ -6,9 +6,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO: This is awful
|
||||
extern BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath);
|
||||
#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA)
|
||||
#include "hooks/files.h"
|
||||
|
||||
static char miceFSCwd[MAX_PATH + 1];
|
||||
|
||||
@ -51,7 +49,7 @@ static volatile LONG miceFsLockCount = 0;
|
||||
|
||||
BOOL MiceFSInit(VOID) {
|
||||
// By not using MiceFSSetCwd we can save a buffer allocation
|
||||
GetCurrentDirectoryA(sizeof miceFSCwd, miceFSCwd);
|
||||
_GetCurrentDirectoryA(sizeof miceFSCwd, miceFSCwd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -114,58 +112,113 @@ BOOL MiceFSAddDevLayers(VOID) {
|
||||
CHAR szMountPoint[4];
|
||||
CHAR szTargetPath[MAX_PATH + 1];
|
||||
ZeroMemory(szTargetPath, sizeof szTargetPath);
|
||||
strcpy_s(szTargetPath, sizeof szTargetPath, ".\\dev\\x\\");
|
||||
strcpy_s(szTargetPath, sizeof szTargetPath, MiceIpcRelativePath("dev\\x\\"));
|
||||
DWORD index = strlen(szTargetPath) - 2;
|
||||
|
||||
CHAR szCurrentDir[MAX_PATH + 1];
|
||||
_GetCurrentDirectoryA(sizeof szCurrentDir, szCurrentDir);
|
||||
|
||||
// See below TODO
|
||||
if (szCurrentDir[0] == RING_MOUNT_APPDATA[0]) {
|
||||
log_error(plfBoot,
|
||||
"Booting on the %s drive is currently unsupported. There's a potential for it to "
|
||||
"do nasty things to your computer at the moment.",
|
||||
RING_MOUNT_APPDATA);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
BOOL success = TRUE;
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (i == 2) continue; // TODO: DON'T SKIP C
|
||||
// TODO: DON'T SKIP C
|
||||
/**
|
||||
* Note: This is currently skipped because things such as DLLs, COM
|
||||
* registrations, etc. are all stored on C.
|
||||
* I have, however, run into an issue with a game (I forget which)
|
||||
* where _not_ hooking C caused issues.
|
||||
* This will likely require fine-grained whitelists.
|
||||
*/
|
||||
if (i == 2) continue;
|
||||
// TODO: Cleaner way to not skip the current drive?
|
||||
// Currently skipped because of games that compile shaders at runtime (eg SDCM), however
|
||||
// this could cause issues if a game is running on a drive letter that we really need to
|
||||
// hook. _Are_ there any drive letters that would prove fatal? Appdata, probably. To
|
||||
// protect users from themselves, we're currently rejecting the use of Y: as a boot drive
|
||||
// entirely. This is ugly, and I hate it very much, but I have bigger fish to fry for now.
|
||||
if (i == szCurrentDir[0] - 'A' || i == szCurrentDir[0] - 'a') continue;
|
||||
|
||||
szMountPoint[0] = 'A' + (char)i;
|
||||
szMountPoint[1] = ':';
|
||||
szMountPoint[2] = '\\';
|
||||
szMountPoint[3] = '\0';
|
||||
|
||||
szTargetPath[6] = 'a' + (char)i;
|
||||
szTargetPath[index] = 'a' + (char)i;
|
||||
|
||||
success &= MiceFSAddLayer(szMountPoint, szTargetPath);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate) {
|
||||
/**
|
||||
* Note: Layers are searched in reverse order. Most lookups will be served by:
|
||||
* 1. original
|
||||
* 2. pathch
|
||||
* 3. extend
|
||||
* so those are added last!
|
||||
*/
|
||||
BOOL success = TRUE;
|
||||
|
||||
// Windows file systems
|
||||
success &= MiceFSAddLayer(RING_MOUNT_OS, "mount/os");
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND, "mount/extend");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, "mount/os_recovery");
|
||||
|
||||
// TrueCrypt Volumes
|
||||
success &= MiceFSAddLayer(RING_MOUNT_SYSTEM, "mount/system");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, "mount/original");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_PATCH, "mount/patch");
|
||||
if (bIsOsupdate) {
|
||||
success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, "mount/os_update");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS, "mount/os_default_drivers");
|
||||
} else {
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, "mount/extend/extend");
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, "mount/extend/extend2");
|
||||
}
|
||||
|
||||
// geminifs
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/original");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/patch");
|
||||
|
||||
// External media
|
||||
success &= MiceFSAddLayer(RING_MOUNT_APM, "mount/apm");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_AM_LOG, "mount/am_log");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_DVD, "mount/dvd");
|
||||
success &= MiceFSAddLayer(RING_MOUNT_DEV, "mount/dev");
|
||||
|
||||
// TODO: Configurable!
|
||||
MiceFSAddLayer("R:", "H:\\Arcades\\USBs\\FiNALE_DL\\usb");
|
||||
MiceFSAddLayer("S:", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive");
|
||||
MiceFSAddLayer("C:\\System\\Execute", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive");
|
||||
|
||||
// Windows file systems
|
||||
// TODO: See note about the C: drive above
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_OS, MiceIpcRelativePath("mount\\os"));
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_APPDATA, MiceIpcRelativePath("mount\\extend"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, MiceIpcRelativePath("mount\\os_recovery"));
|
||||
|
||||
// External media
|
||||
success &= MiceFSAddLayer(RING_MOUNT_APM, MiceIpcRelativePath("mount\\apm"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_AM_LOG, MiceIpcRelativePath("mount\\am_log"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_DVD, MiceIpcRelativePath("mount\\dvd"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_DEV, MiceIpcRelativePath("mount\\dev"));
|
||||
|
||||
success &= MiceFSAddLayer("C:\\Documents and Settings\\AppUser",
|
||||
MiceIpcRelativePath("mount\\appuser"));
|
||||
success &= MiceFSAddLayer("C:\\Documents and Settings\\SystemUser",
|
||||
MiceIpcRelativePath("mount\\systemuser"));
|
||||
|
||||
success &=
|
||||
MiceFSAddLayer("C:\\DOCUME~1\\SYSTEM~1\\LOCALS~1\\Temp\\", MiceIpcRelativePath("temp"));
|
||||
|
||||
// TrueCrypt Volumes
|
||||
success &= MiceFSAddLayer(RING_MOUNT_SYSTEM, MiceIpcRelativePath("mount\\system"));
|
||||
if (bIsOsupdate) {
|
||||
success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, MiceIpcRelativePath("mount\\os_update"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS,
|
||||
MiceIpcRelativePath("mount\\os_default_drivers"));
|
||||
} else {
|
||||
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL,
|
||||
// MiceIpcRelativePath("mount\\extend/extend")); success &=
|
||||
// MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, MiceIpcRelativePath("mount\\extend/extend2"));
|
||||
}
|
||||
success &= MiceFSAddLayer(RING_MOUNT_PATCH, MiceIpcRelativePath("mount\\patch"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceIpcRelativePath("mount\\original"));
|
||||
|
||||
// geminifs
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceIpcRelativePath("mount\\patch"));
|
||||
success &= MiceFSAddLayer(RING_MOUNT_GAME, MiceIpcRelativePath("mount\\original"));
|
||||
|
||||
// Make directories that we're going to need
|
||||
make_dirs(MiceIpcRelativePath("mount\\appuser\\temp"));
|
||||
make_dirs(MiceIpcRelativePath("temp"));
|
||||
// Directories games read and write
|
||||
make_dirs(MiceIpcRelativePath("dev\\w"));
|
||||
make_dirs(MiceIpcRelativePath("dev\\v"));
|
||||
make_dirs(MiceIpcRelativePath("dev\\y"));
|
||||
make_dirs(MiceIpcRelativePath("dev\\x"));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -288,14 +341,17 @@ BOOL MiceFSRedirectPathA(LPCSTR lpFilename, LPCSTR* pszRedirected) {
|
||||
|
||||
PMICE_FS_LAYER layer = miceFsRoot.m_Next;
|
||||
CHAR szTail[MAX_PATH + 1];
|
||||
wchar_t szwPath[MAX_PATH + 1];
|
||||
BOOL bFound = FALSE;
|
||||
while (layer) {
|
||||
if (MiceFSMatchPathA(szExpanded, layer->m_lpMountPoint, szTail, sizeof szTail)) {
|
||||
_redirected_path[0] = '\0';
|
||||
PathCombineA(_redirected_path, layer->m_lpTargetPath, szTail);
|
||||
*pszRedirected = _redirected_path;
|
||||
if (pszRedirected) *pszRedirected = _redirected_path;
|
||||
|
||||
if (_PathFileExistsA(_redirected_path)) {
|
||||
MultiByteToWideChar(0, 0, _redirected_path, -1, szwPath, _countof(szwPath));
|
||||
|
||||
if (FileExistsW(szwPath)) {
|
||||
MiceReleaseLockShared(miceFsLockCount);
|
||||
return TRUE;
|
||||
}
|
||||
@ -320,6 +376,56 @@ BOOL MiceFSRedirectPathW(LPCWSTR lpFileName, LPCWSTR* pszRedirected) {
|
||||
if (!bRedirected) return FALSE;
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, szRedirected, -1, _redirected_path_w, sizeof _redirected_path_w);
|
||||
*pszRedirected = _redirected_path_w;
|
||||
if (pszRedirected) *pszRedirected = _redirected_path_w;
|
||||
|
||||
return bRedirected;
|
||||
}
|
||||
|
||||
void MiceFSDebugPrintLayers(void) {
|
||||
MiceTakeLockShared(miceFsLockCount);
|
||||
|
||||
PMICE_FS_LAYER lpLayer = &miceFsRoot;
|
||||
while (lpLayer = lpLayer->m_Next) {
|
||||
printf("%s -> %s\n", lpLayer->m_lpMountPoint, lpLayer->m_lpTargetPath);
|
||||
}
|
||||
|
||||
MiceReleaseLockShared(miceFsLockCount);
|
||||
}
|
||||
BOOL MiceFSDebugTraceRedirectPathA(LPCSTR lpFilename, LPCSTR* pszRedirected) {
|
||||
printf("Tracing redirect of %s:\n", lpFilename);
|
||||
CHAR szExpanded[MAX_PATH + 1];
|
||||
if (!MiceFSGetFullPathNameA(lpFilename, sizeof szExpanded, szExpanded, NULL)) {
|
||||
printf(":: Redirect ended early with no action taken.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
MiceTakeLockShared(miceFsLockCount);
|
||||
|
||||
PMICE_FS_LAYER layer = miceFsRoot.m_Next;
|
||||
CHAR szTail[MAX_PATH + 1];
|
||||
wchar_t szwPath[MAX_PATH + 1];
|
||||
BOOL bFound = FALSE;
|
||||
while (layer) {
|
||||
if (MiceFSMatchPathA(szExpanded, layer->m_lpMountPoint, szTail, sizeof szTail)) {
|
||||
_redirected_path[0] = '\0';
|
||||
PathCombineA(_redirected_path, layer->m_lpTargetPath, szTail);
|
||||
if (pszRedirected) *pszRedirected = _redirected_path;
|
||||
|
||||
MultiByteToWideChar(0, 0, _redirected_path, -1, szwPath, _countof(szwPath));
|
||||
|
||||
printf("-> %s\n", _redirected_path);
|
||||
if (FileExistsW(szwPath)) {
|
||||
MiceReleaseLockShared(miceFsLockCount);
|
||||
printf(":: Redirect ended with valid redirection found.");
|
||||
return TRUE;
|
||||
}
|
||||
bFound = TRUE;
|
||||
}
|
||||
|
||||
layer = layer->m_Next;
|
||||
}
|
||||
|
||||
MiceReleaseLockShared(miceFsLockCount);
|
||||
printf(":: Redirect ended with no redirection found.");
|
||||
return FALSE;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#define RING_MOUNT_OS "C:"
|
||||
#define RING_MOUNT_EXTEND "Y:"
|
||||
#define RING_MOUNT_APPDATA "Y:"
|
||||
#define RING_MOUNT_RECOVERY "Z:"
|
||||
#define RING_MOUNT_SYSTEM "S:"
|
||||
#define RING_MOUNT_ORIGINAL "O:"
|
||||
@ -71,7 +71,7 @@ VOID MiceFSSetCwd(LPCSTR lpNewCwd);
|
||||
BOOL MiceFSAddLayer(_In_z_ LPCSTR lpMountPoint, _In_z_ LPCSTR lpTargetPath);
|
||||
|
||||
/**
|
||||
* @brief Add layers for all drive letters backed by ".\dev\[letter]"
|
||||
* @brief Add layers for all drive letters backed by ".\mice\dev\[letter]"
|
||||
* If used, this should be the first set of layers added, to act as a fallback
|
||||
*
|
||||
* @return BOOL Success. As this function adds 26 layers, and failiure could occur at any time,
|
||||
@ -148,8 +148,17 @@ BOOL MiceFSMatchPathA(_In_z_ LPCSTR lpPath, _In_z_ LPCSTR lpPrefix,
|
||||
* @param pszRedirected Redirected real filename
|
||||
* @return BOOL If redirection occured
|
||||
*/
|
||||
BOOL MiceFSRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_ LPCSTR* pszRedirected);
|
||||
BOOL MiceFSRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_opt_ LPCSTR* pszRedirected);
|
||||
/**
|
||||
* @brief Wide variant of MiceFSRedirectPathA
|
||||
*/
|
||||
BOOL MiceFSRedirectPathW(_In_z_ LPCWSTR lpFileName, _Out_ LPCWSTR* pszRedirected);
|
||||
BOOL MiceFSRedirectPathW(_In_z_ LPCWSTR lpFileName, _Out_opt_ LPCWSTR* pszRedirected);
|
||||
|
||||
/**
|
||||
* @brief Output a list of all filesystem layers to stdout
|
||||
*/
|
||||
void MiceFSDebugPrintLayers(void);
|
||||
/**
|
||||
* @brief Perform MiceFSRedirectPathA, with trace logging to stdout
|
||||
*/
|
||||
BOOL MiceFSDebugTraceRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_opt_ LPCSTR* pszRedirected);
|
@ -6,7 +6,8 @@
|
||||
#define HDATA_FIND_VOLUME 1
|
||||
#define HDATA_ANY 0xFFFFFFFF
|
||||
|
||||
BOOL FileExists(wchar_t* szPath);
|
||||
BOOL FileExistsW(const wchar_t* szPath);
|
||||
BOOL FileExistsA(const char* szPath);
|
||||
PVOID GetDataForHandle(HANDLE hObject, DWORD type);
|
||||
void SetDataForHandle(HANDLE hObject, DWORD type, PVOID pData, BOOL isHeap);
|
||||
BOOL RemoveDataForHandle(HANDLE hObject, DWORD type);
|
||||
@ -24,7 +25,7 @@ char GetGamedataDrive(void);
|
||||
BOOL IsGamedataLocalPath(LPCSTR path);
|
||||
|
||||
void make_dirs(const char* path);
|
||||
void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping);
|
||||
void* open_mapped_file(LPCSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping);
|
||||
|
||||
#define char_lower(value) (('A' <= (value) && (value) <= 'Z') ? ((value) - 'A' + 'a') : (value))
|
||||
#define char_upper(value) (('a' <= (value) && (value) <= 'z') ? ((value) - 'a' + 'A') : (value))
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "hook.h"
|
||||
|
||||
#include <detours.h>
|
||||
#include <memory.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
@ -28,132 +29,176 @@ void hook(LPCSTR dll, LPCSTR name, void* patch, void** store) {
|
||||
append_hook(hook);
|
||||
}
|
||||
|
||||
void patch_at(PVOID addr, const char* patch, DWORD length) {
|
||||
DWORD MiceGetImageBase(void) {
|
||||
static DWORD imageBase = 0;
|
||||
if (imageBase != 0) return imageBase;
|
||||
|
||||
WCHAR sModulePath[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, sModulePath, MAX_PATH);
|
||||
|
||||
HANDLE hObject =
|
||||
CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hObject == INVALID_HANDLE_VALUE) {
|
||||
log_error(plfBoot, "Failed to open %ls %03x", sModulePath, GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMAGE_DOS_HEADER dosHeader = { 0 };
|
||||
DWORD nRead;
|
||||
SetFilePointer(hObject, 0, NULL, FILE_BEGIN);
|
||||
ReadFile(hObject, &dosHeader, sizeof dosHeader, &nRead, NULL);
|
||||
if (nRead != sizeof dosHeader) {
|
||||
log_error(plfBoot, "Failed to read DOS header %03x", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
log_error(plfBoot, "Invalid DOS magic number: %04x", dosHeader.e_magic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS32 ntHeaders32 = { 0 };
|
||||
SetFilePointer(hObject, dosHeader.e_lfanew, NULL, FILE_BEGIN);
|
||||
ReadFile(hObject, &ntHeaders32, sizeof ntHeaders32, &nRead, NULL);
|
||||
if (nRead != sizeof ntHeaders32) {
|
||||
log_error(plfBoot, "Failed to read NT header %03x", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) {
|
||||
log_error(plfBoot, "Invalid NT signature: %08x", ntHeaders32.Signature);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(hObject);
|
||||
return (imageBase = ntHeaders32.OptionalHeader.ImageBase);
|
||||
}
|
||||
|
||||
void MiceHookPatchAt(PVOID addr, const void* patch, DWORD length) {
|
||||
DWORD oldProt;
|
||||
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
memcpy(addr, patch, length);
|
||||
VirtualProtect(addr, length, oldProt, &oldProt);
|
||||
}
|
||||
void clear_at(PVOID addr, BYTE clearVal, DWORD length) {
|
||||
void MiceHookClearAt(PVOID addr, BYTE clearVal, DWORD length) {
|
||||
DWORD oldProt;
|
||||
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
memset(addr, clearVal, length);
|
||||
VirtualProtect(addr, length, oldProt, &oldProt);
|
||||
}
|
||||
|
||||
BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
|
||||
if (len < 5) return FALSE;
|
||||
// BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
|
||||
// if (len < 5) return FALSE;
|
||||
|
||||
DWORD oldProt;
|
||||
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
// DWORD oldProt;
|
||||
// VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
|
||||
*(PCHAR)src = '\xE9';
|
||||
*(PINT)((int)src + 1) = (int)dst - (int)src - 5;
|
||||
// *(PCHAR)src = '\xE9';
|
||||
// *(PINT)((size_t)src + 1) = size2int((size_t)dst - (size_t)src - 5);
|
||||
|
||||
VirtualProtect(src, len, oldProt, &oldProt);
|
||||
return TRUE;
|
||||
}
|
||||
// VirtualProtect(src, len, oldProt, &oldProt);
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
void* Win32HotpatchHook(PVOID src, PVOID dst) {
|
||||
LPBYTE bSrc = (LPBYTE)src;
|
||||
// void* Win32HotpatchHook(PVOID src, PVOID dst) {
|
||||
// LPBYTE bSrc = (LPBYTE)src;
|
||||
|
||||
DWORD oldProt;
|
||||
VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
// DWORD oldProt;
|
||||
// VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
|
||||
// relative JMP to dst
|
||||
bSrc[-5] = 0xE9;
|
||||
DWORD relJump = (DWORD)dst - (DWORD)src;
|
||||
bSrc[-1] = (relJump >> 24) & 0xff;
|
||||
bSrc[-2] = (relJump >> 16) & 0xff;
|
||||
bSrc[-3] = (relJump >> 8) & 0xff;
|
||||
bSrc[-4] = relJump & 0xff;
|
||||
// JMP $-5
|
||||
bSrc[0] = 0xEB;
|
||||
bSrc[1] = 0xF9;
|
||||
// // relative JMP to dst
|
||||
// bSrc[-5] = 0xE9;
|
||||
// size_t relJump = (size_t)dst - (size_t)src;
|
||||
// bSrc[-1] = (relJump >> 24) & 0xff;
|
||||
// bSrc[-2] = (relJump >> 16) & 0xff;
|
||||
// bSrc[-3] = (relJump >> 8) & 0xff;
|
||||
// bSrc[-4] = relJump & 0xff;
|
||||
// // JMP $-5
|
||||
// bSrc[0] = 0xEB;
|
||||
// bSrc[1] = 0xF9;
|
||||
|
||||
VirtualProtect(bSrc - 5, 7, oldProt, &oldProt);
|
||||
// VirtualProtect(bSrc - 5, 7, oldProt, &oldProt);
|
||||
|
||||
// We don't need a gateway; we can just jump right in
|
||||
return bSrc + 2;
|
||||
}
|
||||
// // We don't need a gateway; we can just jump right in
|
||||
// return bSrc + 2;
|
||||
// }
|
||||
|
||||
#define CMP2(x, a, b) (x[0] == 0x##a && x[1] == 0x##b)
|
||||
#define CMP3(x, a, b, c) (CMP2(x, a, b) && x[2] == 0x##c)
|
||||
#define CMP4(x, a, b, c, d) (CMP3(x, a, b, c) && x[3] == 0x##d)
|
||||
#define CMP5(x, a, b, c, d, e) (CMP4(x, a, b, c, d) && x[4] == 0x##e)
|
||||
void* CreateHook32(PVOID src, PVOID dst) {
|
||||
LPBYTE bSrc = (LPBYTE)src;
|
||||
// #define CMP2(x, a, b) (x[0] == 0x##a && x[1] == 0x##b)
|
||||
// #define CMP3(x, a, b, c) (CMP2(x, a, b) && x[2] == 0x##c)
|
||||
// #define CMP4(x, a, b, c, d) (CMP3(x, a, b, c) && x[3] == 0x##d)
|
||||
// #define CMP5(x, a, b, c, d, e) (CMP4(x, a, b, c, d) && x[4] == 0x##e)
|
||||
// void* CreateHook32(PVOID src, PVOID dst) {
|
||||
// LPBYTE bSrc = (LPBYTE)src;
|
||||
|
||||
// If this DLL is hotpatchable, sieze the opportunity
|
||||
if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC &&
|
||||
bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) {
|
||||
return Win32HotpatchHook(src, dst);
|
||||
}
|
||||
// // If this DLL is hotpatchable, sieze the opportunity
|
||||
// if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC &&
|
||||
// bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) {
|
||||
// return Win32HotpatchHook(src, dst);
|
||||
// }
|
||||
|
||||
intptr_t len = 5;
|
||||
// intptr_t len = 5;
|
||||
|
||||
// This is a very crude way to identify common instruction patterns
|
||||
// to select or patch length.
|
||||
if (CMP2(bSrc, ff, 25)) {
|
||||
// jmp DWORD PTR ds:0x........
|
||||
len = 6;
|
||||
} else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) {
|
||||
// push 0x... (byte)
|
||||
// push 0x... (dword)
|
||||
len = 7;
|
||||
} else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) {
|
||||
// push 0x... (byte)
|
||||
// mov eax,0x... (dword)
|
||||
len = 7;
|
||||
} else if (bSrc[0] == 0x68) {
|
||||
// push 0x... (dword)
|
||||
len = 5;
|
||||
} else if (CMP5(bSrc, 55, 8B, EC, 83, E4)) {
|
||||
// pusb ebp
|
||||
// mov ebp,esp
|
||||
// and esp,ffffff**
|
||||
len = 6;
|
||||
} else if (CMP5(bSrc, 55, 8B, EC, 8B, 45)) {
|
||||
// pusb ebp
|
||||
// mov ebp,esp
|
||||
// mov eax,DWORD PTR [...]
|
||||
len = 6;
|
||||
} else if (CMP5(bSrc, 55, 8B, EC, 80, 3D)) {
|
||||
// pusb ebp
|
||||
// mov ebp,esp
|
||||
// cmd BYTE PTR ds:0x...,0x...
|
||||
len = 10;
|
||||
} else if (CMP5(bSrc, B8, 00, 10, 00, 00)) {
|
||||
// mov eax,0x1000
|
||||
len = 5;
|
||||
} else {
|
||||
log_error(plfHooks, "Unable to identify gateway length! Function peek:");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x ", ((LPBYTE)src)[i]);
|
||||
}
|
||||
puts("");
|
||||
log_error(plfHooks, "Unsafely defaulting to 5!");
|
||||
len = 5;
|
||||
}
|
||||
// // This is a very crude way to identify common instruction patterns
|
||||
// // to select or patch length.
|
||||
// if (CMP2(bSrc, ff, 25)) {
|
||||
// // jmp DWORD PTR ds:0x........
|
||||
// len = 6;
|
||||
// } else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) {
|
||||
// // push 0x... (byte)
|
||||
// // push 0x... (dword)
|
||||
// len = 7;
|
||||
// } else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) {
|
||||
// // push 0x... (byte)
|
||||
// // mov eax,0x... (dword)
|
||||
// len = 7;
|
||||
// } else if (bSrc[0] == 0x68) {
|
||||
// // push 0x... (dword)
|
||||
// len = 5;
|
||||
// } else if (CMP5(bSrc, 55, 8B, EC, 83, E4)) {
|
||||
// // pusb ebp
|
||||
// // mov ebp,esp
|
||||
// // and esp,ffffff**
|
||||
// len = 6;
|
||||
// } else if (CMP5(bSrc, 55, 8B, EC, 8B, 45)) {
|
||||
// // pusb ebp
|
||||
// // mov ebp,esp
|
||||
// // mov eax,DWORD PTR [...]
|
||||
// len = 6;
|
||||
// } else if (CMP5(bSrc, 55, 8B, EC, 80, 3D)) {
|
||||
// // pusb ebp
|
||||
// // mov ebp,esp
|
||||
// // cmd BYTE PTR ds:0x...,0x...
|
||||
// len = 10;
|
||||
// } else if (CMP5(bSrc, B8, 00, 10, 00, 00)) {
|
||||
// // mov eax,0x1000
|
||||
// len = 5;
|
||||
// } else {
|
||||
// char hex_str[16 * 3 + 1];
|
||||
// hex_str[0] = 0;
|
||||
// for (int i = 0; i < 16; i++) {
|
||||
// snprintf(&hex_str[i * 3], 4, "%02x ", ((LPBYTE)src)[i]);
|
||||
// }
|
||||
// hex_str[sizeof hex_str - 1] = 0;
|
||||
// log_error(plfHooks, "Unable to identify gateway length! Function peek: %s", hex_str);
|
||||
// log_error(plfHooks, "Unsafely defaulting to 5!");
|
||||
// len = 5;
|
||||
// }
|
||||
|
||||
PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!gateway) return NULL;
|
||||
// PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
// if (!gateway) return NULL;
|
||||
|
||||
memcpy(gateway, src, len);
|
||||
// memcpy(gateway, src, len);
|
||||
|
||||
*(PCHAR)((int)gateway + len) = '\xE9';
|
||||
*(PINT)((int)gateway + len + 1) = (int)src - (int)gateway - 5;
|
||||
// *(PCHAR)((size_t)gateway + len) = '\xE9';
|
||||
// *(PINT)((size_t)gateway + len + 1) = size2int((size_t)src - (size_t)gateway - 5);
|
||||
|
||||
Detour(src, dst, len);
|
||||
// Detour(src, dst, len);
|
||||
|
||||
return gateway;
|
||||
}
|
||||
// return gateway;
|
||||
// }
|
||||
|
||||
extern FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
|
||||
// extern FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
|
||||
|
||||
void setup_hooks() {
|
||||
log_info(plfHooks, "attaching");
|
||||
|
||||
LONG detourError;
|
||||
if (hook_list == NULL) {
|
||||
log_warning(plfHooks, "No hooks to register!");
|
||||
return;
|
||||
@ -176,13 +221,27 @@ void setup_hooks() {
|
||||
if (original == NULL) {
|
||||
log_warning(plfHooks, "failed to get original %s (%03x)", hook->name, GetLastError());
|
||||
} else {
|
||||
void* gateway = CreateHook32(original, hook->patch);
|
||||
if (hook->store != NULL) *hook->store = gateway;
|
||||
// void* gateway = CreateHook(original, hook->patch);
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
detourError = DetourAttach(&original, hook->patch);
|
||||
if (detourError != NO_ERROR) {
|
||||
log_error(plfHooks, "DetourAttach failed: %d", detourError);
|
||||
DetourTransactionAbort();
|
||||
continue;
|
||||
}
|
||||
|
||||
detourError = DetourTransactionCommit();
|
||||
if (detourError != NO_ERROR) {
|
||||
log_error(plfHooks, "DetourTransactionCommit failed: %d", detourError);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hook->store != NULL) *hook->store = original;
|
||||
log_misc(plfHooks, "hooked %s", hook->name);
|
||||
}
|
||||
|
||||
hook = hook->next;
|
||||
} while (hook != NULL);
|
||||
|
||||
log_info(plfHooks, "attach complete");
|
||||
}
|
||||
|
@ -10,11 +10,21 @@ typedef struct function_hook {
|
||||
struct function_hook* next;
|
||||
} function_hook_t;
|
||||
|
||||
static BOOL Detour(PVOID src, PVOID dst, const intptr_t len);
|
||||
#define NOP 0x90
|
||||
|
||||
void patch_at(PVOID addr, const char* patch, DWORD length);
|
||||
void clear_at(PVOID addr, BYTE clearVal, DWORD length);
|
||||
void* CreateHook32(PVOID src, PVOID dst);
|
||||
DWORD MiceGetImageBase(void);
|
||||
|
||||
void MiceHookPatchAt(PVOID addr, const void* patch, DWORD length);
|
||||
#define MiceHookPatchAtImage(hModule, addr, patch, length) \
|
||||
MiceHookPatchAt((PVOID)((DWORD)(addr) + ((DWORD)(hModule)-MiceGetImageBase())), (patch), \
|
||||
(length))
|
||||
void MiceHookClearAt(PVOID addr, BYTE clearVal, DWORD length);
|
||||
#define MiceHookClearAtImage(hModule, addr, clearVal, length) \
|
||||
MiceHookClearAt((PVOID)((DWORD)(addr) + ((DWORD)(hModule)-MiceGetImageBase())), (clearVal), \
|
||||
(length))
|
||||
#define MiceHookNopAt(addr, length) MiceHookClearAt((addr), NOP, (length))
|
||||
#define MiceHookNopAtImage(hModule, addr, length) \
|
||||
MiceHookClearAtImage((hModule), (addr), NOP, (length))
|
||||
|
||||
static void append_hook(function_hook_t* hook);
|
||||
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store);
|
||||
|
@ -31,8 +31,14 @@ void PrintStack(void) {
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
BOOL FileExists(wchar_t* szPath) {
|
||||
DWORD dwAttrib = GetFileAttributesW(szPath);
|
||||
BOOL FileExistsW(const wchar_t* szPath) {
|
||||
DWORD dwAttrib = _GetFileAttributesW(szPath);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
BOOL FileExistsA(const char* szPath) {
|
||||
wchar_t szPathW[MAX_PATH + 1];
|
||||
MultiByteToWideChar(0, 0, szPath, -1, szPathW, _countof(szPathW));
|
||||
DWORD dwAttrib = _GetFileAttributesW(szPathW);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
@ -156,17 +162,17 @@ void make_dirs(const char* path) {
|
||||
free(temp);
|
||||
}
|
||||
|
||||
void* open_mapped_file(LPCWSTR lpFilename, DWORD size, HANDLE* file, HANDLE* file_mapping) {
|
||||
char szFileName[MAX_PATH] = { 0 };
|
||||
WideCharToMultiByte(CP_ACP, 0, lpFilename, wcslen(lpFilename), szFileName, sizeof szFileName,
|
||||
NULL, NULL);
|
||||
make_dirs(szFileName);
|
||||
void* open_mapped_file(LPCSTR lpFilename, DWORD size, HANDLE* file, HANDLE* file_mapping) {
|
||||
// char szFileName[MAX_PATH] = { 0 };
|
||||
// WideCharToMultiByte(CP_ACP, 0, lpFilename, wcslen(lpFilename), szFileName,
|
||||
// size2int(sizeof szFileName), NULL, NULL);
|
||||
make_dirs(lpFilename);
|
||||
|
||||
*file = _CreateFileW(lpFilename, GENERIC_READ | GENERIC_WRITE,
|
||||
*file = _CreateFileA(lpFilename, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (*file == INVALID_HANDLE_VALUE) {
|
||||
log_error(plfMisc, "Failed to CreateFileW(%ls): %d", lpFilename, GetLastError());
|
||||
log_error(plfMisc, "Failed to CreateFileW(%s): %d", lpFilename, GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../hooks/files.h"
|
||||
|
||||
BOOL PathEqual(LPCSTR path1, LPCSTR path2) {
|
||||
char buffer1[MAX_PATH];
|
||||
char buffer2[MAX_PATH];
|
||||
@ -24,10 +26,10 @@ BOOL PathPrefix(LPCSTR path, LPCSTR prefix) {
|
||||
|
||||
static char WORKING_DIR[MAX_PATH + 1] = { 0 };
|
||||
char GetGamedataDrive(void) {
|
||||
if (WORKING_DIR[0] == 0x00) GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
|
||||
if (WORKING_DIR[0] == 0x00) _GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
|
||||
return WORKING_DIR[0];
|
||||
}
|
||||
BOOL IsGamedataLocalPath(LPCSTR path) {
|
||||
if (WORKING_DIR[0] == 0x00) GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
|
||||
if (WORKING_DIR[0] == 0x00) _GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
|
||||
return PathPrefix(path, WORKING_DIR);
|
||||
}
|
||||
|
@ -3,8 +3,14 @@
|
||||
#include "../lib/mice/mice.h"
|
||||
|
||||
const char* KNOWN_GAMES[] = {
|
||||
// Ideally, we're running from the X: root
|
||||
"maimai\\maimai_dump_.exe",
|
||||
"maimai\\maimai_dump.exe",
|
||||
"maimai\\Game.exe",
|
||||
// Preferentially use a decrypted dump if present
|
||||
"maimai_dump_.exe",
|
||||
"maimai_dump.exe",
|
||||
"Game.exe",
|
||||
|
||||
// Specific games
|
||||
"DOA5A.exe",
|
||||
@ -16,50 +22,12 @@ const char* KNOWN_GAMES[] = {
|
||||
"maimai.exe",
|
||||
};
|
||||
|
||||
bool locate_file(char* path, size_t len, const char* exe) {
|
||||
WIN32_FIND_DATA fdFile;
|
||||
HANDLE hFind = NULL;
|
||||
|
||||
char work_path[2048];
|
||||
snprintf(work_path, sizeof work_path, ".\\*.*");
|
||||
|
||||
if ((hFind = FindFirstFile(work_path, &fdFile)) == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
do {
|
||||
if (!strcmp(fdFile.cFileName, ".") || !strcmp(fdFile.cFileName, "..")) continue;
|
||||
|
||||
if (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
||||
|
||||
if (!strcmp(fdFile.cFileName, exe)) {
|
||||
snprintf(path, len, ".\\%s", fdFile.cFileName);
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
} while (FindNextFile(hFind, &fdFile));
|
||||
|
||||
FindClose(hFind);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_game(char* path, size_t len) {
|
||||
// This is slightly wasteful, but is needed to ensure priority!
|
||||
for (size_t i = 0; i < ((sizeof KNOWN_GAMES) / (sizeof KNOWN_GAMES[0])); i++) {
|
||||
if (locate_file(path, len, KNOWN_GAMES[i])) {
|
||||
for (size_t i = 0; i < _countof(KNOWN_GAMES); i++) {
|
||||
if (PathFileExistsA(KNOWN_GAMES[i])) {
|
||||
snprintf(path, len, ".\\%s", KNOWN_GAMES[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_library(char* path, size_t len) {
|
||||
if (locate_file(path, len, MiceConfig.launcher.mice_dll)) return true;
|
||||
|
||||
// Don't call DllMain! We don't want to hook ourself!
|
||||
HANDLE mice = LoadLibraryExA(MiceConfig.launcher.mice_dll, NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||
if (mice != NULL) {
|
||||
GetModuleFileNameA(mice, path, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -4,6 +4,4 @@
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
bool locate_exe(char* path, size_t len, const char* exe);
|
||||
bool locate_game(char* path, size_t len);
|
||||
bool locate_library(char* path, size_t len);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/ipc.h"
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "../lib/util/pid.h"
|
||||
#include "locate.h"
|
||||
@ -10,7 +11,10 @@ bool debug_wait = false;
|
||||
int boot_delay = 0;
|
||||
char exe_name[MAX_PATH + 1] = "";
|
||||
|
||||
size_t nCommandLine = 256;
|
||||
BYTE _MiceLauncherNext = 2;
|
||||
HANDLE _MiceLauncherNextEvent = INVALID_HANDLE_VALUE;
|
||||
|
||||
size_t nCommandLine = 0;
|
||||
char* commandLine = NULL;
|
||||
|
||||
static void print_help(char* exe) {
|
||||
@ -71,19 +75,22 @@ static bool parse_cmdline(int argc, char* argv[]) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
size_t newLength = nCommandLine + 1 + strlen(argv[i]) + 1;
|
||||
if (newLength > nCommandLine) {
|
||||
nCommandLine = newLength;
|
||||
nCommandLine += 1 + strlen(argv[i]) + 1;
|
||||
if (commandLine == NULL) {
|
||||
commandLine = malloc(nCommandLine);
|
||||
commandLine[0] = '\0';
|
||||
} else {
|
||||
commandLine = realloc(commandLine, nCommandLine);
|
||||
}
|
||||
strcat_s(commandLine, nCommandLine, " ");
|
||||
strcat_s(commandLine, nCommandLine, argv[i]);
|
||||
commandLine[nCommandLine - 1] = '\0';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
|
||||
static DWORD WINAPI MiceIpcMessageWatcher(PVOID _) {
|
||||
// Enable colour support in conhost
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
@ -101,132 +108,253 @@ static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
|
||||
}
|
||||
}
|
||||
|
||||
OVERLAPPED ov;
|
||||
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
ov.Offset = ov.OffsetHigh = 0;
|
||||
ov.hEvent = hEvent;
|
||||
|
||||
char readBuffer[4096];
|
||||
DWORD nRead, nBytes;
|
||||
while (1) {
|
||||
nRead = nBytes = 0;
|
||||
ReadFile(*pSlot, readBuffer, sizeof readBuffer, &nRead, &ov);
|
||||
GetOverlappedResult(*pSlot, &ov, &nBytes, TRUE);
|
||||
DWORD nWrote;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), readBuffer, nBytes, &nWrote, NULL);
|
||||
MICE_IPC_MESSAGE message;
|
||||
MiceIpcPopMessage(&message, TRUE);
|
||||
|
||||
if (hLogFile != INVALID_HANDLE_VALUE) {
|
||||
// The only VT100 sequences being used are colours, so this lazy approach works
|
||||
BOOL inVt100 = FALSE;
|
||||
for (unsigned int i = 0; i < nBytes; i++) {
|
||||
if (readBuffer[i] == '\033') {
|
||||
inVt100 = TRUE;
|
||||
continue;
|
||||
switch (message.m_Type) {
|
||||
case MICE_IPC_TYPE_LOG:
|
||||
// printf("%s", message.m_Message);
|
||||
|
||||
DWORD nWrote;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), message.m_Message, message.m_Size,
|
||||
&nWrote, NULL);
|
||||
|
||||
if (hLogFile != INVALID_HANDLE_VALUE) {
|
||||
// The only VT100 sequences being used are colours, so this lazy approach works
|
||||
BOOL inVt100 = FALSE;
|
||||
for (unsigned int i = 0; i < message.m_Size; i++) {
|
||||
if (message.m_Message[i] == '\033') {
|
||||
inVt100 = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (inVt100 && message.m_Message[i] == 'm') {
|
||||
inVt100 = FALSE;
|
||||
continue;
|
||||
}
|
||||
if (!inVt100)
|
||||
WriteFile(hLogFile, &(message.m_Message[i]), 1, &nWrote, NULL);
|
||||
}
|
||||
// FlushFileBuffers(hLogFile);
|
||||
}
|
||||
if (inVt100 && readBuffer[i] == 'm') {
|
||||
inVt100 = FALSE;
|
||||
continue;
|
||||
}
|
||||
if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL);
|
||||
}
|
||||
// FlushFileBuffers(hLogFile);
|
||||
// FlushFileBuffers(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL setup_mailslot(void) {
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
char slotName[MAX_PATH + 1];
|
||||
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", pid);
|
||||
|
||||
HANDLE* pSlot = malloc(sizeof(HANDLE));
|
||||
if (pSlot == NULL) {
|
||||
fprintf(stderr, "malloc(pSlot) failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
*pSlot = CreateMailslotA(slotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
|
||||
if (*pSlot == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Creation of mailslot failed %d\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CreateThread(NULL, 0, MiceMailslotWatcher, pSlot, 0, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because logging is via a mailslot, we need to give it a chance to flush messages before
|
||||
* terminating. While we could engineer something overly fancy, the only situation this ever occurs
|
||||
* is in the main() function just below.
|
||||
* Because logging is via IPC, we need to give it a chance to flush messages before
|
||||
* terminating. While we could engineer something overly fancy, the only situation
|
||||
* this ever occurs is in the main() function just below.
|
||||
*
|
||||
* I'll let the code speak for itself.
|
||||
*/
|
||||
static int terminate(int err) {
|
||||
Sleep(100);
|
||||
static int terminate(int err, char* szMessage) {
|
||||
printf("Mice termination occuring... %d\n", err);
|
||||
log_info(plfBoot, "Terminating");
|
||||
Sleep(1000);
|
||||
|
||||
extern unsigned char g_szFault[255 + 1];
|
||||
extern BYTE g_nFault;
|
||||
|
||||
if (g_nFault) {
|
||||
MessageBeep(MB_ICONERROR);
|
||||
MessageBoxA(NULL, (LPCSTR)g_szFault, "System Fault",
|
||||
MB_OK | MB_SETFOREGROUND | MB_SYSTEMMODAL);
|
||||
} else if (szMessage) {
|
||||
MessageBeep(MB_ICONERROR);
|
||||
MessageBoxA(NULL, szMessage, "Boot Failed", MB_OK | MB_SETFOREGROUND | MB_SYSTEMMODAL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
HANDLE hJob = INVALID_HANDLE_VALUE;
|
||||
BOOL WINAPI MiceHandlerRoutine(DWORD CtrlType) {
|
||||
if (hJob != INVALID_HANDLE_VALUE) CloseHandle(hJob);
|
||||
ExitProcess(terminate(0));
|
||||
ExitProcess(terminate(0, NULL));
|
||||
}
|
||||
|
||||
#include "../lib/mice/spad.h"
|
||||
static BOOL StartGame(LPPROCESS_INFORMATION lpPi, LPCSTR args) {
|
||||
// Clear out the next flag. If the game closes without setting this, we don't want to restart
|
||||
// the game.
|
||||
_MiceLauncherNext = 0;
|
||||
|
||||
hJob = CreateJobObject(NULL, NULL);
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
|
||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
||||
|
||||
size_t nFullCommandLine = strlen(exe_name) + 1;
|
||||
if (args != NULL && strlen(args) > 0) nFullCommandLine += 1 + strlen(args);
|
||||
if (nCommandLine > 0) nFullCommandLine += 1 + nCommandLine;
|
||||
char* fullCommandLine = malloc(nFullCommandLine);
|
||||
|
||||
if (args != NULL && nCommandLine > 0) {
|
||||
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s %s", exe_name, args, commandLine);
|
||||
} else if (args == NULL && nCommandLine > 0) {
|
||||
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine);
|
||||
} else if (args != NULL) {
|
||||
sprintf_s(fullCommandLine, nFullCommandLine, "%s %s", exe_name, args);
|
||||
} else {
|
||||
sprintf_s(fullCommandLine, nFullCommandLine, "%s", exe_name);
|
||||
}
|
||||
|
||||
char* extra_injections = MiceConfig.launcher.inject;
|
||||
if (!start_and_inject(hJob, exe_name, fullCommandLine, _miceIpcData->m_MiceDll, debug_wait,
|
||||
boot_delay, extra_injections, 0, lpPi)) {
|
||||
free(fullCommandLine);
|
||||
return FALSE;
|
||||
}
|
||||
free(fullCommandLine);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _GameIdSearcher(char* lpBasePath, char* lpGameId) {
|
||||
WIN32_FIND_DATAA findFileData;
|
||||
|
||||
CHAR szSearchPath[MAX_PATH + 1];
|
||||
sprintf_s(szSearchPath, _countof(szSearchPath), "%s\\*", lpBasePath);
|
||||
|
||||
// Search for a table in the CWD
|
||||
HANDLE hFind = FindFirstFileA(szSearchPath, &findFileData);
|
||||
do {
|
||||
if (strcmp(findFileData.cFileName, ".") == 0 || strcmp(findFileData.cFileName, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
sprintf_s(szSearchPath, _countof(szSearchPath), "%s\\%s", lpBasePath,
|
||||
findFileData.cFileName);
|
||||
if (_GameIdSearcher(szSearchPath, lpGameId)) {
|
||||
FindClose(hFind);
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
if (strlen(findFileData.cFileName) == strlen("SAAA_Table.dat") &&
|
||||
PathMatchSpecA(findFileData.cFileName, "S*_Table.dat")) {
|
||||
// maimai games have a copy of the R&D table; ignore it.
|
||||
if (strncmp(findFileData.cFileName, "SBRZ", 4) == 0) continue;
|
||||
lpGameId[0] = findFileData.cFileName[0];
|
||||
lpGameId[1] = findFileData.cFileName[1];
|
||||
lpGameId[2] = findFileData.cFileName[2];
|
||||
lpGameId[3] = findFileData.cFileName[3];
|
||||
|
||||
FindClose(hFind);
|
||||
return TRUE;
|
||||
}
|
||||
if (strlen(findFileData.cFileName) == strlen("SAAA_banner.bmp") &&
|
||||
PathMatchSpecA(findFileData.cFileName, "S*_banner.bmp")) {
|
||||
lpGameId[0] = findFileData.cFileName[0];
|
||||
lpGameId[1] = findFileData.cFileName[1];
|
||||
lpGameId[2] = findFileData.cFileName[2];
|
||||
lpGameId[3] = findFileData.cFileName[3];
|
||||
|
||||
FindClose(hFind);
|
||||
return TRUE;
|
||||
}
|
||||
if (strlen(findFileData.cFileName) == strlen("SAAA_main.wmv") &&
|
||||
PathMatchSpecA(findFileData.cFileName, "S*_main.wmv")) {
|
||||
lpGameId[0] = findFileData.cFileName[0];
|
||||
lpGameId[1] = findFileData.cFileName[1];
|
||||
lpGameId[2] = findFileData.cFileName[2];
|
||||
lpGameId[3] = findFileData.cFileName[3];
|
||||
|
||||
FindClose(hFind);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &findFileData));
|
||||
FindClose(hFind);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL MiceGuessGameId(char* lpGameId) {
|
||||
if (_GameIdSearcher(".", lpGameId)) return TRUE;
|
||||
|
||||
// TODO: Some more lookups. Exe name is probably not an awful fallback
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL g_bIsInDllMain = FALSE;
|
||||
int main(int argc, char* argv[]) {
|
||||
// unsigned char spad_new_bytes[16] = {
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x06,
|
||||
// 0x94, 0x87, 0x82, 0x60, 0x37, 0x73, 0x12, 0x13,
|
||||
// };
|
||||
// unsigned char spn[16];
|
||||
// Spad0Encrypt(spn, spad_new_bytes);
|
||||
// for (int i = 0; i < 8; i++) printf("%02x", spn[i]);
|
||||
// puts("");
|
||||
// for (int i = 8; i < 16; i++) printf("%02x", spn[i]);
|
||||
// puts("");
|
||||
#if 0
|
||||
// char buffer[] = "41A800003F000000000000006801";
|
||||
char* buffer = argv[1];
|
||||
char local_10[4];
|
||||
|
||||
// puts("--");
|
||||
sscanf_s(buffer, "%08x", local_10, sizeof local_10);
|
||||
float measure_whole = *(float*)(void*)&local_10;
|
||||
printf("measure_whole: %f\n", measure_whole);
|
||||
sscanf_s(buffer + 8, "%08x", local_10, sizeof local_10);
|
||||
float measure_fraction = *(float*)(void*)&local_10;
|
||||
printf("measure_fraction: %f\n", measure_fraction);
|
||||
sscanf_s(buffer + 16, "%08x", local_10, sizeof local_10);
|
||||
float duration = *(float*)(void*)&local_10;
|
||||
printf("duration: %f\n", duration);
|
||||
sscanf_s(buffer + 24, "%01x", local_10, sizeof local_10);
|
||||
unsigned char location = local_10[0];
|
||||
printf("location: %d\n", location);
|
||||
|
||||
// unsigned char back_out[16];
|
||||
// Spad0Decrypt(back_out, spn);
|
||||
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
|
||||
// puts("");
|
||||
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
|
||||
// puts("");
|
||||
sscanf_s(buffer + 25, "%01x", local_10, sizeof local_10);
|
||||
unsigned char type = local_10[0];
|
||||
|
||||
// unsigned char bng[16] = {
|
||||
// 0xE6, 0xBC, 0x6D, 0x56, 0x83, 0xF6, 0xB6, 0x48,
|
||||
// 0x4C, 0x24, 0xE4, 0x83, 0xD5, 0xE8, 0x93, 0x7F,
|
||||
// };
|
||||
// Spad0Decrypt(back_out, bng);
|
||||
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
|
||||
// puts("");
|
||||
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
|
||||
// puts("");
|
||||
printf("Type: %d\n", local_10[0]);
|
||||
if (local_10[0] < '\0') {
|
||||
type = type ^ 0x80;
|
||||
puts("<0");
|
||||
// field_0x42 = 1;
|
||||
}
|
||||
if ((type & 0x40) != 0) {
|
||||
puts("&0x40");
|
||||
type = type ^ 0x40;
|
||||
// field15_0x18 = 0x40000000;
|
||||
}
|
||||
if ((type & 0x20) != 0) {
|
||||
puts("&0x20");
|
||||
type = type ^ 0x20;
|
||||
// field15_0x18 = 0x40800000;
|
||||
}
|
||||
printf("TypeO: %01x\n", type);
|
||||
|
||||
// return -1;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
load_mice_config();
|
||||
if (!setup_mailslot()) return 1;
|
||||
|
||||
if (!MiceIpcSetup(TRUE)) return 1;
|
||||
_miceIpcData->m_LauncherIsReady = TRUE;
|
||||
char gameId[4];
|
||||
if (MiceGuessGameId(gameId)) memcpy(_miceIpcData->m_GameId, gameId, 4);
|
||||
|
||||
CreateThread(NULL, 0, MiceIpcMessageWatcher, NULL, 0, NULL);
|
||||
|
||||
setup_logging();
|
||||
|
||||
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
||||
|
||||
commandLine = malloc(nCommandLine);
|
||||
if (commandLine == NULL) {
|
||||
log_error(plfBoot, "Fatal: Failed to malloc(commandLine)");
|
||||
return terminate(-1);
|
||||
if (_miceIpcData->m_GameId[0] == '\0') {
|
||||
if (MiceConfig.devices.do_auto) {
|
||||
log_error(
|
||||
plfBoot,
|
||||
"Failed to identify game. Please edit [devices].do_auto to false and restart.");
|
||||
log_error(plfBoot, "Please also report this.");
|
||||
return terminate(-1, "Failed to identify game.");
|
||||
}
|
||||
log_warning(plfBoot, "Failed to identify game, but proceeding regardless.");
|
||||
} else {
|
||||
log_info(plfBoot, "Booting game: %.*s", 4, _miceIpcData->m_GameId);
|
||||
}
|
||||
commandLine[0] = '\0';
|
||||
|
||||
CHAR workDir[MAX_PATH + 1];
|
||||
GetCurrentDirectory(MAX_PATH, workDir);
|
||||
log_info(plfBoot, "Current directory: %s", workDir);
|
||||
CHAR szPath[MAX_PATH + 1];
|
||||
GetCurrentDirectory(MAX_PATH, szPath);
|
||||
szPath[sizeof szPath - 1] = '\0';
|
||||
log_info(plfBoot, "Current directory: %s", szPath);
|
||||
|
||||
if (!parse_cmdline(argc, argv)) return terminate(0);
|
||||
if (!parse_cmdline(argc, argv)) {
|
||||
puts("parse_cmdline failed");
|
||||
return terminate(-2, "parse_cmdline failed");
|
||||
}
|
||||
|
||||
if (exe_name[0] == '\0' && MiceConfig.launcher.game_binary[0] != '\0') {
|
||||
snprintf(exe_name, sizeof exe_name, "%s", MiceConfig.launcher.game_binary);
|
||||
@ -237,56 +365,89 @@ int main(int argc, char* argv[]) {
|
||||
if (exe_name[0] == '\0') {
|
||||
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
||||
log_error(plfBoot, "Fatal: Failed to locate a game");
|
||||
return terminate(0);
|
||||
return terminate(-3, "Failed to locate a game");
|
||||
}
|
||||
} else {
|
||||
DWORD dwAttrib = GetFileAttributes(exe_name);
|
||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
log_error(plfBoot, "Fatal: %s: no such file found", exe_name);
|
||||
return terminate(0);
|
||||
return terminate(-4, "Specified executable not locatable");
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
// Build IPC.m_PathPrefix
|
||||
{
|
||||
_miceIpcData->m_PathPrefix[0] = '\0';
|
||||
for (i = 0; i < sizeof _miceIpcData->m_PathPrefix; i++) {
|
||||
_miceIpcData->m_PathPrefix[i] = exe_name[i];
|
||||
if (exe_name[i] == '\0') break;
|
||||
}
|
||||
// Find the final slash in the path
|
||||
for (; i > 0; i--) {
|
||||
if (_miceIpcData->m_PathPrefix[i] == '/' || _miceIpcData->m_PathPrefix[i] == '\\')
|
||||
break;
|
||||
}
|
||||
_miceIpcData->m_PathPrefix[i] = '\0';
|
||||
}
|
||||
|
||||
strcpy_s(_miceIpcData->m_MiceBase, sizeof _miceIpcData->m_MiceBase, szPath);
|
||||
|
||||
if (!SearchPathA(NULL, MiceConfig.launcher.mice_dll, NULL, sizeof _miceIpcData->m_MiceDll,
|
||||
_miceIpcData->m_MiceDll, NULL)) {
|
||||
log_error(plfBoot, "Unable to locate micelib. Check your mice_dll setting!");
|
||||
return terminate(-5, "Unable to locate micelib");
|
||||
}
|
||||
_miceIpcData->m_MiceDll[sizeof _miceIpcData->m_MiceDll - 1] = '\0';
|
||||
|
||||
_MiceLauncherNextEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
||||
|
||||
spawn_pcp_processes();
|
||||
|
||||
log_info(plfBoot, "exec: %s %s", exe_name, commandLine);
|
||||
|
||||
char micepath[MAX_PATH + 1];
|
||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||
log_error(plfBoot, "Fatal: Failed to locate micelib. Check your mice_dll setting!");
|
||||
return terminate(0);
|
||||
while (1) {
|
||||
if (hJob != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hJob);
|
||||
hJob = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION pi;
|
||||
if (_MiceLauncherNext == 2) {
|
||||
if (!StartGame(&pi, NULL))
|
||||
return terminate(-6, "Start failed. Check console for errors.");
|
||||
} else if (_MiceLauncherNext == 3 || _MiceLauncherNext == 4) {
|
||||
// TODO: Boot mode 3 is actually system test. We could do something here?
|
||||
if (!StartGame(&pi, "gametest"))
|
||||
return terminate(-7, "Gametest failed. Check console for errors.");
|
||||
} else {
|
||||
log_info(plfBoot, "Boot mode %d not supported. Exiting.", _MiceLauncherNext);
|
||||
return terminate(-8, NULL);
|
||||
}
|
||||
|
||||
HANDLE objects[2];
|
||||
objects[0] = pi.hProcess;
|
||||
objects[1] = _MiceLauncherNextEvent;
|
||||
DWORD waited = WaitForMultipleObjects(_countof(objects), objects, FALSE, INFINITE);
|
||||
if (FAILED(waited)) {
|
||||
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
||||
return terminate(-9, "WFSO failed");
|
||||
}
|
||||
if (waited == WAIT_OBJECT_0) {
|
||||
DWORD exitCode;
|
||||
if (GetExitCodeProcess(pi.hProcess, &exitCode))
|
||||
log_info(plfBoot, "Shutting down (ret:%d)", exitCode);
|
||||
else
|
||||
log_info(plfBoot, "Shutting down (failed to get exit code)");
|
||||
CloseHandle(pi.hProcess);
|
||||
continue;
|
||||
// return terminate(-10);
|
||||
} else if (waited == WAIT_OBJECT_0 + 1) {
|
||||
continue;
|
||||
} else {
|
||||
log_error(plfBoot, "Unknown wait object retured: %d", waited);
|
||||
return terminate(-11, "Unknown wait object!");
|
||||
}
|
||||
}
|
||||
|
||||
hJob = CreateJobObject(NULL, NULL);
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
|
||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
||||
|
||||
size_t nFullCommandLine = nCommandLine + strlen(exe_name) + 1;
|
||||
char* fullCommandLine = malloc(nFullCommandLine);
|
||||
snprintf(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine);
|
||||
free(commandLine);
|
||||
|
||||
char* extra_injections = MiceConfig.launcher.inject;
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!start_and_inject(hJob, exe_name, fullCommandLine, micepath, debug_wait, boot_delay,
|
||||
extra_injections, 0, &pi)) {
|
||||
free(fullCommandLine);
|
||||
return terminate(-1);
|
||||
}
|
||||
free(fullCommandLine);
|
||||
|
||||
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
||||
|
||||
if (FAILED(WaitForSingleObject(pi.hProcess, INFINITE))) {
|
||||
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
||||
} else {
|
||||
DWORD exitCode;
|
||||
if (GetExitCodeProcess(pi.hProcess, &exitCode))
|
||||
log_info(plfBoot, "Shutting down (ret:%d)", exitCode);
|
||||
else
|
||||
log_info(plfBoot, "Shutting down (failed to get exit code)");
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
return terminate(0);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
rc = import('windows').compile_resources('mice.rc', depend_files: mice_ico)
|
||||
executable(
|
||||
'mice',
|
||||
get_option('win64') ? 'mice64' : 'mice',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'locate.c',
|
||||
@ -18,5 +18,9 @@ executable(
|
||||
dummykeychip,
|
||||
dummymaster,
|
||||
dummyinstaller,
|
||||
dummygdeliver,
|
||||
dummynetwork,
|
||||
|
||||
amSerialId,
|
||||
],
|
||||
)
|
||||
|
@ -1,3 +1,3 @@
|
||||
#include <winuser.h>
|
||||
|
||||
0 ICON "../assets/mice.ico"
|
||||
0 ICON "../../assets/mice.ico"
|
||||
|
@ -3,35 +3,44 @@
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
|
||||
spawn_t mxspawns[3] = {
|
||||
// { "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc },
|
||||
// { "master", SPAWN_DUMMY, MdmThreadProc, NULL },
|
||||
// { "installer", SPAWN_DUMMY, MdiThreadProc, NULL },
|
||||
{ "keychip", SPAWN_NONE, MdkThreadProc, MxkThreadProc },
|
||||
{ "master", SPAWN_NONE, MdmThreadProc, NULL },
|
||||
{ "installer", SPAWN_NONE, MdiThreadProc, NULL },
|
||||
spawn_t mxspawns[] = {
|
||||
{ "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc },
|
||||
{ "master", SPAWN_DUMMY, MdmThreadProc, NULL },
|
||||
{ "installer", SPAWN_DUMMY, MdiThreadProc, NULL },
|
||||
{ "network", SPAWN_DUMMY, MdnThreadProc, NULL },
|
||||
{ "gdeliver", SPAWN_DUMMY, MdgdThreadProc, NULL },
|
||||
};
|
||||
|
||||
int mxkMain();
|
||||
int miceDummyKeychip(unsigned short textPort, unsigned short binaryPort, bool global);
|
||||
int miceDummyMaster(unsigned short textPort, unsigned short binaryPort, bool global);
|
||||
int miceDummyInstaller(unsigned short textPort, unsigned short binaryPort, bool global);
|
||||
int miceDummyNetwork(unsigned short textPort, unsigned short binaryPort, bool global);
|
||||
int miceDummyGDeliver(unsigned short textPort, unsigned short binaryPort, bool global);
|
||||
DWORD WINAPI MdkThreadProc(LPVOID lpParameter) {
|
||||
miceDummyKeychip(40106, 40107, false);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
DWORD WINAPI MxkThreadProc(LPVOID lpParameter) {
|
||||
mxkMain();
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
DWORD WINAPI MdmThreadProc(LPVOID lpParameter) {
|
||||
miceDummyMaster(40100, 40101, false);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
DWORD WINAPI MdiThreadProc(LPVOID lpParameter) {
|
||||
miceDummyInstaller(40102, 40103, false);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
DWORD WINAPI MdnThreadProc(LPVOID lpParameter) {
|
||||
miceDummyNetwork(40104, 40105, false);
|
||||
return 0;
|
||||
}
|
||||
DWORD WINAPI MdgdThreadProc(LPVOID lpParameter) {
|
||||
miceDummyGDeliver(40108, 40112, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void spawn_one(spawn_t* spawn) {
|
||||
if (spawn->mode == SPAWN_NONE) {
|
||||
|
@ -12,11 +12,13 @@ typedef struct {
|
||||
#define SPAWN_REAL 2
|
||||
#define SPAWN_BOTH (SPAWN_DUMMY | SPAWN_REAL)
|
||||
|
||||
extern spawn_t mxspawns[3];
|
||||
extern spawn_t mxspawns[5];
|
||||
|
||||
DWORD WINAPI MxkThreadProc(LPVOID lpParameter);
|
||||
DWORD WINAPI MdkThreadProc(LPVOID lpParameter);
|
||||
DWORD WINAPI MdmThreadProc(LPVOID lpParameter);
|
||||
DWORD WINAPI MdiThreadProc(LPVOID lpParameter);
|
||||
DWORD WINAPI MdnThreadProc(LPVOID lpParameter);
|
||||
DWORD WINAPI MdgdThreadProc(LPVOID lpParameter);
|
||||
|
||||
void spawn_pcp_processes(void);
|
||||
|
@ -1,5 +1,3 @@
|
||||
#include "../mice/version_fallback.h"
|
||||
|
||||
#define AM_LIB_C_HEADER(name, storage_type) \
|
||||
int name##DebugLevel = 0; \
|
||||
struct storage_type name; \
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../dmi/dmi.h"
|
||||
#include "../mice/dmi.h"
|
||||
#include "../mice/mice.h"
|
||||
|
||||
AM_LIB_C_HEADER(amOemstring, AM_OEMSTRING)
|
||||
|
@ -1,6 +0,0 @@
|
||||
dmi_lib = static_library(
|
||||
'dmi',
|
||||
sources: [
|
||||
'dmi.c'
|
||||
],
|
||||
)
|
@ -1246,7 +1246,6 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, const unsigned char* send_binary_buffer,
|
||||
|
||||
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
|
||||
size_t* psVar1;
|
||||
char** send_buf;
|
||||
undefined4 uVar2;
|
||||
int iVar3;
|
||||
e_pcpt_t eVar4;
|
||||
@ -1688,14 +1687,12 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
|
||||
} while (stream->field_0x1fc <= stream->recv_binary_buf_len &&
|
||||
stream->recv_binary_buf_len != stream->field_0x1fc);
|
||||
}
|
||||
send_buf = (char**)&stream->send_buf;
|
||||
psVar1 = &stream->send_buf_len;
|
||||
stream->state = pcpp_state_send_binary_ack;
|
||||
*send_buf[0] = PCP_CHAR_BINACK;
|
||||
*psVar1 = 1;
|
||||
stream->send_buf[0] = PCP_CHAR_BINACK;
|
||||
stream->send_buf_len = 1;
|
||||
local_20 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18),
|
||||
&timeout);
|
||||
eVar4 = pcptSend(&stream->sock, (unsigned char*)*send_buf, psVar1, stream->field_0x204,
|
||||
eVar4 = pcptSend(&stream->sock, (unsigned char*)stream->send_buf, &stream->send_buf_len, stream->field_0x204,
|
||||
timeout);
|
||||
eVar7 = _errT2P(eVar4);
|
||||
stream->err = eVar7;
|
||||
@ -1713,9 +1710,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) {
|
||||
stream->state = pcpp_state_send_binary_ack_wait;
|
||||
iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream,
|
||||
_amTimeMs(local_18), &timeout);
|
||||
*psVar1 = PCP_SEND_BUF_MAX;
|
||||
stream->send_buf_len = PCP_SEND_BUF_MAX;
|
||||
ZERO(stream->send_buf);
|
||||
eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)*send_buf, psVar1, timeout);
|
||||
eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)stream->send_buf, &stream->send_buf_len, timeout);
|
||||
eVar7 = _errT2P(eVar4);
|
||||
stream->err = eVar7;
|
||||
if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
subdir('util') # This is the only lib that should ever be link_with'd by another lib
|
||||
subdir('dmi')
|
||||
|
||||
subdir('ami')
|
||||
subdir('libpcp')
|
||||
|
@ -6,8 +6,12 @@
|
||||
|
||||
#include "../../../../subprojects/inih_dep/ini.h"
|
||||
#include "../../dll/devices/smb_pca9535.h"
|
||||
#include "../../dll/drivers/jvs_boards/jvs.h"
|
||||
#include "../../dll/hooks/files.h"
|
||||
#include "../../dll/key_config.h"
|
||||
|
||||
MICE_JVS _MiceJvsBoards[JVS_IO_MAX];
|
||||
|
||||
config_t MiceConfig = {
|
||||
#define SECTION(s, comment) .s = {
|
||||
#define CFG_str(s, n, default, comment) .n = default,
|
||||
@ -24,7 +28,7 @@ config_t MiceConfig = {
|
||||
._keep_linter_happy = true
|
||||
};
|
||||
|
||||
void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
|
||||
static void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
|
||||
char *copy = (char *)malloc(strlen(text) + 1);
|
||||
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
|
||||
|
||||
@ -38,99 +42,174 @@ void fprintf_prefix(FILE *file, const char *prefix, const char *text) {
|
||||
free(copy);
|
||||
}
|
||||
|
||||
void make_default_config() {
|
||||
FILE *config_file;
|
||||
fopen_s(&config_file, CONFIG_PATH, "w");
|
||||
if (config_file == NULL) {
|
||||
puts("Failed to create config file!");
|
||||
void save_keybinds() {
|
||||
HANDLE hFile = CreateFileA(KEYBINDS_PATH, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, NULL,
|
||||
CREATE_ALWAYS, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Failed to open keybinds file: %d", GetLastError());
|
||||
return;
|
||||
};
|
||||
int first_section = true;
|
||||
}
|
||||
|
||||
#define CFG_str(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %s ;(string)\n", #n, default);
|
||||
SetFilePointer(hFile, 8, NULL, 0);
|
||||
|
||||
#define CFG_bool(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %s ;(bool)\n", #n, default ? "true" : "false");
|
||||
DWORD nWrote;
|
||||
DWORD totalSize = 0;
|
||||
WriteFile(hFile, &MiceConfig.keys.board_count, sizeof MiceConfig.keys.board_count, &nWrote,
|
||||
NULL);
|
||||
totalSize += nWrote;
|
||||
|
||||
#define CFG_int(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %d ;(int)\n", #n, default);
|
||||
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
|
||||
WriteFile(hFile, &_MiceJvsBoards->m_Players, sizeof _MiceJvsBoards->m_Players, &nWrote,
|
||||
NULL);
|
||||
totalSize += nWrote;
|
||||
WriteFile(hFile, &_MiceJvsBoards->m_ButtonsPerPlayer,
|
||||
sizeof _MiceJvsBoards->m_ButtonsPerPlayer, &nWrote, NULL);
|
||||
totalSize += nWrote;
|
||||
WriteFile(hFile, &_MiceJvsBoards->m_Coins, sizeof _MiceJvsBoards->m_Coins, &nWrote, NULL);
|
||||
totalSize += nWrote;
|
||||
WriteFile(hFile, &_MiceJvsBoards->m_NumButtons, sizeof _MiceJvsBoards->m_NumButtons,
|
||||
&nWrote, NULL);
|
||||
totalSize += nWrote;
|
||||
|
||||
#define CFG_hex(s, n, precision, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %.*X ;(hex, %d byte%s)\n", #n, precision, 0x##default, precision, \
|
||||
precision == 1 ? "" : "s");
|
||||
WriteFile(hFile, _MiceJvsBoards[board].m_Bindings,
|
||||
sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons, &nWrote,
|
||||
NULL);
|
||||
totalSize += nWrote;
|
||||
}
|
||||
|
||||
#define CFG_ipv4(s, n, a, b, c, d, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", #n, a, b, c, d);
|
||||
SetFilePointer(hFile, 0, NULL, 0);
|
||||
WriteFile(hFile, &totalSize, sizeof totalSize, &nWrote, NULL);
|
||||
|
||||
#define SECTION(s, comment) \
|
||||
if (!first_section) fprintf(config_file, "\n"); \
|
||||
first_section = false; \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "[%s]\n", #s);
|
||||
amiCrc32RInit();
|
||||
DWORD readLeft = totalSize;
|
||||
DWORD crc32 = 0;
|
||||
SetFilePointer(hFile, 8, NULL, 0);
|
||||
while (readLeft) {
|
||||
BYTE readBuf[0x1000];
|
||||
DWORD toRead = sizeof readBuf;
|
||||
if (readLeft < toRead) toRead = readLeft;
|
||||
DWORD nRead;
|
||||
ReadFile(hFile, readBuf, toRead, &nRead, NULL);
|
||||
|
||||
#define COMMENT(comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment);
|
||||
if (nRead == 0) {
|
||||
fprintf(stderr, "Binding saving failed %d\n", GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return;
|
||||
}
|
||||
crc32 = amiCrc32RCalc(nRead, readBuf, crc32);
|
||||
readLeft -= nRead;
|
||||
}
|
||||
SetFilePointer(hFile, 4, NULL, 0);
|
||||
WriteFile(hFile, &crc32, sizeof crc32, &nWrote, NULL);
|
||||
|
||||
#include "config.def"
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
void load_keybind_config() {
|
||||
HANDLE hFile =
|
||||
CreateFileA(KEYBINDS_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
fclose(config_file);
|
||||
DWORD nRead;
|
||||
DWORD nSize = 0;
|
||||
ReadFile(hFile, &nSize, sizeof nSize, &nRead, NULL);
|
||||
|
||||
SetFilePointer(hFile, 8, NULL, 0);
|
||||
amiCrc32RInit();
|
||||
DWORD crc32 = 0;
|
||||
while (nSize) {
|
||||
BYTE readBuf[0x1000];
|
||||
DWORD toRead = sizeof readBuf;
|
||||
if (nSize < toRead) toRead = nSize;
|
||||
ReadFile(hFile, readBuf, toRead, &nRead, NULL);
|
||||
|
||||
if (nRead == 0) {
|
||||
fprintf(stderr, "Binding reading failed\n");
|
||||
CloseHandle(hFile);
|
||||
return;
|
||||
}
|
||||
crc32 = amiCrc32RCalc(nRead, readBuf, crc32);
|
||||
nSize -= nRead;
|
||||
}
|
||||
|
||||
DWORD savedCrc;
|
||||
SetFilePointer(hFile, 4, NULL, 0);
|
||||
ReadFile(hFile, &savedCrc, sizeof savedCrc, &nRead, NULL);
|
||||
if (savedCrc != crc32) {
|
||||
fprintf(stderr, "Binding file CRC failed (%08x!=%08x)\n", savedCrc, crc32);
|
||||
CloseHandle(hFile);
|
||||
return;
|
||||
}
|
||||
|
||||
ReadFile(hFile, &MiceConfig.keys.board_count, sizeof MiceConfig.keys.board_count, &nRead, NULL);
|
||||
|
||||
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
|
||||
ReadFile(hFile, &_MiceJvsBoards->m_Players, sizeof _MiceJvsBoards->m_Players, &nRead, NULL);
|
||||
ReadFile(hFile, &_MiceJvsBoards->m_ButtonsPerPlayer,
|
||||
sizeof _MiceJvsBoards->m_ButtonsPerPlayer, &nRead, NULL);
|
||||
ReadFile(hFile, &_MiceJvsBoards->m_Coins, sizeof _MiceJvsBoards->m_Coins, &nRead, NULL);
|
||||
ReadFile(hFile, &_MiceJvsBoards->m_NumButtons, sizeof _MiceJvsBoards->m_NumButtons, &nRead,
|
||||
NULL);
|
||||
|
||||
free(_MiceJvsBoards[board].m_Bindings);
|
||||
_MiceJvsBoards[board].m_Bindings =
|
||||
malloc(sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons);
|
||||
ReadFile(hFile, _MiceJvsBoards[board].m_Bindings,
|
||||
sizeof *_MiceJvsBoards[board].m_Bindings * _MiceJvsBoards->m_NumButtons, &nRead,
|
||||
NULL);
|
||||
|
||||
free(_MiceJvsBoards[board].m_ButtonStates);
|
||||
_MiceJvsBoards[board].m_ButtonStates =
|
||||
malloc(sizeof *_MiceJvsBoards[board].m_ButtonStates * _MiceJvsBoards->m_NumButtons);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
char keybindBuffer[8192];
|
||||
void save_current_config() {
|
||||
// Dump keybind settings
|
||||
int i = 0;
|
||||
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
|
||||
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
|
||||
jvsKeybindings[board].test);
|
||||
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
|
||||
jvsKeybindings[board].notdefault);
|
||||
for (int n = 0; n < JVS_BUTTON_PAIR_COUNT * 2; n++) {
|
||||
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
|
||||
jvsKeybindings[board].buttons[n]);
|
||||
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
|
||||
jvsKeybindings[board].invert[n]);
|
||||
}
|
||||
}
|
||||
keybindBuffer[i] = '\0';
|
||||
free(MiceConfig.keys.keys);
|
||||
MiceConfig.keys.keys = _strdup(keybindBuffer);
|
||||
char keybindBuffer[2 * JVS_IO_MAX * (sizeof _MiceJvsBoards[0].m_Bindings[0]) * 32];
|
||||
void save_current_config(bool writeDefault) {
|
||||
CreateDirectoryA("mice", NULL); // TODO: A touch nicer?
|
||||
|
||||
save_keybinds();
|
||||
|
||||
FILE *config_file;
|
||||
fopen_s(&config_file, CONFIG_PATH, "w");
|
||||
if (config_file == NULL) {
|
||||
puts("Failed to create config file!");
|
||||
return;
|
||||
};
|
||||
}
|
||||
int first_section = true;
|
||||
|
||||
#define CFG_str(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %s ;(string)\n", #n, MiceConfig.s.n);
|
||||
#define CFG_str(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "; (string) default = %s\n", writeDefault ? MiceConfig.s.n : default); \
|
||||
fprintf(config_file, "%s = %s\n", #n, MiceConfig.s.n);
|
||||
|
||||
#define CFG_bool(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %s ;(bool)\n", #n, MiceConfig.s.n ? "true" : "false");
|
||||
#define CFG_bool(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "; (bool) default = %s\n", \
|
||||
(writeDefault ? MiceConfig.s.n : default) ? "true" : "false"); \
|
||||
fprintf(config_file, "%s = %s\n", #n, MiceConfig.s.n ? "true" : "false");
|
||||
|
||||
#define CFG_int(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %d ;(int)\n", #n, MiceConfig.s.n);
|
||||
#define CFG_int(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "; (int) default = %d\n", writeDefault ? MiceConfig.s.n : default); \
|
||||
fprintf(config_file, "%s = %d\n", #n, MiceConfig.s.n);
|
||||
|
||||
#define CFG_hex(s, n, precision, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %.*X ;(hex, %d byte%s)\n", #n, precision, MiceConfig.s.n, \
|
||||
precision, precision == 1 ? "" : "s");
|
||||
#define CFG_hex(s, n, precision, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "; (hex, %d byte%s) default = %.*X \n", precision, \
|
||||
precision == 1 ? "" : "s", precision, writeDefault ? MiceConfig.s.n : 0x##default); \
|
||||
fprintf(config_file, "%s = %.*X\n", #n, precision, MiceConfig.s.n);
|
||||
|
||||
#define CFG_ipv4(s, n, a, b, c, d, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", #n, (MiceConfig.s.n >> 24), \
|
||||
((MiceConfig.s.n >> 16) & 0xff), ((MiceConfig.s.n >> 8) & 0xff), \
|
||||
#define CFG_ipv4(s, n, a, b, c, d, comment) \
|
||||
if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \
|
||||
fprintf(config_file, "; (ipv4) default = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", \
|
||||
writeDefault ? MiceConfig.s.n >> 24 : a, \
|
||||
writeDefault ? (MiceConfig.s.n >> 16) & 0xff : b, \
|
||||
writeDefault ? (MiceConfig.s.n >> 8) & 0xff : c, \
|
||||
writeDefault ? (MiceConfig.s.n & 0xff) : d); \
|
||||
fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu\n", #n, (MiceConfig.s.n >> 24), \
|
||||
((MiceConfig.s.n >> 16) & 0xff), ((MiceConfig.s.n >> 8) & 0xff), \
|
||||
(MiceConfig.s.n & 0xff));
|
||||
|
||||
#define SECTION(s, comment) \
|
||||
@ -189,8 +268,26 @@ const unsigned int RES_W[8] = { 640, 640, 1024, 1024, 1280, 1280, 1360, 1920 };
|
||||
const unsigned int RES_H[8] = { 480, 480, 600, 768, 720, 1024, 768, 1080 };
|
||||
void load_mice_config() {
|
||||
if (ini_parse(CONFIG_PATH, handler, &MiceConfig) < 0) {
|
||||
make_default_config();
|
||||
printf("Can't load '%s', using defaults\n", CONFIG_PATH);
|
||||
printf("Loading config defaults\n");
|
||||
|
||||
if (MiceConfig.sysconf.serial) free(MiceConfig.sysconf.serial);
|
||||
MiceConfig.sysconf.serial = malloc(17);
|
||||
if (MiceConfig.sysconf.keyid) free(MiceConfig.sysconf.keyid);
|
||||
MiceConfig.sysconf.keyid = malloc(17);
|
||||
GetSerialNumbers(MiceConfig.sysconf.serial, MiceConfig.sysconf.keyid);
|
||||
|
||||
save_current_config(true);
|
||||
}
|
||||
|
||||
if (!MiceConfig.sysconf.serial || strlen(MiceConfig.sysconf.serial) == 0) {
|
||||
if (MiceConfig.sysconf.serial) free(MiceConfig.sysconf.serial);
|
||||
MiceConfig.sysconf.serial = malloc(17);
|
||||
GetSerialNumbers(MiceConfig.sysconf.serial, NULL);
|
||||
}
|
||||
if (!MiceConfig.sysconf.keyid || strlen(MiceConfig.sysconf.keyid) == 0) {
|
||||
if (MiceConfig.sysconf.keyid) free(MiceConfig.sysconf.keyid);
|
||||
MiceConfig.sysconf.keyid = malloc(17);
|
||||
GetSerialNumbers(NULL, MiceConfig.sysconf.keyid);
|
||||
}
|
||||
|
||||
if (MiceConfig.window.dipsw) {
|
||||
@ -214,44 +311,4 @@ void load_mice_config() {
|
||||
else if (MiceConfig.window.w == 640 && MiceConfig.window.h == 480)
|
||||
MiceConfig.sysconf.dipsw |= DIPSW_RES_640x480;
|
||||
}
|
||||
|
||||
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
|
||||
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
|
||||
|
||||
char *text = MiceConfig.keys.keys;
|
||||
if (text) {
|
||||
char *copy = (char *)malloc(strlen(text) + 1);
|
||||
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
|
||||
|
||||
char *next_token;
|
||||
char *token = strtok_s(copy, ",", &next_token);
|
||||
int board = 0;
|
||||
int state = 0;
|
||||
int n = 0;
|
||||
while (token != NULL) {
|
||||
int val = atoi(token);
|
||||
if (state == 0) {
|
||||
jvsKeybindings[board].test = val;
|
||||
state = 1;
|
||||
} else if (state == 1) {
|
||||
jvsKeybindings[board].notdefault = val;
|
||||
state = 2;
|
||||
} else {
|
||||
if (state == 2) {
|
||||
jvsKeybindings[board].buttons[n] = val;
|
||||
state = 3;
|
||||
} else {
|
||||
jvsKeybindings[board].invert[n] = val;
|
||||
state = 2;
|
||||
if (n++ == JVS_BUTTON_PAIR_COUNT * 2) {
|
||||
n = 0;
|
||||
state = 0;
|
||||
if (board++ == JVS_IO_MAX) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
token = strtok_s(NULL, ",", &next_token);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,20 @@ SECTION(launcher, "These options are only used during initial bootstrapping")
|
||||
CFG_str(launcher, game_binary, "", "Override binary detection")
|
||||
CFG_bool(launcher, wait_for_debugger, false, "Wait for a debugger to attach when starting")
|
||||
CFG_int(launcher, startup_delay, 0, "Pause during startup")
|
||||
#ifdef _WIN64
|
||||
CFG_str(launcher, mice_dll, "mice64.dll", "The path to mice's DLL")
|
||||
#else
|
||||
CFG_str(launcher, mice_dll, "mice.dll", "The path to mice's DLL")
|
||||
#endif
|
||||
CFG_str(launcher, inject, "", "Extra DLLs to inject during boot")
|
||||
ENDSECTION(launcher)
|
||||
|
||||
SECTION(sysconf, "System configuration settings")
|
||||
CFG_int(sysconf, platform, 2, "System platform. 0 = RingWide, 1 = RingEdge, 2 = RingEdge2")
|
||||
CFG_int(sysconf, region, 1, "Board region. 1 = Jpn, 2 = USA, 4 = Exp, 8 = Chn")
|
||||
CFG_bool(sysconf, rental, false, "")
|
||||
CFG_str(sysconf, serial, "AASE-01A65646203", "")
|
||||
CFG_str(sysconf, serial, "A000-00000000000", "")
|
||||
CFG_str(sysconf, keyid, "A000-00000000000", "")
|
||||
CFG_hex(sysconf, dipsw, 2, 40, "DIP Switch values") // Default 40 = 1280x720
|
||||
ENDSECTION(sysconf)
|
||||
|
||||
@ -58,14 +64,15 @@ CFG_ipv4(network, subnet_mask, 255, 255, 255, 0, "")
|
||||
CFG_ipv4(network, gateway, 192, 168, 103, 254, "")
|
||||
CFG_ipv4(network, primary_dns, 192, 168, 103, 254, "")
|
||||
CFG_ipv4(network, secondary_dns, 0, 0, 0, 0, "")
|
||||
COMMENT("Emulated DNS records. Routers must be pingable!")
|
||||
CFG_ipv4(network, naominet_jp, 10, 0, 0, 2, "")
|
||||
CFG_ipv4(network, ib_naominet_jp, 10, 0, 0, 2, "")
|
||||
CFG_ipv4(network, aime_naominet_jp, 10, 0, 0, 2, "")
|
||||
CFG_ipv4(network, tenporouter_loc, 127, 0, 0, 1, "")
|
||||
CFG_ipv4(network, bbrouter_loc, 127, 0, 0, 1, "")
|
||||
CFG_ipv4(network, mobirouter_loc, 127, 0, 0, 1, "")
|
||||
CFG_ipv4(network, dslrouter_loc, 127, 0, 0, 1, "")
|
||||
CFG_ipv4(network, upstream_dns_server, 0, 0, 0, 0, "")
|
||||
COMMENT("Emulated DNS records.")
|
||||
CFG_ipv4(network, naominet_jp, 134, 65, 56, 170, "")
|
||||
CFG_ipv4(network, ib_naominet_jp, 127, 0, 0, 1, "")
|
||||
CFG_ipv4(network, aime_naominet_jp, 134, 65, 56, 170, "")
|
||||
CFG_ipv4(network, tenporouter_loc, 192, 168, 103, 254, "")
|
||||
CFG_ipv4(network, bbrouter_loc, 192, 168, 103, 254, "")
|
||||
CFG_ipv4(network, mobirouter_loc, 192, 168, 103, 254, "")
|
||||
CFG_ipv4(network, dslrouter_loc, 192, 168, 103, 254, "")
|
||||
COMMENT("Second half of system mac address. The vendor prefix D8:BB:C1: will be prepended")
|
||||
CFG_hex(network, mac, 6, 0A2F1D, "")
|
||||
ENDSECTION(network)
|
||||
@ -100,7 +107,6 @@ SECTION(keys, "Raw keybinding data. Edit this using the built in binding tool!")
|
||||
CFG_int(keys, test, 0, "")
|
||||
CFG_int(keys, service, 0, "")
|
||||
CFG_int(keys, board_count, 1, "")
|
||||
CFG_str(keys, keys, "", "")
|
||||
ENDSECTION(keys)
|
||||
|
||||
SECTION(devices, "Register attached hardware devices. COM4 is reserved for JVS.")
|
||||
@ -112,6 +118,7 @@ CFG_str(devices, com5, "", "")
|
||||
CFG_str(devices, com6, "", "")
|
||||
CFG_str(devices, com7, "", "")
|
||||
CFG_str(devices, com8, "", "")
|
||||
CFG_bool(devices, add_idlers, true, "Monitors for activity on disconnected virtual serial ports")
|
||||
ENDSECTION(devices)
|
||||
|
||||
SECTION(aime, "Aime cards used when a TN32MSEC reader is attached\nSpecify either an access code or FeliCa ID")
|
||||
|
@ -3,7 +3,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CONFIG_PATH "mice.ini"
|
||||
#define CONFIG_PATH MiceIpcRelativePath("config.ini")
|
||||
#define KEYBINDS_PATH MiceIpcRelativePath("keybinds.bin")
|
||||
|
||||
#define MICE_PLATFORM_RINGWIDE 0
|
||||
#define MICE_PLATFORM_RINGEDGE1 1 // Explictly RingEdge1, to avoid confusion
|
||||
#define MICE_PLATFORM_RINGEDGE2 2
|
||||
|
||||
typedef struct config {
|
||||
#define SECTION(s, comment) struct {
|
||||
@ -19,6 +24,6 @@ typedef struct config {
|
||||
|
||||
extern config_t MiceConfig;
|
||||
|
||||
void make_default_config();
|
||||
void save_current_config();
|
||||
void save_current_config(bool writeDefault);
|
||||
void load_mice_config();
|
||||
void load_keybind_config();
|
||||
|
@ -1,119 +1,147 @@
|
||||
#include "dmi.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
LPBYTE dmi_table = NULL;
|
||||
WORD dmi_size = 0;
|
||||
WORD _dmi_max = 0;
|
||||
|
||||
DMI_BIOS default_dmi_bios = {
|
||||
.Head.Type = DmiTypeBios,
|
||||
.Head.Length = 0x12,
|
||||
.Head.Handle = 0x0000,
|
||||
.Vendor = 0x01, // "American Megatrends Inc."
|
||||
.Version = 0x02, // "080015 "
|
||||
.StartSegment = 0x0000, // '00 f0'h
|
||||
.ReleaseDate = 0x03, // "07/28/2011"
|
||||
.ROMSize = 0x00, // 03h
|
||||
.Chars = 0x1f, // '1F 90 DA 8B'h
|
||||
.VerMajor = 0x08,
|
||||
.VerMinor = 0x0f,
|
||||
.ECVerMajor = 0xff,
|
||||
.ECVerMinor = 0xff,
|
||||
};
|
||||
|
||||
DMI_SYSTEM default_dmi_system = {
|
||||
.Head.Type = DmiTypeSystem,
|
||||
.Head.Length = 0x08,
|
||||
.Head.Handle = 0x0001,
|
||||
.Manufacturer = 0x01, // "NEC"
|
||||
.ProductName = 0x02, // "To Be Filled By O.E.M."
|
||||
.Version = 0x03, // "To Be Filled By O.E.M."
|
||||
.Serial = 0x04, // "To Be Filled By O.E.M."
|
||||
};
|
||||
|
||||
DMI_STRING default_dmi_string = {
|
||||
.Head.Type = DmiTypeString,
|
||||
.Head.Length = 0x05,
|
||||
.Head.Handle = 0x0002,
|
||||
.NoStrings = 0x00,
|
||||
};
|
||||
|
||||
static void dmi_init(void) {
|
||||
if (dmi_table) free(dmi_table);
|
||||
_dmi_max = 0xff;
|
||||
dmi_table = (LPBYTE)malloc(_dmi_max);
|
||||
memset(dmi_table, 0, _dmi_max);
|
||||
dmi_size = 0;
|
||||
}
|
||||
|
||||
static void dmi_append(void* data, WORD size) {
|
||||
if (!dmi_table) return;
|
||||
while (dmi_size + (size + 1) >= _dmi_max) {
|
||||
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
|
||||
if (!new_table) return;
|
||||
dmi_table = new_table;
|
||||
}
|
||||
memcpy(dmi_table + dmi_size, data, size);
|
||||
dmi_size += size;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
}
|
||||
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
|
||||
va_list args;
|
||||
va_start(args, num_strings);
|
||||
|
||||
dmi_append(data, size);
|
||||
dmi_size -= 2;
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
char* str = va_arg(args, char*);
|
||||
WORD len = strlen(str) & 0xffff;
|
||||
memcpy((char*)dmi_table + dmi_size, str, len + 1);
|
||||
dmi_size += len + 1;
|
||||
dmi_table[dmi_size - 1] = 0;
|
||||
}
|
||||
dmi_table[dmi_size++] = 0;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dmi_build_default() {
|
||||
dmi_init();
|
||||
// BIOS version
|
||||
dmi_append_with_strings(&default_dmi_bios, sizeof default_dmi_bios, 3,
|
||||
"American Megatrends Inc.", "080015 ", "07/28/2011");
|
||||
|
||||
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
|
||||
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4, "NEC",
|
||||
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.",
|
||||
"To Be Filled By O.E.M.");
|
||||
|
||||
default_dmi_string.NoStrings = 5;
|
||||
|
||||
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string,
|
||||
// OEM strings:
|
||||
// 0: ??
|
||||
// 1: ??
|
||||
// 2: Platform ID (AAL, AAM)
|
||||
// AAL = Nvidia drivers
|
||||
// AAM = AMD drivers
|
||||
// *** = No dedicated drivers
|
||||
// 3: ??
|
||||
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
|
||||
// If present -> makes board = 4
|
||||
// AAL = 4
|
||||
// AAM = 4
|
||||
// Supermicro = 4
|
||||
// Advantech = 4
|
||||
// These values are pulled from an 846-5004D
|
||||
5, "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2");
|
||||
}
|
||||
|
||||
BYTE dmi_calc_checksum(const char* buf, int len) {
|
||||
int sum = 0;
|
||||
int a;
|
||||
for (a = 0; a < len; a++) sum += buf[a];
|
||||
return (BYTE)(sum == 0);
|
||||
}
|
||||
#include "dmi.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
LPBYTE dmi_table = NULL;
|
||||
WORD dmi_size = 0;
|
||||
WORD _dmi_max = 0;
|
||||
|
||||
DMI_BIOS default_dmi_bios = {
|
||||
.Head.Type = DmiTypeBios,
|
||||
.Head.Length = 0x12,
|
||||
.Head.Handle = 0x0000,
|
||||
.Vendor = 0x01, // "American Megatrends Inc."
|
||||
.Version = 0x02, // "080015 "
|
||||
.StartSegment = 0x0000, // '00 f0'h
|
||||
.ReleaseDate = 0x03, // "07/28/2011"
|
||||
.ROMSize = 0x00, // 03h
|
||||
.Chars = 0x1f, // '1F 90 DA 8B'h
|
||||
.VerMajor = 0x08,
|
||||
.VerMinor = 0x0f,
|
||||
.ECVerMajor = 0xff,
|
||||
.ECVerMinor = 0xff,
|
||||
};
|
||||
|
||||
DMI_SYSTEM default_dmi_system = {
|
||||
.Head.Type = DmiTypeSystem,
|
||||
.Head.Length = 0x08,
|
||||
.Head.Handle = 0x0001,
|
||||
.Manufacturer = 0x01, // "NEC"
|
||||
.ProductName = 0x02, // "To Be Filled By O.E.M."
|
||||
.Version = 0x03, // "To Be Filled By O.E.M."
|
||||
.Serial = 0x04, // "To Be Filled By O.E.M."
|
||||
};
|
||||
|
||||
DMI_STRING default_dmi_string = {
|
||||
.Head.Type = DmiTypeString,
|
||||
.Head.Length = 0x05,
|
||||
.Head.Handle = 0x0002,
|
||||
.NoStrings = 0x00,
|
||||
};
|
||||
|
||||
static void dmi_init(void) {
|
||||
if (dmi_table) free(dmi_table);
|
||||
_dmi_max = 0xff;
|
||||
dmi_table = (LPBYTE)malloc(_dmi_max);
|
||||
memset(dmi_table, 0, _dmi_max);
|
||||
dmi_size = 0;
|
||||
}
|
||||
|
||||
static void dmi_append(void* data, WORD size) {
|
||||
if (!dmi_table) return;
|
||||
while (dmi_size + (size + 1) >= _dmi_max) {
|
||||
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
|
||||
if (!new_table) return;
|
||||
dmi_table = new_table;
|
||||
}
|
||||
memcpy(dmi_table + dmi_size, data, size);
|
||||
dmi_size += size;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
}
|
||||
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
|
||||
va_list args;
|
||||
va_start(args, num_strings);
|
||||
|
||||
dmi_append(data, size);
|
||||
dmi_size -= 2;
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
char* str = va_arg(args, char*);
|
||||
WORD len = strlen(str) & 0xffff;
|
||||
memcpy((char*)dmi_table + dmi_size, str, len + 1);
|
||||
dmi_size += len + 1;
|
||||
dmi_table[dmi_size - 1] = 0;
|
||||
}
|
||||
dmi_table[dmi_size++] = 0;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Strings are: 0, 1, Platform ID, 3, Board Type
|
||||
/**
|
||||
* | | Wide1 | Wide2 | Edge | Edge2 |
|
||||
* | ------------ | ---------- | --------- | ---- | ----- |
|
||||
* | Manufacturer | Supermicro | Advantech | NEC | NEC |
|
||||
* | Platform ID | AAM | AAM | AAL | AAL |
|
||||
* | Board Type | | | "" | AAL2 |
|
||||
*/
|
||||
|
||||
#define MANUFACTURER_RINGWIDE "Supermicro"
|
||||
#define MANUFACTURER_RINGEDGE "NEC"
|
||||
#define MANUFACTURER_RINGEDGE2 MANUFACTURER_RINGEDGE
|
||||
|
||||
#define OEM_STRINGS_RINGWIDE "DAC-BJ02", "DAC-BJ02", "AAM", "Supermicro", ""
|
||||
#define OEM_STRINGS_RINGEDGE "DAC-BJ02", "DAC-BJ02", "AAL", "NEC", ""
|
||||
#define OEM_STRINGS_RINGEDGE2 "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2"
|
||||
|
||||
void dmi_build_default() {
|
||||
dmi_init();
|
||||
// BIOS version
|
||||
dmi_append_with_strings(&default_dmi_bios, sizeof default_dmi_bios, 3,
|
||||
"American Megatrends Inc.", "080015 ", "07/28/2011");
|
||||
|
||||
switch (MiceConfig.sysconf.platform) {
|
||||
case MICE_PLATFORM_RINGWIDE: {
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
|
||||
MANUFACTURER_RINGWIDE, "To Be Filled By O.E.M.",
|
||||
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
|
||||
|
||||
default_dmi_string.NoStrings = 5;
|
||||
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
|
||||
OEM_STRINGS_RINGWIDE);
|
||||
break;
|
||||
}
|
||||
case MICE_PLATFORM_RINGEDGE1: {
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
|
||||
MANUFACTURER_RINGEDGE, "To Be Filled By O.E.M.",
|
||||
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
|
||||
|
||||
default_dmi_string.NoStrings = 5;
|
||||
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
|
||||
OEM_STRINGS_RINGEDGE);
|
||||
break;
|
||||
}
|
||||
case MICE_PLATFORM_RINGEDGE2:
|
||||
default: {
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4,
|
||||
MANUFACTURER_RINGEDGE2, "To Be Filled By O.E.M.",
|
||||
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.");
|
||||
|
||||
default_dmi_string.NoStrings = 5;
|
||||
|
||||
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string, 5,
|
||||
OEM_STRINGS_RINGEDGE2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BYTE dmi_calc_checksum(const char* buf, int len) {
|
||||
int sum = 0;
|
||||
int a;
|
||||
for (a = 0; a < len; a++) sum += buf[a];
|
||||
return (BYTE)(sum == 0);
|
||||
}
|
@ -1,64 +1,64 @@
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern LPBYTE dmi_table;
|
||||
extern WORD dmi_size;
|
||||
|
||||
enum DmiType {
|
||||
DmiTypeBios = 0,
|
||||
DmiTypeSystem = 1,
|
||||
DmiTypeString = 11,
|
||||
};
|
||||
typedef BYTE DmiType_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
DmiType_t Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
} DMI_SECTION_HEADER;
|
||||
|
||||
typedef struct {
|
||||
CHAR Signature[5];
|
||||
BYTE Checksum;
|
||||
WORD StructLength;
|
||||
DWORD StructAddr;
|
||||
WORD NumberOfStructs;
|
||||
BYTE BCDRevision;
|
||||
BYTE Reserved;
|
||||
} DMI_HEADER;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Vendor;
|
||||
BYTE Version;
|
||||
WORD StartSegment;
|
||||
BYTE ReleaseDate;
|
||||
BYTE ROMSize;
|
||||
uint64_t Chars;
|
||||
BYTE VerMajor;
|
||||
BYTE VerMinor;
|
||||
BYTE ECVerMajor;
|
||||
BYTE ECVerMinor;
|
||||
} DMI_BIOS;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Manufacturer;
|
||||
BYTE ProductName;
|
||||
BYTE Version;
|
||||
BYTE Serial;
|
||||
} DMI_SYSTEM;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE NoStrings;
|
||||
} DMI_STRING;
|
||||
#pragma pack(pop)
|
||||
|
||||
static void dmi_init(void);
|
||||
static void dmi_append(void* data, WORD size);
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
|
||||
|
||||
void dmi_build_default(void);
|
||||
BYTE dmi_calc_checksum(const char* buf, int len);
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern LPBYTE dmi_table;
|
||||
extern WORD dmi_size;
|
||||
|
||||
enum DmiType {
|
||||
DmiTypeBios = 0,
|
||||
DmiTypeSystem = 1,
|
||||
DmiTypeString = 11,
|
||||
};
|
||||
typedef BYTE DmiType_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
DmiType_t Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
} DMI_SECTION_HEADER;
|
||||
|
||||
typedef struct {
|
||||
CHAR Signature[5];
|
||||
BYTE Checksum;
|
||||
WORD StructLength;
|
||||
DWORD StructAddr;
|
||||
WORD NumberOfStructs;
|
||||
BYTE BCDRevision;
|
||||
BYTE Reserved;
|
||||
} DMI_HEADER;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Vendor;
|
||||
BYTE Version;
|
||||
WORD StartSegment;
|
||||
BYTE ReleaseDate;
|
||||
BYTE ROMSize;
|
||||
uint64_t Chars;
|
||||
BYTE VerMajor;
|
||||
BYTE VerMinor;
|
||||
BYTE ECVerMajor;
|
||||
BYTE ECVerMinor;
|
||||
} DMI_BIOS;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Manufacturer;
|
||||
BYTE ProductName;
|
||||
BYTE Version;
|
||||
BYTE Serial;
|
||||
} DMI_SYSTEM;
|
||||
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE NoStrings;
|
||||
} DMI_STRING;
|
||||
#pragma pack(pop)
|
||||
|
||||
static void dmi_init(void);
|
||||
static void dmi_append(void* data, WORD size);
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
|
||||
|
||||
void dmi_build_default(void);
|
||||
BYTE dmi_calc_checksum(const char* buf, int len);
|
@ -4,10 +4,10 @@
|
||||
|
||||
#include "log.h"
|
||||
|
||||
bool inject_debug_wait(HANDLE process) {
|
||||
bool inject_debug_wait(HANDLE process, DWORD pid) {
|
||||
BOOL present;
|
||||
|
||||
log_info(plfBoot, "Waiting for debugger to attach.");
|
||||
log_info(plfBoot, "Waiting for debugger to attach (pid=%d).", pid);
|
||||
do {
|
||||
Sleep(1000);
|
||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||
@ -35,7 +35,7 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
|
||||
|
||||
HANDLE remote_thread =
|
||||
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
||||
if (remote_thread == INVALID_HANDLE_VALUE) {
|
||||
if (remote_thread == NULL) {
|
||||
log_error(plfProcesses, "CreateRemoteThread failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
@ -106,15 +106,15 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
|
||||
flags |= CREATE_SUSPENDED;
|
||||
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
|
||||
&processInformation)) {
|
||||
log_error(plfProcesses, "CreateProcessA(%s, %s) failed: %d", path, cmdline,
|
||||
GetLastError());
|
||||
log_error(plfProcesses, "CreateProcessA(%s, %s) failed: %d", path, cmdline, GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (hJob != INVALID_HANDLE_VALUE) AssignProcessToJobObject(hJob, processInformation.hProcess);
|
||||
|
||||
if (debug_wait)
|
||||
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||
if (!inject_debug_wait(processInformation.hProcess, processInformation.dwProcessId))
|
||||
goto abort;
|
||||
if (inject != NULL)
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
|
||||
|
@ -6,4 +6,10 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
|
||||
DWORD delay, LPCSTR extra_injections, DWORD flags,
|
||||
LPPROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
#ifdef _WIN64
|
||||
#define MICELIB "mice64.dll"
|
||||
#define MICEEXE "mice64.exe"
|
||||
#else
|
||||
#define MICELIB "mice.dll"
|
||||
#define MICEEXE "mice.exe"
|
||||
#endif
|
||||
|
159
src/micetools/lib/mice/ipc.c
Normal file
159
src/micetools/lib/mice/ipc.c
Normal file
@ -0,0 +1,159 @@
|
||||
#include "ipc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../util/pid.h"
|
||||
|
||||
PMICE_IPC_DATA _miceIpcData = NULL;
|
||||
static HANDLE hMapFile = NULL;
|
||||
static HANDLE _miceIpcSendEvent = NULL;
|
||||
static HANDLE _miceIpcPopEvent = NULL;
|
||||
static HANDLE _miceIpcMutex = NULL;
|
||||
|
||||
BOOL MiceIpcGetGameId(LPSTR lpGameId) {
|
||||
if (_miceIpcData == NULL) return FALSE;
|
||||
if (!_miceIpcData->m_LauncherIsReady) return FALSE;
|
||||
memcpy(lpGameId, _miceIpcData->m_GameId, 4);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MiceIpcSetup(BOOL isOwner) {
|
||||
DWORD pid;
|
||||
if (isOwner)
|
||||
pid = GetCurrentProcessId();
|
||||
else
|
||||
pid = GetOutermostMiceId();
|
||||
|
||||
char mapName[MAX_PATH + 1];
|
||||
sprintf_s(mapName, MAX_PATH, "Local\\MiceMappingObject%d", pid);
|
||||
|
||||
SetLastError(0);
|
||||
if (isOwner)
|
||||
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||
sizeof *_miceIpcData, mapName);
|
||||
else {
|
||||
hMapFile = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, TRUE, mapName);
|
||||
}
|
||||
if (hMapFile == NULL) {
|
||||
fprintf(stderr, "Opening shared memory failed: %d\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SetLastError(0);
|
||||
_miceIpcData = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof *_miceIpcData);
|
||||
if (_miceIpcData == NULL) {
|
||||
fprintf(stderr, "Mapping view of memory failed: %d\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-Mutex%d", pid);
|
||||
_miceIpcMutex = CreateMutexA(NULL, 0, mapName);
|
||||
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-SendE%d", pid);
|
||||
_miceIpcSendEvent = CreateEventA(NULL, FALSE, FALSE, mapName);
|
||||
sprintf_s(mapName, MAX_PATH, "MiceMappingObject-PopE%d", pid);
|
||||
_miceIpcPopEvent = CreateEventA(NULL, FALSE, FALSE, mapName);
|
||||
|
||||
if (isOwner) {
|
||||
ZeroMemory(_miceIpcData, sizeof *_miceIpcData);
|
||||
} else {
|
||||
if (!_miceIpcData->m_LauncherIsReady) {
|
||||
fprintf(stderr, "IPC connected, but launcher never signalled!\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void _MiceIpcLock(void) { WaitForSingleObject(_miceIpcMutex, INFINITE); }
|
||||
void _MiceIpcUnlock(void) { ReleaseMutex(_miceIpcMutex); }
|
||||
|
||||
BOOL MiceIpcPushMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking) {
|
||||
if (!_miceIpcData->m_LauncherIsReady) return FALSE;
|
||||
_MiceIpcLock();
|
||||
|
||||
if (_miceIpcData->m_MessagesWaiting == MICE_IPC_MAX_MESSAGES) {
|
||||
if (!bBlocking) {
|
||||
_MiceIpcUnlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
_MiceIpcUnlock();
|
||||
WaitForSingleObject(_miceIpcPopEvent, INFINITE);
|
||||
_MiceIpcLock();
|
||||
} while (_miceIpcData->m_MessagesWaiting == MICE_IPC_MAX_MESSAGES);
|
||||
}
|
||||
|
||||
memcpy(&_miceIpcData->m_MessageQueue[_miceIpcData->m_MessageWriteHead], lpMessage,
|
||||
sizeof *lpMessage);
|
||||
_miceIpcData->m_MessageWriteHead++;
|
||||
if (_miceIpcData->m_MessageWriteHead == MICE_IPC_MAX_MESSAGES)
|
||||
_miceIpcData->m_MessageWriteHead = 0;
|
||||
_miceIpcData->m_MessagesWaiting++;
|
||||
|
||||
SetEvent(_miceIpcSendEvent);
|
||||
|
||||
_MiceIpcUnlock();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MiceIpcPopMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking) {
|
||||
_MiceIpcLock();
|
||||
|
||||
if (_miceIpcData->m_MessagesWaiting == 0) {
|
||||
if (!bBlocking) {
|
||||
_MiceIpcUnlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
_MiceIpcUnlock();
|
||||
WaitForSingleObject(_miceIpcSendEvent, INFINITE);
|
||||
_MiceIpcLock();
|
||||
} while (_miceIpcData->m_MessagesWaiting == 0);
|
||||
}
|
||||
|
||||
int index = _miceIpcData->m_MessageWriteHead - _miceIpcData->m_MessagesWaiting;
|
||||
if (index < 0) index += MICE_IPC_MAX_MESSAGES;
|
||||
// Impossible condition, but guard against it just in case!
|
||||
if (index < 0 || index >= MICE_IPC_MAX_MESSAGES) {
|
||||
_MiceIpcUnlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(lpMessage, &_miceIpcData->m_MessageQueue[index],
|
||||
sizeof _miceIpcData->m_MessageQueue[index]);
|
||||
_miceIpcData->m_MessagesWaiting--;
|
||||
|
||||
// Signal to any pushes waiting that the queue should have more now
|
||||
SetEvent(_miceIpcPopEvent);
|
||||
|
||||
_MiceIpcUnlock();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static CHAR _szMiceRelative[MAX_PATH + 1];
|
||||
static DWORD _szMiceRelativeN = 0xffffffff;
|
||||
LPSTR MiceIpcRelativePath(LPSTR lpChild) {
|
||||
if (_miceIpcData && _miceIpcData->m_LauncherIsReady) {
|
||||
if (_szMiceRelative[0] == '\0' || _szMiceRelativeN == 0xffffffff) {
|
||||
strcpy_s(_szMiceRelative, sizeof _szMiceRelative, _miceIpcData->m_MiceBase);
|
||||
_szMiceRelativeN = strlen(_szMiceRelative);
|
||||
|
||||
if (_szMiceRelativeN == 0) {
|
||||
strcat_s(_szMiceRelative, sizeof _szMiceRelative, "mice\\");
|
||||
_szMiceRelativeN += 5;
|
||||
} else {
|
||||
strcat_s(_szMiceRelative, sizeof _szMiceRelative, "\\mice\\");
|
||||
_szMiceRelativeN += 6;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy_s(&_szMiceRelative[_szMiceRelativeN], sizeof _szMiceRelative - _szMiceRelativeN,
|
||||
lpChild);
|
||||
} else {
|
||||
sprintf_s(_szMiceRelative, sizeof _szMiceRelative, ".\\mice\\%s", lpChild);
|
||||
}
|
||||
|
||||
return _szMiceRelative;
|
||||
}
|
40
src/micetools/lib/mice/ipc.h
Normal file
40
src/micetools/lib/mice/ipc.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define MICE_IPC_MAX_MESSAGES 160
|
||||
|
||||
typedef enum MICE_IPC_TYPE {
|
||||
MICE_IPC_TYPE_INVALID = 0,
|
||||
MICE_IPC_TYPE_LOG = 1,
|
||||
} MICE_IPC_TYPE;
|
||||
|
||||
typedef struct MICE_IPC_MESSAGE {
|
||||
MICE_IPC_TYPE m_Type;
|
||||
DWORD m_Size;
|
||||
BYTE m_Message[1024];
|
||||
} MICE_IPC_MESSAGE, *PMICE_IPC_MESSAGE;
|
||||
|
||||
typedef struct MICE_IPC_DATA {
|
||||
BOOL m_LauncherIsReady;
|
||||
char m_GameId[4];
|
||||
char m_PathPrefix[MAX_PATH + 1];
|
||||
char m_MiceBase[MAX_PATH + 1];
|
||||
char m_MiceDll[MAX_PATH + 1];
|
||||
|
||||
DWORD m_MessageWriteHead;
|
||||
DWORD m_MessagesWaiting;
|
||||
MICE_IPC_MESSAGE m_MessageQueue[MICE_IPC_MAX_MESSAGES];
|
||||
} MICE_IPC_DATA, *PMICE_IPC_DATA;
|
||||
|
||||
BOOL MiceIpcSetup(BOOL isOwner);
|
||||
BOOL MiceIpcGetGameId(LPSTR lpGameId);
|
||||
|
||||
void _MiceIpcLock(void);
|
||||
void _MiceIpcUnlock(void);
|
||||
|
||||
BOOL MiceIpcPushMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking);
|
||||
BOOL MiceIpcPopMessage(PMICE_IPC_MESSAGE lpMessage, BOOL bBlocking);
|
||||
LPSTR MiceIpcRelativePath(LPSTR lpChild);
|
||||
|
||||
extern PMICE_IPC_DATA _miceIpcData;
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "../util/pid.h"
|
||||
#include "config.h"
|
||||
#include "ipc.h"
|
||||
|
||||
#define _LF(category, name, display) \
|
||||
LOG_FACILITY lf##name = { \
|
||||
@ -70,8 +71,6 @@ void __stdcall amLogCallback(DWORD level, char* format) {
|
||||
DWORD pLogcb;
|
||||
DWORD* ppLogcb;
|
||||
|
||||
HANDLE hSlot;
|
||||
|
||||
static char log_buf[1024];
|
||||
int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list args) {
|
||||
// Early-return if we have nothing to do
|
||||
@ -92,7 +91,7 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
|
||||
|
||||
char prefix = LOG_PREFIXES[log_level];
|
||||
|
||||
int col_len = strlen(log_colours[log_level]);
|
||||
size_t col_len = strlen(log_colours[log_level]);
|
||||
|
||||
EnterCriticalSection(&logger_lock);
|
||||
int log_len = snprintf(log_buf, _countof(log_buf), "%s%s%c:%s:", log_colours[log_level],
|
||||
@ -101,11 +100,19 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
|
||||
log_len += snprintf(log_buf + log_len, _countof(log_buf) - log_len, "%s\n", COLOR_RESET);
|
||||
log_buf[_countof(log_buf) - 1] = '\0';
|
||||
|
||||
if (hSlot != INVALID_HANDLE_VALUE) {
|
||||
WriteFile(hSlot, log_buf, log_len, NULL, NULL);
|
||||
MICE_IPC_MESSAGE ipcMessage;
|
||||
ipcMessage.m_Type = MICE_IPC_TYPE_LOG;
|
||||
memcpy_s(ipcMessage.m_Message, sizeof ipcMessage.m_Message, log_buf, log_len);
|
||||
if (log_len < sizeof ipcMessage.m_Message) {
|
||||
ipcMessage.m_Message[log_len] = '\0';
|
||||
ipcMessage.m_Size = log_len;
|
||||
} else {
|
||||
// This should never happen, but there's no harm being prepared in case it does
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_buf, log_len, NULL, NULL);
|
||||
ipcMessage.m_Message[sizeof ipcMessage.m_Message - 1] = '\0';
|
||||
ipcMessage.m_Size = sizeof ipcMessage.m_Message;
|
||||
}
|
||||
|
||||
if (!MiceIpcPushMessage(&ipcMessage, TRUE)) {
|
||||
fprintf(stderr, "Failed to log: %.*s", log_len, log_buf);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
@ -172,19 +179,7 @@ int _log_game(PLOG_FACILITY facility, const char* format, ...) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setup_logging() {
|
||||
char slotName[MAX_PATH + 1];
|
||||
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", GetOutermostMiceId());
|
||||
|
||||
hSlot = CreateFile(slotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSlot == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Fatal: Failed to open mailslot %s", slotName);
|
||||
ExitProcess(2);
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&logger_lock);
|
||||
}
|
||||
void setup_logging() { InitializeCriticalSection(&logger_lock); }
|
||||
|
||||
void log_stack(PLOG_FACILITY facility) {
|
||||
char name[MAX_PATH * sizeof(TCHAR)];
|
||||
@ -195,12 +190,21 @@ void log_stack(PLOG_FACILITY facility) {
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
STACKFRAME64 stack = { 0 };
|
||||
#ifdef _WIN64
|
||||
stack.AddrPC.Offset = context.Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = context.Rsp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = context.Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#else
|
||||
stack.AddrPC.Offset = context.Eip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = context.Esp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = context.Ebp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
|
@ -43,7 +43,7 @@ void log_stack(PLOG_FACILITY facility);
|
||||
void setup_logging();
|
||||
|
||||
// Disable some logging entirely at build time for speed
|
||||
#define COMPILE_LOG_LEVEL 6
|
||||
#define COMPILE_LOG_LEVEL 5
|
||||
|
||||
#if COMPILE_LOG_LEVEL >= 6
|
||||
#define log_trace _log_trace
|
||||
|
@ -8,6 +8,7 @@ _LF(Misc, Fprintf, "fprintf")
|
||||
_LF(Misc, Fprintf_s, "fprintf_s")
|
||||
_LF(Misc, Vfprintf_s, "vfprintf_s")
|
||||
_LF(Misc, AmLog, "amLog")
|
||||
_LF(Misc, DebugLog, "DebugLog")
|
||||
|
||||
_LF(Hooks, Processes, "processes")
|
||||
_LF(Hooks, Registry, "registry")
|
||||
@ -30,6 +31,7 @@ _LF(Devices, Eeprom, "eeprom")
|
||||
_LF(Devices, MaiTouch, "maitouch")
|
||||
_LF(Devices, MaiLED, "mailed")
|
||||
_LF(Devices, Servo15069, "servo15069")
|
||||
_LF(Devices, GacchuGuts, "gacchuGuts")
|
||||
|
||||
_LF(Drivers, Columba, "columba")
|
||||
_LF(Drivers, MxJvs, "mxjvs")
|
||||
|
@ -7,15 +7,20 @@ mice_lib = static_library(
|
||||
'ringbuf.c',
|
||||
'config.c',
|
||||
'kcf.c',
|
||||
'micefs.c',
|
||||
'des.c',
|
||||
'blowfish.c',
|
||||
'solitaire.c',
|
||||
'spad.c',
|
||||
'dmi.c',
|
||||
'ipc.c',
|
||||
'serial.c',
|
||||
],
|
||||
link_with: [
|
||||
inih.get_variable('lib_inih'),
|
||||
util_lib,
|
||||
amiCrc,
|
||||
],
|
||||
include_directories: [
|
||||
openssl_inc,
|
||||
],
|
||||
)
|
||||
|
@ -8,9 +8,12 @@
|
||||
#include "config.h"
|
||||
#include "exe.h"
|
||||
#include "ioctl.h"
|
||||
#include "ipc.h"
|
||||
#include "kcf.h"
|
||||
#include "log.h"
|
||||
#include "micefs.h"
|
||||
#include "patch.h"
|
||||
#include "ringbuf.h"
|
||||
#include "version_fallback.h"
|
||||
|
||||
#define SRAM_PATH MiceIpcRelativePath("sram.bin")
|
||||
|
||||
BOOL GetSerialNumbers(LPSTR szMainId, LPSTR szKeyId);
|
||||
|
140
src/micetools/lib/mice/serial.c
Normal file
140
src/micetools/lib/mice/serial.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <stdio.h>
|
||||
#include <wbemidl.h>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
static BOOL PerformWmiQuery(LPCWCH szClass, LPCWCH szProperty, LPWCH lpResult, DWORD nResult) {
|
||||
HRESULT hres;
|
||||
IWbemLocator *pLoc = NULL;
|
||||
IWbemServices *pSvc = NULL;
|
||||
IEnumWbemClassObject *pEnumerator = NULL;
|
||||
BOOL bSuccess = FALSE;
|
||||
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hres)) return FALSE;
|
||||
|
||||
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
|
||||
if (FAILED(hres)) goto cleanup;
|
||||
|
||||
hres = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator,
|
||||
(LPVOID *)&pLoc);
|
||||
if (FAILED(hres)) goto cleanup;
|
||||
|
||||
hres =
|
||||
pLoc->lpVtbl->ConnectServer(pLoc, L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &pSvc);
|
||||
|
||||
if (FAILED(hres)) goto cleanup;
|
||||
|
||||
hres = CoSetProxyBlanket((IUnknown *)pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
|
||||
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
if (FAILED(hres)) goto cleanup;
|
||||
|
||||
WCHAR szQuery[128];
|
||||
swprintf_s(szQuery, _countof(szQuery), L"SELECT * FROM %ls", szClass);
|
||||
|
||||
hres = pSvc->lpVtbl->ExecQuery(pSvc, L"WQL", szQuery,
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL,
|
||||
&pEnumerator);
|
||||
if (FAILED(hres)) goto cleanup;
|
||||
|
||||
IWbemClassObject *pclsObj = NULL;
|
||||
ULONG uReturn = 0;
|
||||
while (pEnumerator) {
|
||||
HRESULT hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
|
||||
if (!uReturn) break;
|
||||
|
||||
VARIANT vtProp;
|
||||
hr = pclsObj->lpVtbl->Get(pclsObj, szProperty, 0, &vtProp, 0, 0);
|
||||
|
||||
if (SUCCEEDED(hr) && vtProp.vt != VT_NULL) {
|
||||
wcscpy_s(lpResult, nResult, vtProp.bstrVal);
|
||||
bSuccess = TRUE;
|
||||
}
|
||||
|
||||
VariantClear(&vtProp);
|
||||
pclsObj->lpVtbl->Release(pclsObj);
|
||||
}
|
||||
|
||||
pEnumerator->lpVtbl->Release(pEnumerator);
|
||||
|
||||
cleanup:
|
||||
if (pSvc) pSvc->lpVtbl->Release(pSvc);
|
||||
if (pLoc) pLoc->lpVtbl->Release(pLoc);
|
||||
CoUninitialize();
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
inline static void alphaNum(CHAR *lpAddr, BYTE val) {
|
||||
val %= 26 + 10;
|
||||
if (val < 10)
|
||||
lpAddr[0] = '0' + val;
|
||||
else
|
||||
lpAddr[0] = 'A' + (val - 10);
|
||||
}
|
||||
inline static void numeric(CHAR *lpAddr, BYTE val) {
|
||||
val %= 100;
|
||||
lpAddr[0] = '0' + (val / 10);
|
||||
lpAddr[1] = '0' + (val % 10);
|
||||
}
|
||||
|
||||
extern BOOL g_bIsInDllMain;
|
||||
BOOL GetSerialNumbers(LPSTR szMainId, LPSTR szKeyId) {
|
||||
// Making WMI queries from within DllMain is not happening. Ever. :D
|
||||
if (g_bIsInDllMain) return FALSE;
|
||||
|
||||
WCHAR szMbSerial[128];
|
||||
if (!PerformWmiQuery(L"Win32_BaseBoard", L"SerialNumber", szMbSerial, _countof(szMbSerial)))
|
||||
return FALSE;
|
||||
szMbSerial[127] = L'\0';
|
||||
WCHAR szCpuId[128];
|
||||
if (!PerformWmiQuery(L"Win32_Processor", L"ProcessorId", szCpuId, _countof(szCpuId)))
|
||||
return FALSE;
|
||||
szCpuId[127] = L'\0';
|
||||
|
||||
BYTE sumOut[20];
|
||||
unsigned int outlen;
|
||||
|
||||
EVP_MD_CTX *ctx;
|
||||
ctx = EVP_MD_CTX_create();
|
||||
EVP_DigestInit(ctx, EVP_sha1());
|
||||
EVP_DigestUpdate(ctx, szMbSerial, wcslen(szMbSerial));
|
||||
EVP_DigestUpdate(ctx, szCpuId, wcslen(szCpuId));
|
||||
EVP_DigestFinal_ex(ctx, sumOut, &outlen);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
if (szMainId) {
|
||||
szMainId[0] = 'M';
|
||||
alphaNum(&szMainId[1], sumOut[0]);
|
||||
alphaNum(&szMainId[2], sumOut[1]);
|
||||
alphaNum(&szMainId[3], sumOut[2]);
|
||||
szMainId[4] = '-';
|
||||
alphaNum(&szMainId[5], sumOut[3]);
|
||||
alphaNum(&szMainId[6], sumOut[4]);
|
||||
alphaNum(&szMainId[7], sumOut[5]);
|
||||
numeric(&szMainId[8], sumOut[6]);
|
||||
numeric(&szMainId[10], sumOut[7]);
|
||||
numeric(&szMainId[12], sumOut[8]);
|
||||
numeric(&szMainId[14], sumOut[9]);
|
||||
szMainId[16] = '\0';
|
||||
}
|
||||
|
||||
if (szKeyId) {
|
||||
szKeyId[0] = 'M';
|
||||
alphaNum(&szKeyId[1], sumOut[10]);
|
||||
alphaNum(&szKeyId[2], sumOut[11]);
|
||||
alphaNum(&szKeyId[3], sumOut[12]);
|
||||
szKeyId[4] = '-';
|
||||
alphaNum(&szKeyId[5], sumOut[13]);
|
||||
alphaNum(&szKeyId[6], sumOut[14]);
|
||||
alphaNum(&szKeyId[7], sumOut[15]);
|
||||
numeric(&szKeyId[8], sumOut[16]);
|
||||
numeric(&szKeyId[10], sumOut[17]);
|
||||
numeric(&szKeyId[12], sumOut[18]);
|
||||
numeric(&szKeyId[14], sumOut[19]);
|
||||
szKeyId[16] = '\0';
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#ifndef MICE_VERSION
|
||||
#define MICE_VERSION "0.0-pre"
|
||||
#endif
|
@ -152,7 +152,7 @@ BOOL mxkFlashRead(unsigned int address, unsigned int nbytes, unsigned char* buff
|
||||
mxkPacketReqFlashRead(packet, address, nbytes);
|
||||
if (!mxkSendPacket(packet)) return FALSE;
|
||||
|
||||
for (size_t i = 0; i < nbytes; i += 0x100) {
|
||||
for (unsigned int i = 0; i < nbytes; i += 0x100) {
|
||||
unsigned int rest = (nbytes - i) > 0x100 ? 0x100 : (nbytes - i);
|
||||
if (!mxkTransportRecv(buffer + i, rest)) return FALSE;
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ void mxkSignValue(unsigned int value, unsigned char* signature) {
|
||||
mxkSign(&hash_data, sizeof hash_data, signature);
|
||||
}
|
||||
|
||||
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer,
|
||||
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, unsigned int* nbuffer,
|
||||
unsigned char* buffer, size_t nin) {
|
||||
if (key == NULL || buffer == NULL || md == NULL || nbuffer == NULL) {
|
||||
amiDebugLog("Error: Invalid param.");
|
||||
|
@ -21,7 +21,7 @@ void mxkSwapKeys();
|
||||
|
||||
MXK_STATUS mxkCryptInit(void);
|
||||
|
||||
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer,
|
||||
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, unsigned int* nbuffer,
|
||||
unsigned char* buffer, size_t nin);
|
||||
void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, PSha1Sum_t sum);
|
||||
|
||||
|
@ -195,7 +195,7 @@ int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t no
|
||||
unsigned char data_in[sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce];
|
||||
|
||||
size_t count = sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce;
|
||||
size_t nout = HMAC_SUM_SIZE;
|
||||
unsigned int nout = HMAC_SUM_SIZE;
|
||||
mxkN2UtilCatenateData(data_in, &count, 3, packetSha, sizeof *packetSha, hmacSalt,
|
||||
sizeof *hmacSalt, nonce, sizeof *nonce);
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <shlwapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "../mice/exe.h"
|
||||
|
||||
#pragma comment(lib, "psapi.lib")
|
||||
|
||||
DWORD GetParentProcessIdFor(DWORD pid) {
|
||||
@ -30,12 +32,14 @@ DWORD GetOutermostMiceId(void) {
|
||||
CHAR baseName[MAX_PATH + 1];
|
||||
if (GetModuleFileNameEx(hProcess, NULL, baseName, sizeof baseName)) {
|
||||
// TODO: Better
|
||||
if (strcmp(PathFindFileNameA(baseName), "mice.exe") == 0) return pid;
|
||||
if (stricmp(PathFindFileNameA(baseName), MICEEXE) == 0)
|
||||
return pid;
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
pid = GetParentProcessIdFor(pid);
|
||||
} while (pid != (DWORD)-1);
|
||||
fprintf(stderr, "Likely fatal: Failed to identify parent mouse!");
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
@ -87,6 +87,6 @@ void mxkPcpAbSeed(pcpa_t* stream, void* data) {
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
|
||||
char sSize[16];
|
||||
sprintf_s(sSize, sizeof sSize, "%d", sizeof mxkKcfConfig.m_Seed);
|
||||
sprintf_s(sSize, sizeof sSize, "%zd", sizeof mxkKcfConfig.m_Seed);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user