Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

focus_here

A one-shot macOS CLI that focuses the browser window on the display you're currently working on.

On a multi-monitor Mac, the standard app switch (Cmd+Tab and friends) raises an app's last-used window — which is often on the other monitor. focus_here instead finds the target app's window on the display that currently has your focus, raises it, and brings the app to the front.

It's designed to be triggered by Karabiner-Elements via shell_command. There is no global hotkey or daemon: it runs, acts, and exits.

focus_here <bundle-id>
# e.g.
focus_here com.google.Chrome

How it works

  1. Check that the process has Accessibility (AX) permission.
  2. Determine the active display from the focused window's position (frontmost app via NSWorkspace, then its focused window via the AX API).
  3. Enumerate the target app's windows and pick the one whose center lies on the active display.
  4. AXRaise that window, set it as main, and activate the app. If no window is on the active display, just activate the app (fallback).

Display geometry comes from Core Graphics' CGDisplay, whose bounds share the same coordinate space as AX window positions (top-left origin, Y-down), so no NSScreen Y-flip is needed. Windows are classified by their center point to avoid misclassifying a window that straddles two displays.

Requirements

  • macOS (tested on macOS 26, Apple Silicon)
  • Rust 1.85+ (uses edition 2024)
  • Xcode or the Command Line Tools — axuielement ships a Swift bridge, and build.rs auto-resolves the correct Swift library search path for either setup
  • Karabiner-Elements (for hotkey triggering)

Build & install

The Accessibility grant is tied to the binary's code signature, so the binary is signed with a stable self-signed identity and a fixed identifier. This keeps the grant alive across rebuilds (a plain ad-hoc signature changes every build and loses the grant).

  1. Create the signing certificate once: Keychain Access → Certificate AssistantCreate a Certificate…

    • Name: focus_here-dev
    • Identity Type: Self Signed Root
    • Certificate Type: Code Signing
  2. Build, sign, and install:

    make install

    This runs cargo build --release, code-signs target/release/focus_here with focus_here-dev / --identifier info.izbrain.focus_here, and installs it to /usr/local/bin/focus_here. (Adjust INSTALL_PATH, SIGN_IDENTITY, and BUNDLE_ID in the Makefile if you like.)

    Verify the signature with make verify.

  3. Grant Accessibility permission once: System Settings → Privacy & Security → Accessibility → add /usr/local/bin/focus_here and enable it.

    Because the signing identity and identifier are stable, later make install rebuilds keep this grant.

Karabiner setup

Copy the bundled rule into Karabiner's assets and enable it from the UI:

cp karabiner/focus_here.json ~/.config/karabiner/assets/complex_modifications/

Then: Karabiner-Elements → Complex ModificationsAdd rule → "Focus browser on the active display".

The default rule maps Cmd+Opt+B to focus_here com.google.Chrome. shell_command runs with a minimal PATH, so the absolute path is required.

Adding more browsers / apps

Append another manipulator with a different key and bundle ID — no Rust changes needed:

{
  "type": "basic",
  "from": { "key_code": "s", "modifiers": { "mandatory": ["left_command", "left_option"] } },
  "to": [ { "shell_command": "/usr/local/bin/focus_here com.apple.Safari" } ]
}

Common bundle IDs:

Browser Bundle ID
Chrome com.google.Chrome
Safari com.apple.Safari
Arc company.thebrowser.Browser
Brave com.brave.Browser
Firefox org.mozilla.firefox

Debugging

Run with --debug to print diagnostics to stderr (permission status, every display's bounds, the detected active display, and each target window's position/size/center and mapped display) without changing focus:

focus_here --debug com.google.Chrome

Karabiner discards stdout, so when testing through a hotkey, redirect stderr:

/usr/local/bin/focus_here --debug com.google.Chrome 2>>$HOME/focus_here.log

Exit codes

Code Meaning
0 success
2 no Accessibility permission
3 target app not running
64 usage error (missing bundle id)

Project layout

Path Responsibility
src/main.rs CLI parsing, orchestration, --debug, exit codes
src/ax.rs Accessibility: trust, focused point, window raise+main
src/display.rs Core Graphics: display enumeration, point→display
src/app.rs AppKit (objc2): frontmost PID, app lookup, activate
build.rs Adds the Swift library search path for the AX bridge
Makefile build → codesign → install
karabiner/focus_here.json Karabiner complex-modification rule
docs/rust-focus-tool.md Original design brief (Japanese)

License

No license file is included yet. Add one (e.g. MIT) before sharing publicly if you want others to reuse it.

About

A one-shot macOS CLI that focuses the browser window on the display you're currently working on.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages