Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Atlas Monitors

Banner Image

atlas.monitors controls your monitors over DDC/CI — the channel the display already uses to talk to your computer. Brightness, contrast, input source, volume, power and any raw VCP feature, from a single command or an interactive TUI. Part of the Atlas Suite.

Go Version Platform

✨ Features

  • 🎚️ Every VCP feature: Named shortcuts for the common ones, raw hex codes for the rest.
  • ⌨️ Two modes: A full TUI when you run it bare, single commands when you don't.
  • Relative and toggle: brightness +10, input --toggle hdmi1,dp1 — made for hotkeys.
  • 🛡️ Capability-aware: Values are checked against what the monitor actually declares, so an unsupported input fails with an explanation instead of being silently ignored.
  • 💾 Profiles: Save a whole multi-monitor setup and switch back to it in one command.
  • 🤖 Scriptable: --json on every command, and an exit code that reflects partial failure.
  • 📦 Cross-platform: Windows and Apple Silicon macOS, with no cgo.

🚀 Installation

From Source

git clone https://github.com/fezcode/atlas.monitors
cd atlas.monitors
gobake build

Binaries land in build/. go build -o atlas.monitors . also works if you would rather not use gobake.

⌨️ Usage

Run it with no arguments for the interactive TUI:

atlas.monitors

Or give it a command and it does one thing and exits:

# What is connected?
atlas.monitors list

# Read
atlas.monitors brightness
atlas.monitors get contrast
atlas.monitors get 0x10

# Write
atlas.monitors brightness 40
atlas.monitors brightness +10          # every monitor, relative to its own value
atlas.monitors brightness 60% -m 2     # monitor 2 only
atlas.monitors set 0xE5 1              # any raw VCP code

# Inputs
atlas.monitors input
atlas.monitors input hdmi1
atlas.monitors input --toggle hdmi1,dp1

Output is a plain aligned table, made to be piped:

$ atlas.monitors list
#  MODEL          DESCRIPTION          DEVICE
1  GR93U          Generic PnP Monitor  \\.\DISPLAY1
2  OMEN by HP 27  Generic PnP Monitor  \\.\DISPLAY2

$ atlas.monitors brightness -5
#  MONITOR        FEATURE     VALUE
1  GR93U          brightness  82 -> 77
2  OMEN by HP 27  brightness  50 -> 45

The model name comes from the monitor's own capability string. Windows reports almost every display as "Generic PnP Monitor", which is no use for telling two apart.

Values are checked before anything is written, and the error says what the monitor will actually take:

$ atlas.monitors input composite1
#  MONITOR  FEATURE  VALUE
1  GR93U    input    error: GR93U does not accept input = 5 (0x05); it reports
                     hdmi1 (0x11), hdmi2 (0x12), dp1 (0x0F), dp2 (0x10)

Choosing monitors

-m / --monitor takes an index, part of a model name, or all. The default is all, because dimming every screen at once is the usual intent.

atlas.monitors brightness 30 -m 2
atlas.monitors brightness 30 -m dell
atlas.monitors brightness 30 -m all

Profiles

atlas.monitors profile save night
atlas.monitors profile apply night
atlas.monitors profile list
atlas.monitors profile show night
atlas.monitors profile delete night

A profile captures brightness, contrast, volume, input and colour for every monitor it was saved from. Applying one matches monitors by identity, falling back to index, so it survives a reboot that reshuffled enumeration order.

Scripting

atlas.monitors get brightness --json
[
  {
    "monitor": { "index": 1, "model": "GR93U", "device": "\\\\.\\DISPLAY1" },
    "feature": { "code": 16, "hex": "0x10", "name": "brightness", "kind": "continuous" },
    "value": 80,
    "max": 100,
    "ok": true
  }
]

Exit codes: 0 success, 1 at least one monitor failed, 2 the command line was wrong. Every targeted monitor produces a row whether it succeeded or not, so a partial failure is visible rather than silent.

Discovering what your monitor supports

atlas.monitors caps     # what this monitor declares
atlas.monitors codes    # every feature this tool knows by name

caps is the authority. If a feature is not listed there, setting it will be refused before anything is written.

