159 lines
4.8 KiB
C++
159 lines
4.8 KiB
C++
|
#include "gunio.h"
|
||
|
#include "util/logging.h"
|
||
|
|
||
|
bool games::mga::SpiceGearGunHandle::open(LPCWSTR lpFileName) {
|
||
|
if (wcscmp(lpFileName, L"COM1") != 0) {
|
||
|
return false;
|
||
|
}
|
||
|
log_info("metalgear", "Opened gun device on COM1");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int games::mga::SpiceGearGunHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
|
||
|
|
||
|
// minimum buffer size
|
||
|
if ((command == 0u) || nNumberOfBytesToRead < 2)
|
||
|
return 0;
|
||
|
|
||
|
// execute command
|
||
|
int bytes_read = 0;
|
||
|
switch (command) {
|
||
|
case 0x04: // get version
|
||
|
|
||
|
// write version
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = version;
|
||
|
|
||
|
break;
|
||
|
case 0x08: // get input state
|
||
|
{
|
||
|
// check buffer size
|
||
|
if (nNumberOfBytesToRead < 12)
|
||
|
return 0;
|
||
|
|
||
|
// get cursor position
|
||
|
POINT cursor_pos{};
|
||
|
GetCursorPos(&cursor_pos);
|
||
|
|
||
|
// get screen size
|
||
|
RECT screen_size{};
|
||
|
GetWindowRect(GetDesktopWindow(), &screen_size);
|
||
|
auto screen_width = (unsigned short) (screen_size.right - screen_size.left);
|
||
|
auto screen_height = (unsigned short) (screen_size.bottom - screen_size.top);
|
||
|
|
||
|
// calculate cursor position
|
||
|
p1_x = (unsigned short) (((cursor_pos.x * 1024) / screen_width) % 1024);
|
||
|
p1_y = (unsigned short) (1024 - (((cursor_pos.y * 1024) / screen_height) % 1024));
|
||
|
|
||
|
// gun P1
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_x);
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_x);
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_y);
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_y);
|
||
|
bytes_read += 3;
|
||
|
|
||
|
// fill buffer
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case 0x0C: // not called in game - empty
|
||
|
|
||
|
// empty data
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
|
||
|
break;
|
||
|
case 0x10: // get DIP switches
|
||
|
|
||
|
// clear bits
|
||
|
*((unsigned char *) lpBuffer + bytes_read) = 0x00;
|
||
|
|
||
|
// set bits
|
||
|
if (frequency == 1)
|
||
|
*((unsigned char *) lpBuffer + bytes_read) |= 0x80;
|
||
|
if (frequency == 2)
|
||
|
*((unsigned char *) lpBuffer + bytes_read) |= 0x40;
|
||
|
if (frequency == 3)
|
||
|
*((unsigned char *) lpBuffer + bytes_read) |= 0x20;
|
||
|
if (frequency == 4)
|
||
|
*((unsigned char *) lpBuffer + bytes_read) |= 0x10;
|
||
|
|
||
|
break;
|
||
|
case 0x14: // frequency 1
|
||
|
|
||
|
// set frequency and return empty data
|
||
|
frequency = 1;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
|
||
|
break;
|
||
|
case 0x18: // frequency 2
|
||
|
|
||
|
// set frequency and return empty data
|
||
|
frequency = 2;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
|
||
|
break;
|
||
|
case 0x19: // frequency 3
|
||
|
|
||
|
// set frequency and return empty data
|
||
|
frequency = 3;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
|
||
|
break;
|
||
|
case 0x1A: // frequency 4
|
||
|
|
||
|
// set frequency and return empty data
|
||
|
frequency = 4;
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
|
||
|
|
||
|
break;
|
||
|
case 0x1C: // led board check
|
||
|
|
||
|
// check buffer size
|
||
|
if (nNumberOfBytesToRead < 11)
|
||
|
return 0;
|
||
|
|
||
|
// set all bits
|
||
|
memset(lpBuffer, 0xFF, 10);
|
||
|
bytes_read += 10;
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
log_warning("metalgear", "unknown opcode: 0x{:02X}", command);
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = 0x01;
|
||
|
}
|
||
|
|
||
|
// reset command
|
||
|
command = 0;
|
||
|
|
||
|
// calculate checksum
|
||
|
unsigned char checksum = 0xFF;
|
||
|
for (int i = 0; i < bytes_read; i++)
|
||
|
checksum -= *((unsigned char *) lpBuffer + i);
|
||
|
*((unsigned char *) lpBuffer + bytes_read++) = checksum;
|
||
|
|
||
|
// return amount of bytes read
|
||
|
return bytes_read;
|
||
|
}
|
||
|
|
||
|
int games::mga::SpiceGearGunHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
|
||
|
|
||
|
// save command
|
||
|
if (nNumberOfBytesToWrite > 0)
|
||
|
command = *((unsigned char *) lpBuffer);
|
||
|
|
||
|
return (int) nNumberOfBytesToWrite;
|
||
|
}
|
||
|
|
||
|
int games::mga::SpiceGearGunHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||
|
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
bool games::mga::SpiceGearGunHandle::close() {
|
||
|
log_info("metalgear", "Closed gun device on COM1");
|
||
|
return true;
|
||
|
}
|