UNPKG

keyboard-mouse-share

Version:
168 lines (138 loc) 4.16 kB
const { GlobalKeyboardListener } = require('node-global-key-listener'); class HotkeyManager { constructor(hotkeyCombo = 'LEFT CTRL + ENTER', callback = null) { this.hotkeyCombo = hotkeyCombo; this.callback = callback; this.listener = null; this.registered = false; this.keysPressed = new Set(); this.debug = false; // Set to true for debugging this.lastTrigger = 0; this.debounceMs = 500; // Minimum 500ms between triggers } register(callback = null) { if (callback) { this.callback = callback; } if (!this.callback) { console.error('No callback provided for hotkey'); return; } try { this.listener = new GlobalKeyboardListener(); // Parse hotkey combination const keys = this.parseHotkey(this.hotkeyCombo); if (this.debug) { console.log('Expected keys:', keys); } this.listener.addListener((e, down) => { const keyName = e.name; if (this.debug) { console.log(`Key event: ${keyName}, state: ${e.state}, down:`, down); } // Track pressed keys if (e.state === 'DOWN') { this.keysPressed.add(keyName); } else if (e.state === 'UP') { this.keysPressed.delete(keyName); } if (this.debug) { console.log('Currently pressed:', Array.from(this.keysPressed)); } // Check if hotkey is pressed on DOWN event if (e.state === 'DOWN') { if (this.isHotkeyPressed(keys)) { if (this.debug) { console.log('✓ Hotkey matched!'); } this.onHotkeyPressed(); } } }); this.registered = true; console.log(`✓ Hotkey registered: ${this.hotkeyCombo}`); console.log(` Press ${this.hotkeyCombo} to toggle capture`); } catch (error) { console.error(`Failed to register hotkey: ${error.message}`); console.log('Note: You may need to run with administrator/root privileges'); } } parseHotkey(combo) { // Parse hotkey combination return combo .split('+') .map(k => k.trim()) .map(k => { // Keep exact names from node-global-key-listener // Don't normalize too much return k; }); } isHotkeyPressed(requiredKeys) { // Check if all required keys are currently pressed for (const key of requiredKeys) { let found = false; for (const pressedKey of this.keysPressed) { // Case-insensitive match and partial match for modifiers const keyLower = key.toLowerCase(); const pressedLower = pressedKey.toLowerCase(); if (pressedLower === keyLower || pressedLower.includes(keyLower) || keyLower.includes(pressedLower)) { found = true; break; } } if (!found) { return false; } } return requiredKeys.length > 0; } onHotkeyPressed() { // Debounce - prevent spam const now = Date.now(); if (now - this.lastTrigger < this.debounceMs) { if (this.debug) { console.log(`Hotkey ignored (debounced, ${now - this.lastTrigger}ms since last trigger)`); } return; } this.lastTrigger = now; if (this.debug) { console.log(`Hotkey triggered: ${this.hotkeyCombo}`); } if (this.callback) { this.callback(); } } unregister() { if (this.registered && this.listener) { try { this.listener.kill(); this.registered = false; console.log(`Hotkey unregistered: ${this.hotkeyCombo}`); } catch (error) { console.error(`Failed to unregister hotkey: ${error.message}`); } } } setHotkey(newCombo) { const wasRegistered = this.registered; if (wasRegistered) { this.unregister(); } this.hotkeyCombo = newCombo; if (wasRegistered) { this.register(); } } enableDebug() { this.debug = true; console.log('Hotkey debug enabled - all key events will be logged'); } disableDebug() { this.debug = false; } } module.exports = HotkeyManager;