import { parentPort } from "worker_threads"; import ffi from "@inigolabs/ffi-napi"; import { createBarcodeHandler } from "../utils/barcodeHandler"; import { getWindowData, findWindow, getWindowRect, } from "../utils/winapi/getWindowData"; import getPixelColor from "../utils/winapi/getPixelColor"; import { BOOL, DWORD, UINT } from "../utils/winapi/types"; const isDev = process.env.NODE_ENV === "development"; const kChangeDelayEvent = "change-delay"; const user32 = ffi.Library("user32", { GetForegroundWindow: ["int", []], AllowSetForegroundWindow: [BOOL, [DWORD]], LockSetForegroundWindow: [BOOL, [UINT]], }); let isHandler; let delay; let intervalKhm; let timeoutMao; let dpi = 1; const maoWin = "MAO_Client.exe"; const khmWinTitle = "WinKHM ©2010 OPTOSOFT"; const colorGreen = 10_747_542; // in hex a3fe96; const colorGreen2 = 9_895_830; // in hex 0x96ff96; const colorGray = 9_868_950; // in hex 0x969696 const colorRed = 255; // in hex 0xff, for testing in dev // ============================ const activateMao = () => { parentPort.postMessage({ event: "winactivate", data: "MAO_Client.exe", }); }; const activateKhm = () => { if (!intervalKhm) { let isKhmOk = false; findWindow({ name: khmWinTitle }, (data) => { const { hwnd } = data; // winActivate(hwnd); parentPort.postMessage({ event: "winactivate", data: "WinKHM.exe", }); intervalKhm = setInterval(() => { const rect = getWindowRect(hwnd); const x = Math.floor((rect.right - rect.left) / 2 / dpi); const y = Math.floor(((rect.bottom - rect.top) * 0.82) / dpi); const color = getPixelColor(hwnd, x, y); if ( (color === colorGreen || color === colorGreen2 || (isDev && color === colorRed)) && !isKhmOk ) { isKhmOk = true; } if (color === colorGray && isKhmOk) { isKhmOk = false; clearInterval(intervalKhm); intervalKhm = null; setTimeout(() => { activateMao(); }, 1000); } }, 1000); }); } }; const isBoardBarcode = (barcode) => { const pattern = /^\w\d{3,4}$/; // Board num patter: B123 or B1234 const re = new RegExp(pattern, "i"); return !!barcode.match(re); }; const barcodeProcessor = (barcode) => { const foregroundHwnd = user32.GetForegroundWindow(); const { path } = getWindowData(foregroundHwnd); const isMao = path.includes(maoWin); if (isMao && isBoardBarcode(barcode)) { parentPort.postMessage({ event: "activateKhm", data: delay, }); timeoutMao = setTimeout( () => { clearInterval(intervalKhm); intervalKhm = null; activateKhm(); }, delay ? delay * 1000 : 200 ); } }; const barcodeHandler = createBarcodeHandler(barcodeProcessor, 100); parentPort.on("message", ({ event, payload }) => { switch (event) { case kChangeDelayEvent: delay = parseInt(payload, 10); if (Number.isNaN(delay)) { parentPort.postMessage({ event: "remove-listener", }); isHandler = false; } else if (!isHandler) { parentPort.postMessage({ event: "add-listener", }); isHandler = true; } clearTimeout(timeoutMao); clearInterval(intervalKhm); intervalKhm = null; break; case "set-dpi": dpi = payload; break; case "key-down": { const { char } = payload.data; barcodeHandler(char); break; } default: break; } });