🖥️ Interactive mode

Run with no arguments. Real output, two monitors:

ATLAS.MONITORS v0.1.0                                                         2 monitor(s)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
① DISPLAYS
──────────────────────────────────────────────────────────────────────────────────────────
▸ 1  GR93U                        \\.\DISPLAY1
    brightness         ████████████████████░░░░  82 / 100
    contrast           ████████████████████░░░░  82 / 100
    input              dp1

  2  OMEN by HP 27                \\.\DISPLAY2
    brightness         ████████████░░░░░░░░░░░░  50 / 100
    contrast           ████████████████████░░░░ 100 / 120

──────────────────────────────────────────────────────────────────────────────────────────
↑↓ select  ·  ←→ brightness  ·  ↵ features  ·  p profiles  ·  r refresh  ·  ? help  ·  q quit

Press on a monitor for everything it supports:

② FEATURES
──────────────────────────────────────────────────────────────────────────────────────────
  1  GR93U   MCCS 2.1

▸ brightness         ████████████████████░░░░  82 / 100
  contrast           ████████████████████░░░░  82 / 100
  input              dp1 → hdmi1  ·  [hdmi1] hdmi2 •dp1  dp2   ↵ apply
  volume             ████████████████████████ 100 / 100
  power              on
  color-preset       user1
  red-gain           ████████████░░░░░░░░░░░░  50 / 100
──────────────────────────────────────────────────────────────────────────────────────────
↑↓ feature  ·  ←→ adjust / choose  ·  ↵ apply  ·  ⇧←→ by 10  ·  tab next monitor  ·  esc back
Key Action
↑ ↓ / j k Select a monitor, or a feature in the detail view
← → Adjust by 1 (brightness, contrast…) or choose a value (input, power…)
Shift + ← → Adjust by 10
Apply the chosen value
/ l On the dashboard, open the monitor's features
esc / h Cancel a choice, or go back
tab Next monitor
p Profiles — applies, s saves, d deletes
r Re-read every monitor
? Help
q Quit

On the dashboard, ← → adjusts brightness directly.

Continuous features (brightness, contrast, volume) apply as you press, so you see the panel respond. Features with fixed values (input, power) work differently: ← → moves through the values the monitor declares and shows the change it would make, and nothing is written until confirms it. A stray keypress cannot switch away the screen you are looking at.

A DDC write takes around 60ms, far slower than key repeat, so writes are coalesced: one is in flight at a time and the newest value wins. Holding an arrow key tracks smoothly instead of queueing up seconds of writes.

🔎 Value forms

Form Meaning
40 Absolute
0x11 Absolute, hex
+10 / -10 Relative, clamped to the monitor's range
60% Percentage of maximum (continuous features only)
hdmi1 A named value — see atlas.monitors codes

📂 Configuration

~/.atlas/monitors.json        profiles
~/.atlas/monitors-caps.json   capability-string cache

Reading a capability string costs up to two seconds per monitor, so it is cached. Pass --refresh to re-read it.

⚠️ Notes

  • DDC/CI must be enabled in the monitor's own OSD menu. Many monitors ship with it off.
  • Laptop built-in panels do not support DDC/CI. Only external displays do.
  • Some KVMs, docks and adapters do not pass DDC/CI through.
  • Switching input can black out your screen. If you switch a monitor to an input this computer is not on, switching back has to happen from the monitor's own buttons.
  • DDC/CI is inherently flaky. Every read and write is retried before being reported failed.

🛠️ Platform support

Platform Status
Windows Monitor Configuration API (dxva2.dll), no elevation needed
macOS (Apple Silicon) IOKit IOAVService over raw I2C, reached via purego
macOS (Intel) Not supported — needs the legacy IOFramebuffer path
Linux Not supported — builds and reports so

CGO is off on every target, so cross-compiled binaries are fully functional.

The macOS backend uses a private, undocumented Apple API — the same one m1ddc and BetterDisplay rely on. It can break on a macOS update.

📄 License

MIT

About

Control your monitors over DDC/CI from the command line — brightness, contrast, input, volume, power and any raw VCP feature. Interactive TUI or single commands. Part of the Atlas Suite.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages