UNPKG

selection-hook

Version:

Text selection monitoring of native Node.js module with N-API across applications

394 lines (357 loc) 12.7 kB
/** * Node Selection Hook * * This module provides a Node.js interface for monitoring text selections * across applications on Windows using UI Automation and Accessibility APIs. */ import { EventEmitter } from "events"; /** * Text selection data returned by the native module * * Contains the selected text and its position information. * Position coordinates are in screen coordinates (pixels). */ export interface TextSelectionData { /** The selected text content */ text: string; /** The program name that triggered the selection */ programName: string; /** First paragraph's left-top point (x, y) in pixels */ startTop: { x: number; y: number }; /** First paragraph's left-bottom point (x, y) in pixels */ startBottom: { x: number; y: number }; /** Last paragraph's right-top point (x, y) in pixels */ endTop: { x: number; y: number }; /** Last paragraph's right-bottom point (x, y) in pixels */ endBottom: { x: number; y: number }; /** Current mouse position (x, y) in pixels */ mousePosStart: { x: number; y: number }; /** Mouse down position (x, y) in pixels */ mousePosEnd: { x: number; y: number }; /** Selection method identifier */ method: (typeof SelectionHook.SelectionMethod)[keyof typeof SelectionHook.SelectionMethod]; /** Position level identifier */ posLevel: (typeof SelectionHook.PositionLevel)[keyof typeof SelectionHook.PositionLevel]; /** Whether the current app's front window is in fullscreen mode, macOS only */ isFullscreen?: boolean; } /** * Mouse event data structure * * Contains information about mouse events such as clicks and movements. * Coordinates are in screen coordinates (pixels). */ export interface MouseEventData { /** X coordinate of mouse pointer (px) */ x: number; /** Y coordinate of mouse pointer (px) */ y: number; /** Mouse button identifier, * same as WebAPIs' MouseEvent.button * Left = 0, Middle = 1, Right = 2, Back = 3, Forward = 4, * Unknown = -1 */ button: number; } /** * Mouse wheel event data structure * * Contains information about mouse wheel events. */ export interface MouseWheelEventData { /** Mouse wheel button type * 0: Vertical * 1: Horizontal */ button: number; /** Mouse wheel direction flag * 1: Up/Right * -1: Down/Left */ flag: number; } /** * Keyboard event data structure * * Contains information about keyboard events such as key presses and releases. */ export interface KeyboardEventData { /** * Unified key value of the vkCode. Same as MDN `KeyboardEvent.key` values. * Converted from platform-specific vkCode. * * Values defined in https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values */ uniKey: string; /** Virtual key code. The value is different on different platforms. * * Windows: VK_* values of vkCode, refer to https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes * macOS: kVK_* values of kCGKeyboardEventKeycode, defined in `HIToolbox/Events.h` */ vkCode: number; /** Whether modifier keys (Alt/Ctrl/Win/⌘/⌥/Fn) are pressed simultaneously */ sys: boolean; /** Keyboard scan code. Windows Only. */ scanCode?: number; /** Additional key flags. Varies on different platforms. */ flags: number; /** Internal event type identifier */ type?: string; /** Specific keyboard action (e.g., "key-down", "key-up") */ action?: string; } /** * Configuration interface for text selection monitoring * * Contains settings that control the behavior of the text selection hook * and its various features like mouse tracking and clipboard fallback. */ export interface SelectionConfig { /** Enable debug logging for warnings and errors */ debug?: boolean; /** Enable high CPU usage mouse movement tracking */ enableMouseMoveEvent?: boolean; /** Enable clipboard fallback for text selection */ enableClipboard?: boolean; /** Enable passive mode where selection requires manual trigger */ selectionPassiveMode?: boolean; /** Mode for clipboard fallback behavior */ clipboardMode?: (typeof SelectionHook.FilterMode)[keyof typeof SelectionHook.FilterMode]; /** List of program names for clipboard mode filtering */ programList?: string[]; } /** * SelectionHook - Main class for text selection monitoring * * This class provides methods to start/stop monitoring text selections * across applications on Windows and emits events when selections occur. */ declare class SelectionHook extends EventEmitter { static SelectionMethod: { NONE: 0; UIA: 1; FOCUSCTL: 2; ACCESSIBLE: 3; AXAPI: 11; CLIPBOARD: 99; }; static PositionLevel: { NONE: 0; MOUSE_SINGLE: 1; MOUSE_DUAL: 2; SEL_FULL: 3; SEL_DETAILED: 4; }; static FilterMode: { DEFAULT: 0; INCLUDE_LIST: 1; EXCLUDE_LIST: 2; }; static FineTunedListType: { EXCLUDE_CLIPBOARD_CURSOR_DETECT: 0; INCLUDE_CLIPBOARD_DELAY_READ: 1; }; /** * Start monitoring text selections * * Initiates the native hooks to listen for text selection events * across all applications. This must be called before any events * will be emitted. * * @param debug Enable console debug logging (warnings and errors) * @returns Success status (true if started successfully) */ start(config?: SelectionConfig | null): boolean; /** * Stop monitoring text selections * * Stops the native hooks and prevents further events from being emitted. * This should be called when monitoring is no longer needed to free resources. * * @returns Success status (true if stopped successfully or wasn't running) */ stop(): boolean; /** * Check if hook is running * * Determines if the selection monitoring is currently active. * * @returns Running status (true if monitoring is active) */ isRunning(): boolean; /** * Get current text selection * * Retrieves the current text selection, if any exists. * Returns null if no text is currently selected or hook isn't running. * * @returns Current selection data or null if no selection exists */ getCurrentSelection(): TextSelectionData | null; /** * Enable mousemove events (high CPU usage) * * Enables "mouse-move" events to be emitted when the mouse moves. * Note: This can cause high CPU usage due to frequent event firing. * * @returns Success status (true if enabled successfully) */ enableMouseMoveEvent(): boolean; /** * Disable mousemove events * * Stops emitting "mouse-move" events to reduce CPU usage. * This is the default state after starting the hook. * * @returns Success status (true if disabled successfully) */ disableMouseMoveEvent(): boolean; /** * Enable clipboard fallback for text selection * * Uses Ctrl+C as a last resort to get selected text when other methods fail. * This might modify clipboard contents. * * @returns Success status (true if enabled successfully) */ enableClipboard(): boolean; /** * Disable clipboard fallback for text selection * * Will not use Ctrl+C to get selected text. * This preserves clipboard contents. * * @returns Success status (true if disabled successfully) */ disableClipboard(): boolean; /** * Set clipboard mode and program list for text selection * * Configures how the clipboard fallback mechanism works for different programs. * Mode can be: * - DEFAULT: Use clipboard for all programs * - INCLUDE_LIST: Only use clipboard for programs in the list * - EXCLUDE_LIST: Use clipboard for all programs except those in the list * * @param {number} mode - Clipboard mode (SelectionHook.ClipboardMode) * @param {string[]} programList - Array of program names to include/exclude * @returns {boolean} Success status */ setClipboardMode( mode: (typeof SelectionHook.FilterMode)[keyof typeof SelectionHook.FilterMode], programList?: string[] ): boolean; /** * Set global filter mode for text selection * * Configures how the global filter mechanism works for different programs. * Mode can be: * - DEFAULT: disable global filter * - INCLUDE_LIST: Only use global filter for programs in the list * - EXCLUDE_LIST: Use global filter for all programs except those in the list * * @param {number} mode - Filter mode (SelectionHook.FilterMode) * @param {string[]} programList - Array of program names to include/exclude * @returns {boolean} Success status */ setGlobalFilterMode( mode: (typeof SelectionHook.FilterMode)[keyof typeof SelectionHook.FilterMode], programList?: string[] ): boolean; /** * Set fine-tuned list for specific behaviors * * Configures fine-tuned lists for specific application behaviors. * List types: * - EXCLUDE_CLIPBOARD_CURSOR_DETECT: Exclude cursor detection for clipboard operations * - INCLUDE_CLIPBOARD_DELAY_READ: Include delay when reading clipboard content * * @param {number} listType - Fine-tuned list type (SelectionHook.FineTunedListType) * @param {string[]} programList - Array of program names for the fine-tuned list * @returns {boolean} Success status */ setFineTunedList( listType: (typeof SelectionHook.FineTunedListType)[keyof typeof SelectionHook.FineTunedListType], programList?: string[] ): boolean; /** * Set selection passive mode * @param {boolean} passive - Passive mode * @returns {boolean} Success status */ setSelectionPassiveMode(passive: boolean): boolean; /** * Write text to clipboard * @param {string} text - Text to write to clipboard * @returns {boolean} Success status */ writeToClipboard(text: string): boolean; /** * Read text from clipboard * @returns {string|null} Text from clipboard or null if empty or error */ readFromClipboard(): string | null; /** * Check if the process is trusted for accessibility (macOS only) * * Checks whether the current process has accessibility permissions * required for text selection monitoring on macOS. * * @returns {boolean} True if the process is trusted for accessibility, false otherwise */ macIsProcessTrusted(): boolean; /** * Try to request accessibility permissions (macOS only) * * This MAY show a dialog to the user if permissions are not granted. * * @returns {boolean} The current permission status, not the request result */ macRequestProcessTrust(): boolean; /** * Release resources * * Stops monitoring and releases all native resources. * Should be called before the application exits to prevent memory leaks. */ cleanup(): void; /** * Register event listeners * * The hook emits various events that can be listened for: */ /** * Emitted when text is selected in any application * @param event The event name * @param listener Callback function receiving selection data */ on(event: "text-selection", listener: (data: TextSelectionData) => void): this; on(event: "mouse-up", listener: (data: MouseEventData) => void): this; on(event: "mouse-down", listener: (data: MouseEventData) => void): this; on(event: "mouse-move", listener: (data: MouseEventData) => void): this; on(event: "mouse-wheel", listener: (data: MouseWheelEventData) => void): this; on(event: "key-down", listener: (data: KeyboardEventData) => void): this; on(event: "key-up", listener: (data: KeyboardEventData) => void): this; on(event: "status", listener: (status: string) => void): this; on(event: "error", listener: (error: Error) => void): this; // Same events available with once() for one-time listeners once(event: "text-selection", listener: (data: TextSelectionData) => void): this; once(event: "mouse-up", listener: (data: MouseEventData) => void): this; once(event: "mouse-down", listener: (data: MouseEventData) => void): this; once(event: "mouse-move", listener: (data: MouseEventData) => void): this; once(event: "mouse-wheel", listener: (data: MouseWheelEventData) => void): this; once(event: "key-down", listener: (data: KeyboardEventData) => void): this; once(event: "key-up", listener: (data: KeyboardEventData) => void): this; once(event: "status", listener: (status: string) => void): this; once(event: "error", listener: (error: Error) => void): this; } /** * Instance type for the SelectionHook class */ export type SelectionHookInstance = InstanceType<typeof SelectionHook>; /** * Constructor type for the SelectionHook class */ export type SelectionHookConstructor = typeof SelectionHook; // Export the SelectionHook class export default SelectionHook;