Skip to content

feat: system-wide shortcuts with desktop_system_key - #54

Merged
iamnbutler merged 2 commits into
mainfrom
feat/system-key
Oct 17, 2026
Merged

iamnbutler merged 2 commits into
mainfrom
feat/system-key

Conversation

@iamnbutler

@iamnbutler iamnbutler commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #51 (rebased onto it after #52 merged). The first commit here is #51's and drops out once #51 merges.

Some shortcuts belong to macOS, not to any window: Spotlight, Command-Tab, Mission Control, the screenshot tools, and input-source switching. desktop_key can't send them, because it is bound to one exact window. This adds a separate, explicit tool for them.

Change

  • desktop_system_key { key, modifiers? }. It takes no snapshot and no target. Keys and modifiers work as in desktop_key: named keys, or one layout character. Characters that need Shift or Option are still refused by the layout patch on the host.
  • Delivery. It uses Peekaboo's global .hotkey op, which is now in the runtime's allowedOperations.
    • Under the default synthFirst strategy, the op posts ordinary keyboard events to .cghidEventTap. They reach whatever is frontmost, as if typed.
    • The tool description and docs say this plainly, and say it usually moves focus, activates apps or opens system UI.
  • Outcome is always unknown after dispatch, with a message to observe with desktop_screen, desktop_apps or desktop_windows and not to repeat the shortcut (many toggle). Nothing reads back an effect. refused happens only before dispatch.
  • Command-W/Q/H/M stay refused, more strictly than in fix: refuse background Command-W, Q, H and M with the tool to use #49. Any chord with Command and W, Q, H or M is refused, so it can't be used to get around fix: refuse background Command-W, Q, H and M with the tool to use #49.
    • This also catches Command-Shift-Q (log out), Command-Option-Shift-Q (log out without asking), Control-Command-Q (lock screen), Command-Option-W/H/M, and so on.
    • Plain Command-X names its tool, for example "Command-W would close whatever is frontmost… Use desktop_close instead". Other chords list all four tools.
  • Locked session. The tool refuses before dispatch while the GUI session is locked (CGSSessionScreenIsLocked), like desktop_menu.
  • Old runtime. It refuses if the host's enabled operations lack .hotkey, which covers a stale /Applications runtime.
  • Code changes. serviceKey, keyboardModifiers, semanticShortcuts and ActionError in actions.swift lose private so the new systemkey.swift can reuse them. The key and modifiers schemas are shared in tools.ts.

Known limits (accepted by the lead)

  • Known limit: the Command-W/Q/H/M refusal is client-side, as in fix: refuse background Command-W, Q, H and M with the tool to use #49. The bridge accepts .hotkey only from our own signed client, so a client the host trusts can still send these chords globally.
  • If a user sets the hotkey strategy to actionFirst, Peekaboo first tries the frontmost app's menu item for the chord. For example, Command-Space could press an app menu item instead of opening Spotlight. native_outcome shows the mechanism used, and the result is unknown either way.

Verified here (dev app, DESKTOP_TOOLS_STATE=/tmp/f7/state; /Applications untouched)

  • Command-Q → refused, with a desktop_quit hint. Command-W → refused, with "would close whatever is frontmost". Command-Shift-Q and Command-Option-M → refused, with the four-tool hint. Nothing was sent.
  • Control-Up, Command-Space and ? → refused with "The macOS GUI session is locked. No key was sent." These requests passed the handshake's .hotkey allowlist check first.
  • npm run check passes, and the native build is green.

Live checks (pending: screen locked)

  • command+space → unknown; desktop_screen shows Spotlight. escape closes it.
  • command+tab → the frontmost app changes (desktop_apps).
  • control+up → Mission Control opens; escape closes it.
  • command+shift+5 → the screenshot toolbar opens; escape dismisses it. (command+shift+4 + escape too.)
  • control+space → the input source changes, if more than one is enabled. Send it again to switch back.
  • / + shift on a US layout sends ?. ? alone is refused by the host, with the hint to use / with shift.
  • native_outcome reports globalEvents/foreground delivery.

🤖 Generated with Claude Code

iamnbutler and others added 2 commits October 16, 2026 22:56
desktop_key refused every snapshot without a unique observed focused
control, so Escape, arrows, Return, Space and shortcuts in Finder lists,
outlines, tables, canvases and web areas could not be sent (#13).

Without a focused-control receipt the key now uses the exact-window
hotkey with no expected element. Before each event the host still
requires the app's focused element to lie inside the exact window and
that window to be the app's key window with no attached sheet, with the
same process generation and bounds. The result's receiver says which
binding was used: observed_control or window_focus. desktop_insert
still needs an observed text control.

Closes #13

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@iamnbutler
iamnbutler merged commit 4aa2609 into main Oct 17, 2026
2 checks passed
@iamnbutler
iamnbutler deleted the feat/system-key branch October 17, 2026 03:07
@iamnbutler iamnbutler mentioned this pull request Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant