UNPKG

keyboard-mouse-share

Version:
189 lines (160 loc) 5.72 kB
const { screen, mouse } = require('@nut-tree-fork/nut-js'); const { exec } = require('child_process'); const util = require('util'); const execPromise = util.promisify(exec); class EdgeDetector { constructor(config, onEdgeCrossed, onEdgeReturn) { this.screenEdge = config.screenEdge || 'right'; this.threshold = config.edgeThreshold || 5; this.enabled = config.autoSwitch !== false; this.onEdgeCrossed = onEdgeCrossed; this.onEdgeReturn = onEdgeReturn; this.screenWidth = 0; this.screenHeight = 0; this.virtualScreenWidth = 0; this.virtualScreenHeight = 0; this.isCrossed = false; this.checkInterval = null; this.checkRate = 50; // Check every 50ms } async getVirtualScreenDimensions() { const platform = process.platform; try { if (platform === 'darwin') { // macOS: Use system_profiler to get all displays const { stdout } = await execPromise('system_profiler SPDisplaysDataType | grep Resolution'); const resolutions = stdout.match(/(\d+) x (\d+)/g); if (resolutions && resolutions.length > 0) { let totalWidth = 0; let maxHeight = 0; resolutions.forEach(res => { const [w, h] = res.match(/\d+/g).map(Number); totalWidth += w; maxHeight = Math.max(maxHeight, h); }); return { width: totalWidth, height: maxHeight }; } } else if (platform === 'win32') { // Windows: Use wmic to get display info const { stdout } = await execPromise('wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution /format:value'); const widths = [...stdout.matchAll(/CurrentHorizontalResolution=(\d+)/g)].map(m => parseInt(m[1])); const heights = [...stdout.matchAll(/CurrentVerticalResolution=(\d+)/g)].map(m => parseInt(m[1])); if (widths.length > 0) { const totalWidth = widths.reduce((a, b) => a + b, 0); const maxHeight = Math.max(...heights); return { width: totalWidth, height: maxHeight }; } } else if (platform === 'linux') { // Linux: Use xrandr const { stdout } = await execPromise('xrandr --query | grep " connected"'); const resolutions = stdout.match(/(\d+)x(\d+)/g); if (resolutions && resolutions.length > 0) { let totalWidth = 0; let maxHeight = 0; resolutions.forEach(res => { const [w, h] = res.split('x').map(Number); totalWidth += w; maxHeight = Math.max(maxHeight, h); }); return { width: totalWidth, height: maxHeight }; } } } catch (error) { console.warn(`Could not detect virtual screen size: ${error.message}`); } // Fallback to nut-js screen size return { width: await screen.width(), height: await screen.height() }; } async init() { // Get primary screen dimensions this.screenWidth = await screen.width(); this.screenHeight = await screen.height(); // Get virtual desktop dimensions (all screens combined) const virtualDims = await this.getVirtualScreenDimensions(); this.virtualScreenWidth = virtualDims.width; this.virtualScreenHeight = virtualDims.height; console.log(`Primary screen: ${this.screenWidth}x${this.screenHeight}`); if (this.virtualScreenWidth !== this.screenWidth || this.virtualScreenHeight !== this.screenHeight) { console.log(`Virtual desktop: ${this.virtualScreenWidth}x${this.virtualScreenHeight}`); } console.log(`Edge detection: ${this.screenEdge} (threshold: ${this.threshold}px)`); } start() { if (!this.enabled || this.screenEdge === 'none') { console.log('Edge detection disabled'); return; } this.checkInterval = setInterval(async () => { await this.checkEdge(); }, this.checkRate); console.log(`✓ Edge detection started on ${this.screenEdge} edge`); } async checkEdge() { try { const pos = await mouse.getPosition(); const atEdge = this.isAtEdge(pos.x, pos.y); // Edge crossed (entering client screen) if (atEdge && !this.isCrossed) { this.isCrossed = true; if (this.onEdgeCrossed) { this.onEdgeCrossed(); } } // Returned from edge (back to master screen) else if (!atEdge && this.isCrossed) { this.isCrossed = false; if (this.onEdgeReturn) { this.onEdgeReturn(); } } } catch (error) { // Silently ignore errors } } isAtEdge(x, y) { // Use virtual screen dimensions for multi-monitor support const width = this.virtualScreenWidth || this.screenWidth; const height = this.virtualScreenHeight || this.screenHeight; switch (this.screenEdge) { case 'right': return x >= width - this.threshold; case 'left': return x <= this.threshold; case 'top': return y <= this.threshold; case 'bottom': return y >= height - this.threshold; default: return false; } } stop() { if (this.checkInterval) { clearInterval(this.checkInterval); this.checkInterval = null; } console.log('Edge detection stopped'); } setEdge(edge) { this.screenEdge = edge; console.log(`Edge detection set to: ${edge}`); } setThreshold(threshold) { this.threshold = threshold; console.log(`Edge threshold set to: ${threshold}px`); } enable() { this.enabled = true; if (!this.checkInterval) { this.start(); } } disable() { this.enabled = false; this.stop(); } } module.exports = EdgeDetector;