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
- Check that the process has Accessibility (AX) permission.
- Determine the active display from the focused window's position
(frontmost app via
NSWorkspace, then its focused window via the AX API). - Enumerate the target app's windows and pick the one whose center lies on the active display.
AXRaisethat window, set it as main, andactivatethe 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.
- macOS (tested on macOS 26, Apple Silicon)
- Rust 1.85+ (uses edition 2024)
- Xcode or the Command Line Tools —
axuielementships a Swift bridge, andbuild.rsauto-resolves the correct Swift library search path for either setup - Karabiner-Elements (for hotkey triggering)
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).
-
Create the signing certificate once: Keychain Access → Certificate Assistant → Create a Certificate…
- Name:
focus_here-dev - Identity Type: Self Signed Root
- Certificate Type: Code Signing
- Name:
-
Build, sign, and install:
make install
This runs
cargo build --release, code-signstarget/release/focus_herewithfocus_here-dev/--identifier info.izbrain.focus_here, and installs it to/usr/local/bin/focus_here. (AdjustINSTALL_PATH,SIGN_IDENTITY, andBUNDLE_IDin theMakefileif you like.)Verify the signature with
make verify. -
Grant Accessibility permission once: System Settings → Privacy & Security → Accessibility → add
/usr/local/bin/focus_hereand enable it.Because the signing identity and identifier are stable, later
make installrebuilds keep this grant.
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 Modifications → Add 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.
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 |
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.ChromeKarabiner discards stdout, so when testing through a hotkey, redirect stderr:
/usr/local/bin/focus_here --debug com.google.Chrome 2>>$HOME/focus_here.log
| Code | Meaning |
|---|---|
| 0 | success |
| 2 | no Accessibility permission |
| 3 | target app not running |
| 64 | usage error (missing bundle id) |
| 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) |
No license file is included yet. Add one (e.g. MIT) before sharing publicly if you want others to reuse it.