How Cua Driver Achieves Background macOS Automation Without Stealing Cursor or Focus

Cua Driver achieves background macOS automation without stealing cursor or focus by layering three independent techniques: accessibility attribute enablement, synthetic focus state injection, and a reactive guard that intercepts and reverses focus-stealing attempts via NSWorkspace notifications.

The trycua/cua repository implements this capability in the Cua Driver, a Swift-based automation framework that controls macOS applications entirely in the background. Unlike traditional AppleScript or Accessibility API approaches that force the target app to the foreground, this driver preserves the user's current context by manipulating the accessibility tree and focus states directly.

The Three-Layer Focus Suppression Architecture

The driver prevents cursor and focus stealing through a coordinated defense implemented across three distinct layers. Each layer addresses a specific mechanism by which macOS applications typically force themselves into the foreground.

The architecture consists of:

  • AX Enablement: Setting accessibility attributes on Chromium-family apps to expose full UI trees without activation
  • Synthetic Focus: Temporarily overriding AXFocused and AXMain attributes to simulate focus without system activation
  • Reactive Guard: Monitoring NSWorkspace.didActivateApplicationNotification to immediately reverse any successful focus grabs

Layer 1: AX Enablement for Chromium Applications

Modern macOS applications built on Chromium frameworks (Chrome, VS Code, Slack) require specific accessibility attributes to expose their full UI hierarchy when running in the background. The AXEnablementAssertion actor in libs/cua-driver/Sources/CuaDriverCore/Focus/AXEnablementAssertion.swift handles this initialization.

/// Writes AXManualAccessibility and AXEnhancedUserInterface on the application root.
public actor AXEnablementAssertion {
    private var assertedPids: Set<pid_t> = []
    private var nonAssertablePids: Set<pid_t> = []

    public func assert(pid: pid_t, root: AXUIElement) -> Bool { … }
}

When assert(pid:root:) succeeds, the target application exposes a complete accessibility tree capable of receiving actions without NSRunningApplication.activate being called. The implementation caches process IDs (PIDs) that fail assertion as "non-assertable" to avoid redundant failed writes on subsequent operations.

Layer 2: Synthetic Focus State Injection

Even with accessibility enabled, macOS UI actions typically require the target window to hold system focus. The SyntheticAppFocusEnforcer actor in libs/cua-driver/Sources/CuaDriverCore/Focus/SyntheticAppFocusEnforcer.swift bypasses this requirement by temporarily manipulating focus attributes directly.

public actor SyntheticAppFocusEnforcer {
    public func preventActivation(pid: pid_t,
                                 window: AXUIElement?,
                                 element: AXUIElement?) async -> FocusState { … }

    public func reenableActivation(_ state: FocusState) async { … }
}

The preventActivation method records the current AXFocused and AXMain boolean values, writes true to both attributes, and returns a FocusState token. This makes the target's internal AppKit state believe it already has focus, preventing the system from invoking AXUIElementPerformAction(kAXRaiseAction). After the automation action completes, reenableActivation restores the original values.

Layer 3: Reactive Focus-Steal Guard

Some applications (particularly Safari and WebKit-based browsers) occasionally bypass synthetic focus controls and trigger activate calls. The SystemFocusStealPreventer in libs/cua-driver/Sources/CuaDriverCore/Focus/SystemFocusStealPreventer.swift implements a reactive defense against these edge cases.

public actor SystemFocusStealPreventer {
    public func beginSuppression(targetPid: pid_t,
                                restoreTo: NSRunningApplication) async -> SuppressionHandle { … }
    public func endSuppression(_ handle: SuppressionHandle) async { … }
}

This actor installs an observer on NSWorkspace.didActivateApplicationNotification. When the notification indicates the suppressed target PID has activated, the guard immediately calls restoreTo.activate(options: []) to return focus to the previously frontmost application. The SuppressionHandle manages the lifecycle of this observation, ensuring cleanup after automation completes.

The FocusGuard Coordinator

