UNPKG

node-native-win-utils

Version:

Native addon for Node.js providing utility operations on Windows systems

266 lines (265 loc) 10.5 kB
import { createRequire as _createRequire } from "module"; const __require = _createRequire(import.meta.url); import EventEmitter from 'events'; import path from "path"; import fs from "fs"; // @ts-ignore const nodeGypBuild = __require("node-gyp-build"); import { keyCodes, KeyCodeHelper } from "./keyCodes.mjs"; import { __dirnameLocal } from "./dirnameLocal.mjs"; const bindings = nodeGypBuild(path.resolve(__dirnameLocal, "..")); const { setKeyDownCallback, setKeyUpCallback, unsetKeyDownCallback, unsetKeyUpCallback, getWindowData, captureWindowN, captureScreenAsync, mouseMove, mouseClick, mouseDrag, typeString, pressKey, imread, imwrite, matchTemplate, blur, bgrToGray, drawRectangle, getRegion, textRecognition, equalizeHist, darkenColor, bringWindowToFront, startMouseListener, stopMouseListener } = bindings; const rawPressKey = pressKey; /** * Captures a window and saves it to a file. * @param windowName - The name of the window to capture. * @param path - The file path to save the captured image. * @returns True if the capture and save operation is successful, otherwise false. */ function captureWindow(windowName, path) { const buffer = captureWindowN(windowName); if (!buffer) return false; fs.writeFileSync(path, new Uint8Array(buffer)); return true; } /** * Captures a screen and saves it to a file. * @param path - The file path to save the captured image. * @returns True if the capture and save operation is successful, otherwise false. */ function captureScreenToFile(path) { return new Promise((resolve, reject) => { captureScreenAsync().then((buffer) => { fs.writeFileSync(path, new Uint8Array(buffer)); resolve(true); }).catch((err => { reject(err); })); }); } /** * Class that implements a private keyboard listener. * This class leverages native C++ bindings to hook into system keyboard events. * The C++ layer uses global ThreadSafeFunction objects to safely dispatch events * (using a dedicated monitoring thread, mutexes, and atomic flags) to JavaScript. * @extends EventEmitter */ class KeyboardListenerPrivate extends EventEmitter { /** * Constructs the keyboard listener and sets up native callbacks. * The callbacks (set via setKeyDownCallback and setKeyUpCallback) are defined in the * C++ binding layer. They are responsible for invoking these JavaScript callbacks * in a thread-safe manner once a key event is detected. */ constructor() { super(); // Set the callback for key down events. setKeyDownCallback((keyCode) => { // Look up the human-readable key name from a mapping. const keyName = keyCodes.get(keyCode.toString()); // Emit the 'keyDown' event to all registered JavaScript listeners. this.emit("keyDown", { keyCode, keyName, }); }); // Set the callback for key up events. setKeyUpCallback((keyCode) => { // Look up the human-readable key name from a mapping. const keyName = keyCodes.get(keyCode.toString()); // Emit the 'keyUp' event to all registered JavaScript listeners. this.emit("keyUp", { keyCode, keyName, }); }); } } /** * A singleton manager for the KeyboardListenerPrivate instance. * This class ensures that only one native keyboard listener is active at any time. * When the listener is destroyed, it calls unsetKeyDownCallback and unsetKeyUpCallback * to clean up native resources, mirroring the cleanup logic in the C++ bindings. */ class KeyboardListener { /** * Holds the singleton instance of KeyboardListenerPrivate. */ static listenerInstance = null; /** * Returns the singleton instance of KeyboardListenerPrivate. If not already created, * it instantiates a new instance and sets up the native callbacks. * @returns The active KeyboardListenerPrivate instance. */ static listener() { if (!this.listenerInstance) { this.listenerInstance = new KeyboardListenerPrivate(); } return this.listenerInstance; } /** * Destroys the current KeyboardListenerPrivate instance and cleans up native callbacks. * This method calls unsetKeyDownCallback and unsetKeyUpCallback to release any * native resources (such as the global ThreadSafeFunctions) and stops the monitoring thread. */ static destroy() { this.listenerInstance = null; unsetKeyDownCallback(); unsetKeyUpCallback(); } } export var TemplateMatchModes; (function (TemplateMatchModes) { TemplateMatchModes[TemplateMatchModes["TM_SQDIFF"] = 0] = "TM_SQDIFF"; TemplateMatchModes[TemplateMatchModes["TM_SQDIFF_NORMED"] = 1] = "TM_SQDIFF_NORMED"; TemplateMatchModes[TemplateMatchModes["TM_CCORR"] = 2] = "TM_CCORR"; TemplateMatchModes[TemplateMatchModes["TM_CCORR_NORMED"] = 3] = "TM_CCORR_NORMED"; TemplateMatchModes[TemplateMatchModes["TM_CCOEFF"] = 4] = "TM_CCOEFF"; TemplateMatchModes[TemplateMatchModes["TM_CCOEFF_NORMED"] = 5] = "TM_CCOEFF_NORMED"; /*!< \f[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }\f] */ })(TemplateMatchModes || (TemplateMatchModes = {})); ; /** * Represents the OpenCV class that provides image processing functionality. */ class OpenCV { imageData; /** * Represents the OpenCV class that provides image processing functionality. */ constructor(image) { if (typeof image === "string") { this.imageData = imread(image); } else { this.imageData = image; } } /** * The width of the image. */ get width() { return this.imageData.width; } /** * The height of the image. */ get height() { return this.imageData.height; } /** * Matches a template image within the current image. * @param template - The template image data to search for. * @param method - The template matching method (optional). * @param mask - The optional mask image data to apply the operation (optional). * @returns The result of the template matching operation. */ matchTemplate(template, method, mask) { if (typeof method !== "number") method = TemplateMatchModes.TM_CCOEFF_NORMED; return matchTemplate(this.imageData, template, method, mask); } /** * Applies a blur filter to the image. * @param sizeX - The horizontal size of the blur filter. * @param sizeY - The vertical size of the blur filter. * @returns A new OpenCV instance with the blurred image data. */ blur(sizeX, sizeY) { return new OpenCV(blur(this.imageData, sizeX, sizeY)); } /** * Converts the image from BGR to grayscale. * @returns A new OpenCV instance with the grayscale image data. */ bgrToGray() { return new OpenCV(bgrToGray(this.imageData)); } /** * Equalize the Histogram by using the OpenCV function cv::equalizeHist. * @returns A new OpenCV instance with the equalized image data. */ equalizeHist() { return new OpenCV(equalizeHist(this.imageData)); } rgbToHsv(rgb) { const r_norm = rgb[0] / 255; const g_norm = rgb[1] / 255; const b_norm = rgb[2] / 255; const Cmax = Math.max(r_norm, g_norm, b_norm); const Cmin = Math.min(r_norm, g_norm, b_norm); const delta = Cmax - Cmin; let Hue = 0; if (delta !== 0) { switch (Cmax) { case r_norm: Hue = 60 * (((g_norm - b_norm) / delta) % 6); break; case g_norm: Hue = 60 * (((b_norm - r_norm) / delta) + 2); break; case b_norm: Hue = 60 * (((r_norm - g_norm) / delta) + 4); break; } } let Saturation = 0.0 * 100; if (Cmax !== 0) Saturation = (delta / Cmax) * 100; let Value = Cmax * 100; return [ [Hue, Saturation, Value] ]; } darkenColor(lowerBound, upperBound, darkenFactor) { return new OpenCV(darkenColor(this.imageData, lowerBound, upperBound, darkenFactor)); } /** * Draws a rectangle on the image. * @param start - The starting point of the rectangle. * @param end - The ending point of the rectangle. * @param rgb - The color (RGB) of the rectangle. * @param thickness - The thickness of the rectangle's border. * @returns A new OpenCV instance with the image containing the drawn rectangle. */ drawRectangle(start, end, rgb, thickness) { return new OpenCV(drawRectangle(this.imageData, start, end, rgb, thickness)); } /** * Extracts a region of interest (ROI) from the image. * @param region - The region of interest defined as [x, y, width, height]. * @returns A new OpenCV instance with the extracted region of interest. */ getRegion(region) { return new OpenCV(getRegion(this.imageData, region)); } /** * Writes the image data to a file. * @param path - The file path to save the image. */ imwrite(path) { const buffer = imwrite(this.imageData); if (!buffer) return; fs.writeFileSync(path, new Uint8Array(buffer)); } } function keyPress(keyCode, repeat) { return new Promise((resolve, reject) => { if (!repeat) { let result = rawPressKey(keyCode); if (!result) reject('Something went wrong'); return resolve(true); } for (let i = 0; i <= repeat; i++) { let result = rawPressKey(keyCode); if (!result) reject('Something went wrong'); } return resolve(true); }); } export { getWindowData, bringWindowToFront, captureWindow, captureWindowN, mouseMove, mouseClick, mouseDrag, typeString, keyPress, rawPressKey, KeyCodeHelper, textRecognition, captureScreenToFile, captureScreenAsync, startMouseListener, stopMouseListener, KeyboardListener, OpenCV };