micetools/src/micetools/dll/devices/ser_maitouch.c

184 lines
5.7 KiB
C

#include "../hooks/gui.h"
#include "_devices.h"
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) {
for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) {
if (TOUCH_ID_LUT[i] == id) return i;
}
return 0xff;
}
// 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)) {
populateActiveResponse();
comdev_write(dev, g_ActiveResponse, 14);
Sleep(5); // 200Hz should be plenty
continue;
}
BYTE startWait;
do {
comdev_read_blocking(dev, &startWait, 1);
} while (startWait != '{');
BYTE command[5];
comdev_read_blocking(dev, command, 5);
BYTE response[6];
memcpy(response, "( )", 6);
if (memcmp(command, "HALT}", 5) == 0) {
if (touch_is_enabled)
log_info(plfMaiTouch, "Touchscreen left active mode");
else
log_misc(plfMaiTouch, "Touchscreen not in active mode");
touch_is_enabled = false;
} else if (memcmp(command, "STAT}", 5) == 0) {
if (!touch_is_enabled)
log_info(plfMaiTouch, "Touchscreen entered active mode");
else
log_misc(plfMaiTouch, "Touchscreen already in active mode");
touch_is_enabled = true;
} else if (command[2] == 'k' && command[4] == '}') {
BYTE sensor = get_touch_id(command[1]);
log_misc(plfMaiTouch, "k-command recieved: %d >=%d", sensor, command[3]);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <> )
response[1] = command[0];
response[2] = command[1];
thresh = command[3];
comdev_write(dev, response, 6);
} else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') {
BYTE sensor = get_touch_id(command[1]);
// { <L/R> <sensor> t h }
log_misc(plfMaiTouch, "th-command recieved: %d", sensor);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <threshold> )
response[1] = command[0]; // 'L' or 'R'
response[2] = command[1]; // Sensor
response[4] = thresh;
comdev_write(dev, response, 6);
} else {
log_error(plfMaiTouch, "Unhandled: {%.*s", 5, command);
}
}
}
void install_touch_bd() { register_device("maitouch", touch_bd_thread); }