#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 inline void handleOneButton(int iW, int iH, int iX, int iY) { float x = (float)iX / (float)(iW); float y = (float)iY / (float)(iH); // If the window is square, assume `1P_ONLY` is set WORD button; if (iW == iH) { 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; } } 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 (!mainWindow) 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; if (GetAsyncKeyState(VK_LBUTTON)) { POINT pCursor; GetCursorPos(&pCursor); if (ScreenToClient(mainWindow, &pCursor)) { handleOneButton(w, h, pCursor.x, pCursor.y); } } MICE_DA_ITER(g_activeTouches, ACTIVE_TOUCH, i) { handleOneButton(w, h, i->m_X, i->m_Y); } MICE_DA_ITER_END // for (DWORD i = 0; i < nActiveTouches; i++) { // handleOneButton(w, h, activeTouches[i].m_X, activeTouches[i].m_Y); // } } 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(2); 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 // ( <> <> ) 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]); // { t h } log_misc(plfMaiTouch, "th-command recieved: %d", sensor); // Sensor == '@': failed // ( <> ) 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); }