feat(macos): complete background operation: sky_key, covered/other-Space windows, agent display - #65
Open
hyprcat wants to merge 9 commits into
Open
Conversation
…ky_key`) Add an explicit `key_method=sky_key` to `type_text` and `press_key` that delivers keyboard input to covered or off-Space windows without changing the user's foreground app, key window, first responder or pointer. Chromium only inserts text while its NSWindow is the AppKit key window, so sky_key reuses sky_click's target-only synthetic-active record, then posts yabai's make-key-window record pair, waits for the target to become key, delivers the existing postToPid keyboard events, and releases the state. Command chords are pressed through the target's AX menu bar because AppKit only dispatches NSMenu key equivalents for the active app. Windows/Linux expose the enum and return a stable unsupported error. Includes unit tests, an opt-in isolated-Chrome live regression, docs, a reference note recording the approaches that were verified not to work, history and a completed execution plan.
hyprcat
force-pushed
the
feat/sky-key-background-keyboard
branch
from
September 8, 2026 17:06
5492394 to
8598550
Compare
…ble and capturable Apps only learn that a window is covered or on another Space through WindowServer occlusion notifications; Chromium, Electron and WebKit react by hiding the page, which drops the web accessibility subtree. Treat this at the WindowServer level instead of per app: - get_app_state resolves off-screen windows (other Space) instead of falling into the activate-and-raise recovery, and captures them with SCK by id. - WindowOcclusionKeepAlive disables occlusion notifications for every window the agent snapshots while it is unoccluded, pinning the app's "visible" state; restored at process exit. - Chromium-family apps (detected by shipped engine frameworks or accepted AXManualAccessibility) get a bounded re-walk until their lazy web tree exists; a hidden window gets a note in the tree instead of a wait. - sky_click accepts covered and other-Space windows; hidden apps fail closed. Includes unit tests, opt-in live regressions for the keep-alive and for a real second Desktop, a reference note with the SPI signatures read from lldb, the verified virtual-display approach for windows that were already hidden at first contact, history and an active execution plan.
hyprcat
force-pushed
the
feat/sky-key-background-keyboard
branch
from
September 8, 2026 17:47
b15cde7 to
9956a94
Compare
…ides A window that is covered or on another Space when the agent first sees it has no WindowServer-level way back to "visible" without showing it. macOS's own mechanism for that is a virtual display, so get_app_state gains an explicit window_placement: - agent_display creates an invisible 1920x1080 CGVirtualDisplay owned by the runtime and moves the target window's frame onto it with AX position (no activation, raise, Space switch or pointer move); the app renders it, exposes its full tree and accepts sky_click / sky_key. - restore puts the window back; the display is removed once nothing is parked, and all windows are restored at process exit. - keep (default) changes nothing. Windows/Linux reject the other values. The private classes live behind a small ObjC shim target resolved with NSClassFromString (no hard link dependency, ARC-managed lifetimes). Includes unit tests, the opt-in AgentDisplayLiveTests regression, docs, history and the archived execution plan.
hyprcat
force-pushed
the
feat/sky-key-background-keyboard
branch
from
September 8, 2026 17:57
0ef5df8 to
5eb5067
Compare
Closed
…nput benchmark Add OPEN_COMPUTER_USE_DEBUG_TIMING=1 per-phase timing on stderr for sky_key, sky_click, snapshot capture/walk and the agent display. Replace the agent display's fixed sleeps with polls on the observable conditions (display bounds + new Space, window frame inside the display, frame back at its original origin), falling back to the old fixed waits when the read-only Space SPIs are unavailable. Keep sky_key's 300 ms key-window settle: both AX signals that could replace it report before Chrome's page has focus. BackgroundInputBenchmarkLiveTests runs N sky_click + sky_key cycles against covered Chrome and reports success counts and p50/p95/max. On macOS 27: 25/25 and 25/25, click observed p50 389 ms, key observed p50 270 ms.
…, exact AX window binding Every fixed gap in the input recipes is now an environment-tunable knob whose default comes from BackgroundInputBenchmarkLiveTests (50 cycles, covered Chrome, exact-once clicks): events on one queue need no gap (type_text chunk 20->0 ms, press_key 100->0 ms, sky_key settle 300->0 ms, release 100->0 ms), the focus-record channel keeps 10 ms (was 40), and the sky_click recipe keeps 0.2x of its gaps (0 fails every click). Result: sky_click 323->82 ms, sky_key 526->30 ms to return, 50/50 on both. Window screenshots use SLSHWCaptureWindowList first (WindowServer reads the backing store, 15-45 ms, also for windows on inactive fullscreen Spaces where ScreenCaptureKit returns -3811), ScreenCaptureKit as fallback. The AX root window is bound to its CGWindowID with _AXUIElementGetWindow so tree, capture and element frames refer to one window. AppMatrixLiveTests surveys every running GUI app read-only and exercises an empty text field where one exists; results are recorded in the reference note.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi! I'm Hyprcat, one of the maintainers of mac-cua, an MCP server for macOS desktop automation built on the same idea as this project: drive apps through accessibility and screenshots without stealing the user's keyboard, focus or pointer. The work here is genuinely exciting and exactly the direction I'm working towards, so I'd like to contribute as much as I can. This PR makes background operation complete:
sky_clickalready handled background clicks; this adds background keyboard, keeps covered and other-Space windows readable, and gives the agent a way to work on windows the app has already hidden.Everything follows the
sky_clickconventions: explicit opt-in, never part ofauto, no silent fallback, fail closed when a private symbol is missing, and nothing is ever sent to the real foreground app. Windows and Linux expose the new enums and return a stable unsupported error before snapshot lookup.What's in it
key_method=sky_keyontype_text/press_key(macOS). Chromium only inserts text while its NSWindow is the AppKit key window, sosky_keyreusessky_click's target-only synthetic-active record, posts yabai's make-key-window record pair (which makes the target set the window key internally, with no front-process switch, raise or Space change), delivers the existingpostToPidkey events, and releases the state. Command chords (cmd+a,cmd+c,cmd+v, ...) are pressed through the target's own menu bar via AX, because AppKit only dispatchesNSMenukey equivalents for the active app.Covered and other-Space windows in
get_app_state. Apps learn that a window is covered only through WindowServer occlusion notifications; Chromium/Electron/WebKit react by hiding the page, which drops the web accessibility subtree.get_app_statenow resolves off-screen windows instead of falling into the activate-and-raise recovery, pins the visibility of each window it snapshots while unoccluded (SLSPackagesEnableWindowOcclusionNotifications, restored to its prior state on normal server/app shutdown or process exit), re-walks Chromium-family trees while their lazy web tree builds, and says so in the tree when a window was already hidden.sky_clickaccepts covered and other-Space windows too.window_placement=agent_displayonget_app_state(macOS). For a window that is already hidden when the agent first sees it, there is no notification trick; macOS's own answer is a virtual display.agent_displaycreates an invisible 1920x1080CGVirtualDisplayowned by the runtime and moves the window's frame onto it with the AX position attribute; the app renders it, exposes its full tree and acceptssky_click/sky_key.restoreputs it back; normal server/app shutdown and process exit both attempt restoration; failed live-window restores remain retryable. The private classes live behind a small ObjC shim resolved withNSClassFromString.Faster snapshots and input. Screenshots use
SLSHWCaptureWindowListfirst (15 to 45 ms, retina, and it captures windows on inactive fullscreen Spaces where ScreenCaptureKit returns -3811), with SCK as fallback. The AX root window is bound to itsCGWindowIDvia_AXUIElementGetWindowso tree, capture and element frames refer to one window. Every fixed gap in the input recipes is an environment-tunable knob. The macOS 27 benchmark reached 82 ms sky_click and 30 ms sky_key returns, while the final defaults retain small compatibility margins validated on macOS 26.6.2.OPEN_COMPUTER_USE_DEBUG_TIMING=1prints per-phase timings.Why it's designed this way
Visibility is a WindowServer concept the app only receives notifications about; input is WindowServer event delivery to a process; reading is AX plus capture by window id. Solving at that level keeps it app-agnostic. The reference notes record what was verified on macOS 27 and, just as importantly, what does not work: Cua's
SLSEventAuthenticationMessageenvelope alone, window-field stamping,SLPSSetFrontProcessWithOptions(makes the user's app resign active),CGSSetConnectionProperty "SetFrontmost", AX window focus, and moving other apps' windows between Spaces from a third-party process (gated on macOS 26+). Guessed private signatures are avoided; the ones used were read from disassembly and are documented.Compatibility follow-up
A macOS 26.6.2 rerun found occasional dropped keys with zero sky_key settle/release (18/20, then 49/50). The branch now defaults sky_key settle/release to 10/10 ms (50/50), and preserves the established auto-input defaults of 20 ms between type_text chunks and 100 ms after press_key. Occlusion cleanup restores each window’s prior notification state, and agent-display cleanup keeps failed live-window restores retryable. Normal MCP/app shutdown runs cleanup; uncatchable forced termination remains a documented boundary.
Verification
swift test: 185 tests, 0 failures; 7 opt-in live regressions skipped by default.cmd+awith the foreground fixture keeping active/key/first-responder state and zero resign counts (SkyKeyboardLiveTests);SkyClickLiveTestsstill green; a visible snapshot pins a window so covering it keeps the web tree and screenshot (OcclusionKeepAliveLiveTests); a Chrome window on a real second Desktop is snapshotted, clicked and typed into from the first Desktop with the active Space unchanged (CrossSpaceLiveTests); a Chrome window hidden before first contact is parked, driven, restored, and the display removed (AgentDisplayLiveTests).BackgroundInputBenchmarkLiveTests: 50/50 clicks and 50/50 keys on covered Chrome, exact-once, frontmost unchanged.AppMatrixLiveTests: every running GUI app with a window (native, Electron, WebKit, GL) snapshotted read-only without activation; background typing verified in System Settings and Slack, on the desktop and parked on the agent display, with windows restored to their original positions.go vet/go testfor both runtimes, the smoke suite,make check-docs.Benchmarks
Apple M5 / macOS 27.0 (26A5425a) / Chrome 152, target = isolated Chrome
--appwindow fully covered by the fixture app, machine idle. Every number comes from a test in this PR; the full report with methodology and reproduce commands isdocs/references/background-input-benchmarks.md.Background click and key latency, 50 cycles, benchmarked macOS 27 timing configuration ("returns" = dispatcher returned; "observed" = page reflected it, including Chromium's own processing)
sky_click, exact-oncesky_keytype_textFrontmost app unchanged in every cycle.
How the defaults were chosen (30 cycles per row;
FOCUS= gap after a synthetic focus record,SCALE= multiplier on the sky_click recipe gaps)The macOS 27 sweep showed that same-queue events can run at 0 ms on that system, but macOS 26.6.2 did not make that a safe cross-version default. Final defaults are type_text chunk 20 ms, press_key tail 100 ms, sky_key key-window settle/release 10/10 ms, focus-record gap 10 ms, and sky_click recipe scale 0.2. All six gaps remain environment-tunable.
Snapshot phases (real apps,
OPEN_COMPUTER_USE_DEBUG_TIMING=1)SLSHWCaptureWindowList(primary)Agent display
Multi-app survey (27 running GUI apps, read-only snapshot each; input only into a currently empty text field, marker removed afterwards)
cgWindowNotFound: running without a window; read-only policy does not activate themFrontmost app and pointer unchanged for both survey runs. Physical keystrokes sent while a target held synthetic key state went to the real frontmost app, not to the target.
Known boundaries
cmd+h) fail closed forsky_key/sky_click; nothing unhides on the user's behalf.agent_displayis the one mode that changes user-visible state: the display sits to the right in the arrangement (a pointer can slide into it) and the parked window is absent from the desktop until restored. It is opt-in only.Docs:
docs/references/macos-skylight-background-keyboard.md,docs/references/macos-window-visibility-and-spaces.md, plus architecture, security, reliability, skill usage, release notes, history entries and archived execution plans.