High-performance macOS system event hook library for Electron applications with full TypeScript support.
This library includes comprehensive AI-optimized documentation to help AI assistants understand and implement the library effectively. These specialized guides are designed to provide AI with contextual usage patterns and best practices.
- CommonJS Guide (English) - Complete CommonJS patterns and implementations
- CommonJS Guide (한국어) - CommonJS 패턴 및 구현 가이드
- ESM Guide (English) - Modern ES Module syntax and patterns
- ESM Guide (한국어) - 최신 ES 모듈 문법 및 패턴
- TypeScript Guide (English) - Type-safe implementations and patterns
- TypeScript Guide (한국어) - 타입 안전한 구현 및 패턴
- Development Document - Technical specifications and architecture
These guides enable AI assistants to provide accurate, context-aware assistance for implementing system event hooks in macOS applications.
Traditional macOS event hooking solutions often suffer from fragmentation and complexity, requiring developers to integrate multiple disparate libraries, manage complex native dependencies, and navigate inconsistent APIs across different event types. This fragmented ecosystem leads to increased development overhead, maintenance burden, and potential compatibility issues.
iohook-macos addresses these challenges by providing a unified, comprehensive solution that consolidates all system-level event monitoring capabilities into a single, well-designed library. Our approach eliminates the need for multiple dependencies while delivering enterprise-grade performance, complete TypeScript integration, and intuitive APIs that abstract away the underlying complexity of macOS Core Graphics Event Services.
By offering a cohesive development experience with consistent patterns across keyboard, mouse, and scroll event handling, developers can focus on building features rather than wrestling with infrastructure concerns.
-
🎹 Keyboard Events:
keyDown
,keyUp
,flagsChanged
- 🖱️ Mouse Events: Click, movement, drag (left/right/other buttons)
- 🌀 Scroll Events: Mouse wheel and trackpad gestures
- 🔒 Security: Built-in accessibility permission handling
- ⚡ Performance: Optimized polling mode with configurable rates
- 🎛️ Filtering: Process ID, coordinate range, and event type filters
- 🛡️ Type Safety: Complete TypeScript definitions included
- 📊 Monitoring: Real-time queue monitoring and statistics
npm install iohook-macos
- macOS 10.15+ (Catalina or later)
- Node.js 14+
- Electron (if using with Electron apps)
- Xcode Command Line Tools
const iohook = require('iohook-macos')
// Check accessibility permissions
const permissions = iohook.checkAccessibilityPermissions()
if (!permissions.hasPermissions) {
console.log('Please grant accessibility permissions')
iohook.requestAccessibilityPermissions()
process.exit(1)
}
// Set up event listeners
iohook.on('keyDown', (event) => {
console.log('Key pressed:', event.keyCode)
})
iohook.on('leftMouseDown', (event) => {
console.log('Mouse clicked at:', event.x, event.y)
})
// Start monitoring
iohook.startMonitoring()
import * as iohook from 'iohook-macos'
import type { EventData, AccessibilityPermissionsResult } from 'iohook-macos'
// Type-safe permission checking
const permissions: AccessibilityPermissionsResult = iohook.checkAccessibilityPermissions()
// Type-safe event handling
iohook.on('keyDown', (event: EventData) => {
console.log('Key pressed:', event.keyCode)
console.log('Event type:', event.type) // CGEventType number
})
// Number-based event listeners (CGEventType)
iohook.on(1, (event: EventData) => { // kCGEventLeftMouseDown
console.log('Left mouse down at:', event.x, event.y)
})
// Start monitoring with full type safety
iohook.startMonitoring()
This library includes comprehensive TypeScript definitions for full type safety and IntelliSense support.
interface EventData {
type: number // CGEventType integer
x?: number // X coordinate (mouse events)
y?: number // Y coordinate (mouse events)
timestamp: number // Event timestamp
processId?: number // Source process ID
keyCode?: number // Key code (keyboard events)
hasKeyCode?: boolean // Whether keyCode is available
}
interface AccessibilityPermissionsResult {
hasPermissions: boolean
message: string
}
interface EventFilterOptions {
filterByProcessId?: boolean
excludeProcessId?: boolean
targetProcessId?: number
filterByCoordinates?: boolean
minX?: number
maxX?: number
minY?: number
maxY?: number
filterByEventType?: boolean
allowKeyboard?: boolean
allowMouse?: boolean
allowScroll?: boolean
}
Both string and numeric event types are fully supported:
// String-based (recommended for readability)
iohook.on('keyDown', handler)
iohook.on('leftMouseDown', handler)
iohook.on('scrollWheel', handler)
// Number-based (CGEventType integers)
iohook.on(10, handler) // kCGEventKeyDown
iohook.on(1, handler) // kCGEventLeftMouseDown
iohook.on(22, handler) // kCGEventScrollWheel
# Install TypeScript dependencies
npm install
# Run TypeScript example
npm run typescript-example
# Compile TypeScript example
npm run typescript-compile
Method | Description | Returns |
---|---|---|
startMonitoring() |
Start event monitoring | void |
stopMonitoring() |
Stop event monitoring | void |
isMonitoring() |
Check monitoring status | boolean |
Method | Description | Parameters |
---|---|---|
setPollingRate(ms) |
Set polling interval | ms: number |
getQueueSize() |
Get event queue size | - |
clearQueue() |
Clear event queue | - |
getNextEvent() |
Get next event manually | - |
Method | Description | Parameters |
---|---|---|
enablePerformanceMode() |
Enable high-performance mode | - |
disablePerformanceMode() |
Disable performance mode | - |
setMouseMoveThrottling(ms) |
Throttle mouse move events | ms: number |
setVerboseLogging(enable) |
Control verbose logging | enable: boolean |
Method | Description | Parameters |
---|---|---|
setEventFilter(options) |
Configure event filters | options: EventFilterOptions |
clearEventFilter() |
Clear all filters | - |
macOS requires accessibility permissions for system event monitoring:
// Check permissions
const result = iohook.checkAccessibilityPermissions()
console.log(result.hasPermissions) // boolean
console.log(result.message) // descriptive message
// Request permissions (shows system dialog)
if (!result.hasPermissions) {
iohook.requestAccessibilityPermissions()
}
Manual Setup:
- Open System Preferences → Security & Privacy → Privacy
- Select Accessibility from the left panel
- Click the lock icon and enter your password
- Add your application to the list
// Listen for specific events
iohook.on('keyDown', (event) => {
console.log(`Key ${event.keyCode} pressed`)
})
iohook.on('mouseMoved', (event) => {
console.log(`Mouse at (${event.x}, ${event.y})`)
})
// Generic event listener
iohook.on('event', (event) => {
console.log(`Event type: ${event.type}`)
})
// Filter by process ID
iohook.setEventFilter({
filterByProcessId: true,
targetProcessId: 1234,
excludeProcessId: false // Include only this process
})
// Filter by screen coordinates
iohook.setEventFilter({
filterByCoordinates: true,
minX: 0, maxX: 1920,
minY: 0, maxY: 1080
})
// Filter by event types
iohook.setEventFilter({
filterByEventType: true,
allowKeyboard: true,
allowMouse: true,
allowScroll: false
})
// Main process (main.js)
const { app, BrowserWindow, ipcMain } = require('electron')
const iohook = require('iohook-macos')
function createWindow() {
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
// Set up event forwarding
iohook.on('keyDown', (data) => {
mainWindow.webContents.send('keyDown', data)
})
iohook.startMonitoring()
}
app.whenReady().then(createWindow)
The repository includes comprehensive examples:
-
JavaScript:
examples/test/
-
TypeScript:
examples/typescript/
-
Electron:
examples/electron/
# Run basic test
npm test
# Run comprehensive test
npm run test-comprehensive
# Run Electron example
npm run electron-test
# Run TypeScript example
npm run typescript-example
// Enable performance mode
iohook.enablePerformanceMode()
// Set optimal polling rate (60fps)
iohook.setPollingRate(16)
// Throttle high-frequency mouse events
iohook.setMouseMoveThrottling(16)
// Monitor queue size
setInterval(() => {
const queueSize = iohook.getQueueSize()
if (queueSize > 100) {
console.warn('Queue getting large:', queueSize)
}
}, 1000)
# Install dependencies
npm install
# Rebuild native module
npm run rebuild
# For Electron
npm run electron-rebuild
- Xcode with Command Line Tools
- Python 3 (for node-gyp)
- Node.js 14+
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details.
- Built with Node.js N-API
- Uses macOS Core Graphics Event Services
- Inspired by the cross-platform iohook library
Made with ❤️ for macOS developers