macos-app-focus
v1.4.0
Published
Native bindings for managing app focus and frontmost applications on macOS
Downloads
23
Maintainers
Readme
macos-focus-manager
A native Node.js module for managing application focus and window management on macOS. Built specifically for Electron apps that need precise control over window focus and frontmost application state.
Features
- Get and set frontmost application
- Track previous application focus
- Capture selected text with app details
- Universal binary support (x64 and arm64)
- TypeScript type definitions included
- Built for macOS 10.15 and later
Installation
npm install macos-focus-managerRequirements
- macOS 10.15 or later
- Node.js >= 18.0.0
- Electron >= 25.0.0 (if using with Electron)
- Accessibility permissions may be required for text selection
Usage
Basic Usage
import { FocusManager } from "macos-focus-manager";
// Create a new instance
const focusManager = new FocusManager();
// Get frontmost application info
const currentApp = focusManager.getFrontmostApp();
console.log("Current frontmost app:", currentApp);
// Output: { name: 'App Name', bundleId: 'com.example.app', pid: 12345 }
// Get previous application info
const prevApp = focusManager.getPreviousApp();
console.log("Previous app:", prevApp);
// Focus a specific application by PID
focusManager.focusApp(12345);
// Store current frontmost app for later restoration
focusManager.storeFrontmostApp();
// Get selected text with app details
const selection = focusManager.getSelectedText();
if (selection) {
console.log("Selected text:", selection.text);
console.log("From app:", selection.app.name);
console.log("Timestamp:", new Date(selection.timestamp).toISOString());
}Text Selection Example
import { FocusManager } from "macos-focus-manager";
const focusManager = new FocusManager();
// Capture selected text from any application with context
const textSelection = focusManager.getSelectedText();
if (textSelection) {
console.log("Selected Text:", textSelection.text);
console.log("HTML Content:", textSelection.html);
console.log("RTF Content:", textSelection.rtf);
console.log("Has Image:", textSelection.hasImage);
console.log("App Name:", textSelection.app.name);
console.log("App Bundle ID:", textSelection.app.bundleId);
console.log("App PID:", textSelection.app.pid);
console.log("Timestamp:", new Date(textSelection.timestamp).toISOString());
// Context information for supported applications
if (textSelection.context) {
if (textSelection.context.browser) {
console.log("🌐 Browser Context:");
console.log(" URL:", textSelection.context.browser.url);
console.log(" Title:", textSelection.context.browser.title);
console.log(" Tab Index:", textSelection.context.browser.tabIndex);
}
if (textSelection.context.vscode) {
console.log("💻 VS Code Context:");
console.log(" File Path:", textSelection.context.vscode.filePath);
console.log(" Line Number:", textSelection.context.vscode.lineNumber);
console.log(" Column Number:", textSelection.context.vscode.columnNumber);
console.log(" Workspace Path:", textSelection.context.vscode.workspacePath);
}
}
} else {
console.log("No text selected or unable to get selection");
}Electron Integration Example
import { BrowserWindow } from "electron";
import { FocusManager } from "macos-focus-manager";
class WindowManager {
private focusManager: FocusManager;
private window: BrowserWindow;
private previousApp: AppInfo | null = null;
constructor(window: BrowserWindow) {
this.focusManager = new FocusManager();
this.window = window;
// Store previous app before showing window
window.on("show", () => {
this.previousApp = this.focusManager.getFrontmostApp();
});
// Handle window blur
window.on("blur", () => {
if (this.previousApp) {
this.focusManager.focusApp(this.previousApp.pid);
this.previousApp = null;
}
});
}
}API Reference
FocusManager
Methods
getFrontmostApp(): AppInfo | nullReturns information about the currently frontmost application.getPreviousApp(): AppInfo | nullReturns information about the previously focused application.focusApp(pid: number): booleanFocuses the application with the given process ID.storeFrontmostApp(): booleanStores the current frontmost application for later reference.getSelectedText(): TextSelection | nullCaptures the currently selected text along with the source application details and context information. Uses a reliable clipboard-based approach with timeout polling and extracts additional metadata for supported applications.
Types
type AppInfo = {
name: string; // Application name
bundleId: string; // Bundle identifier
pid: number; // Process ID
};
type BrowserContext = {
url: string; // Current tab URL
title: string; // Page title
tabIndex?: number; // Tab index (if available)
};
type VSCodeContext = {
filePath: string; // Current file path
lineNumber: number; // Cursor line number
columnNumber: number; // Cursor column number
workspacePath?: string; // Workspace path (if available)
};
type AppContext = {
browser?: BrowserContext; // Browser-specific context
vscode?: VSCodeContext; // VS Code-specific context
};
type TextSelection = {
text: string; // Selected text content
html: string; // HTML formatted content (if available)
rtf: string; // RTF formatted content (if available)
hasImage: boolean; // Whether an image was selected
app: AppInfo; // Source application information
context?: AppContext; // Application-specific context
timestamp: number; // Unix timestamp in milliseconds
};Supported Applications
🌐 Browsers (Generic Detection)
Works with any browser including:
- Google Chrome - URL, title, tab index
- Safari - URL, title, tab index
- Firefox - URL, title, tab index
- Microsoft Edge - URL, title, tab index
- Brave Browser - URL, title, tab index
- Opera - URL, title, tab index
- Dia Browser - URL, title, tab index
- Arc Browser - URL, title, tab index
- Any other browser - Uses generic detection and fallback methods
💻 Code Editors (Generic Detection)
Works with code editors including:
- Visual Studio Code - File path, cursor position, workspace path
- Other code editors - Uses generic detection for similar functionality
📝 Other Applications
- All applications that support text selection (basic text capture)
Permissions
For text selection functionality to work properly, your application may need accessibility permissions. On macOS:
- Go to System Preferences > Security & Privacy > Privacy > Accessibility
- Add your application to the list of allowed applications
- Ensure the checkbox next to your application is enabled
Building from Source
# Install dependencies
npm install
# Build the module
npm run buildLicense
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