The FocusGuard actor in libs/cua-driver/Sources/CuaDriverCore/Focus/FocusGuard.swift serves as the public entry point, coordinating all three suppression layers into a single transactional API.

public actor FocusGuard {
    public func withFocusSuppressed<T: Sendable>(pid: pid_t,
                                                element: AXUIElement?,
                                                body: @Sendable () async throws -> T) async throws -> T { … }
}

The withFocusSuppressed method executes the following sequence:

  1. Invokes AXEnablementAssertion.assert to prepare accessibility attributes
  2. Calls SyntheticAppFocusEnforcer.preventActivation to inject synthetic focus
  3. Optionally initiates SystemFocusStealPreventer.beginSuppression for reactive monitoring
  4. Executes the provided body closure containing the actual automation action
  5. Restores original focus states and ends suppression via the respective cleanup methods

Practical Implementation Example

To perform background automation using the driver, instantiate the three components and wrap your automation logic inside withFocusSuppressed:

import CuaDriverCore

let pid = 12345                     // PID of the background app (e.g. Calculator)
let element: AXUIElement? = nil     // No specific AX element, just the app root

let guard = FocusGuard(
    enablement: AXEnablementAssertion(),
    enforcer: SyntheticAppFocusEnforcer(),
    systemPreventer: SystemFocusStealPreventer()
)

await guard.withFocusSuppressed(pid: pid, element: element) {
    // Inside this closure you can safely call any driver tool, e.g. click a button:
    try await ClickTool.perform(pid: pid, windowId: 0, x: 150, y: 80)
}

For Python-based integrations, the driver_client.py in libs/cua-driver/Tests/integration/driver_client.py forwards JSON-RPC calls to the Swift driver binary where the suppression logic executes:

from driver_client import DriverClient, default_binary_path

with DriverClient(default_binary_path()) as client:
    # Example: press the "A" key in a background app

    client.call_tool("type_text", {"pid": 12345, "text": "A"})

The focus suppression logic resides entirely within the compiled Swift driver, not the client layer, ensuring consistent behavior across language bindings.

Summary

  • Three-layer architecture: Cua Driver combines AX enablement, synthetic focus injection, and reactive focus-steal prevention to maintain background operation.
  • Chromium compatibility: The AXEnablementAssertion class enables full accessibility trees on Electron and Chromium apps without activation.
  • Focus simulation: SyntheticAppFocusEnforcer manipulates AXFocused and AXMain attributes to trick AppKit into believing the target already has focus.
  • Reactive protection: SystemFocusStealPreventer monitors NSWorkspace.didActivateApplicationNotification to reverse any unwanted activations from WebKit applications.
  • Unified API: FocusGuard.withFocusSuppressed provides a transactional interface that bundles all suppression layers and automatically manages cleanup.

Frequently Asked Questions

Does this approach work with all macOS applications?

The driver works with standard Cocoa applications and Chromium-based apps (VS Code, Slack, Chrome) that respect accessibility attributes. However, some system applications or those implementing custom window management may resist synthetic focus injection, in which case the reactive guard in SystemFocusStealPreventer provides fallback protection by immediately reversing any focus theft.

What happens if the target application tries to activate itself during automation?

If the target app attempts to steal focus via NSRunningApplication.activate or similar APIs, the SystemFocusStealPreventer intercepts the NSWorkspace.didActivateApplicationNotification and immediately reactivates the previously frontmost application. This creates a near-instantaneous focus restoration that prevents visible UI disruption or cursor movement.

How does the driver handle performance when suppressing focus?

The suppression logic introduces minimal overhead. AXEnablementAssertion caches non-assertable PIDs to avoid redundant accessibility writes, and SyntheticAppFocusEnforcer performs only two AX attribute reads and writes per operation. The SystemFocusStealPreventer maintains a single notification observer regardless of how many operations are performed, ensuring the reactive guard scales efficiently.

Can I use this driver to automate applications that are not currently running?

No. The Cua Driver requires the target application to be already running with a valid process ID (PID). The focus suppression techniques described here manipulate existing accessibility trees and window states; they do not handle application launch or initialization of new accessibility contexts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →