Flip a DDC-capable external monitor between two or more Macs sharing
it. Type dw in Raycast and the monitor switches.
dw # toggle (with 2 devices) or list (with 3+)
dw <device> # explicit switch (e.g. dw mac-mini)
dw init # interactive setup on the first Mac
dw add <name> <input> # add a new device to the config
dw remove <name> # drop a device
dw use <name> # change which device THIS Mac is
dw share # generate one-paste install commands for other Macs
dw setup raycast # register per-device commands in Raycast
dw reset # wipe config + generated bindings (start fresh)
dw status # show config
dw list # list displays + show config
The repo is named
desk-switch. The binary you run isdw.
Every modern external monitor exposes a side-channel called DDC/CI over
the video cable. The OS can use it to change brightness, volume, and the
input source without touching the monitor's physical buttons. dw wraps
m1ddc — a small CLI that speaks
DDC/CI on Apple Silicon — to write the input source VCP code.
You configure all your devices once on a "main" Mac, then dw share prints
a one-paste install command for each other Mac. Each device knows its own
identity (this_device) and the full map of devices and their input codes,
so any dw <name> call switches the monitor instantly.
- Apple Silicon Mac (M1 / M2 / M3 / M4) on macOS 12+
- A DDC-capable external monitor (most modern monitors are; built-in HDMI on entry-level M1 / base M2 Macs is not DDC-capable — use USB‑C or Thunderbolt instead)
- Homebrew
- Raycast (for the hotkey UI)
curl -fsSL https://raw.githubusercontent.com/thrcrt/desk-switch/main/install.sh | bash
dw initThat's it. The installer is idempotent and:
- verifies Apple Silicon macOS,
- installs
m1ddcandjqvia Homebrew (skipped if already present), - clones the repo to
~/.local/share/dw(override withDW_INSTALL_DIR), - symlinks
dwonto your PATH, preferring/opt/homebrew/bin.
After install, dw is callable from anywhere — no need to be in any
specific directory. If you prefer to clone the repo manually somewhere,
that still works: just run ./install.sh from inside the checkout.
dw init walks you through:
- Which display number to control (usually
1) - How many devices share this monitor
- Each device's name + VCP input code
- Which device THIS Mac is
Standard VCP codes:
| Code | Input |
|---|---|
| 15 | DisplayPort 1 |
| 16 | DisplayPort 2 |
| 17 | HDMI 1 |
| 18 | HDMI 2 |
| 27 | USB‑C |
Config goes to ~/.config/dw/config.json.
On the main Mac (after dw init):
$ dw share
## On 'macmini':
bash <(curl -fsSL https://raw.githubusercontent.com/.../bootstrap.sh) \
--this macmini --devices "macbook=27,macmini=17,work=15"Paste the matching command on each other Mac. bootstrap.sh clones the
repo, runs install.sh, writes the config, and (if Raycast is installed)
generates the per-device Raycast script commands. After it finishes, that
Mac is ready — no init wizard.
dw setup raycast generates one Raycast script command per device into
~/Documents/dw/raycast/. Each script gets a dw → <Device> title and a
🖥 icon. Nothing is uploaded; nothing leaves your Mac.
One-time setup — Raycast has no API for adding a Script Directory, so this single click is unavoidable:
- Run
dw setup raycast— opens Raycast. - Raycast Settings (⌘,) → Extensions → Script Commands →
+→ Add Script Directory. - In the file picker, navigate to Documents → dw → raycast and click Open.
After this one-time step, every dw add, dw remove, or dw setup raycast
regenerates the scripts in place and Raycast picks them up automatically —
no more clicking, ever.
In Raycast: type dw and autocomplete lists every device.
dw reset # interactive: shows what'll be removed, asks to confirm
dw reset --yes # skip confirmationdw reset removes:
~/.config/dw/(the device config)~/Documents/dw/raycast/(generated Raycast script commands)
It does not touch:
- the
dwbinary or its symlink — use./uninstall.shfor that - Homebrew deps (
m1ddc,jq) - the Raycast "Add Script Directory" entry inside Raycast Settings (the
directory will just be empty until you re-run
dw setup raycast)
After a reset, run dw init to set up fresh — or, on a secondary Mac,
paste the matching dw share line from your main Mac.
m1ddc could not write input— Wrong display selector, or the monitor doesn't support DDC input switching. Rundw listto see whatm1ddcdetects, and confirm withm1ddc display 1 get luminancethat DDC reads work for that display.- Switches to the wrong input — Re-run
dw init(or usedw remove <name>+dw add <name> <new-code>). - Monitor goes dark with no signal — You wrote a code for an unused input. Recover with the monitor's joystick, then fix the config.
MIT — see LICENSE.