External monitors don’t expose a brightness interface to the OS the same way laptop panels do, so the standard brightness keys do nothing. The fix is ddcutil, which speaks the DDC/CI protocol over i2c directly to the monitor’s firmware.
I’m running Omarchy (Arch + Hyprland), which ships SwayOSD for on-screen indicators and includes a helper script omarchy-swayosd-brightness that drives it.
Find your i2c buses
sudo ddcutil detect
Each detected monitor will show its i2c bus number. On my triple-monitor setup they came up as buses 7, 8, and 9.
The script
Save this as ~/.local/bin/hdmi_brightness.sh and make it executable (chmod +x).
#!/usr/bin/env bash
# usage: hdmi_brightness.sh up|down|set <value>
BDEVS=(7 8 9) # i2c buses for your 3 monitors
STEP=5 # step size in percent
cmd="$1"
val="$2"
for bus in "${BDEVS[@]}"; do
case "$cmd" in
up)
ddcutil setvcp 10 + "$STEP" --bus "$bus"
;;
down)
ddcutil setvcp 10 - "$STEP" --bus "$bus"
;;
set)
ddcutil setvcp 10 "$val" --bus "$bus"
;;
esac
done
current_brightness=$(ddcutil getvcp 10 --bus "${bus}" 2>/dev/null | awk -F'current value =|,' '/current value/ {gsub(/ /,"",$2); print $2}')
omarchy-swayosd-brightness ${current_brightness}
VCP code 10 is the standard DDC/CI feature code for brightness. After applying the change, the script reads back the current value from one monitor and passes it to omarchy-swayosd-brightness so SwayOSD shows the indicator on screen.
Update BDEVS to match the bus numbers from ddcutil detect on your machine.
Hyprland keybindings
Add these to your Hyprland config (e.g. ~/.config/hypr/hyprland.conf):
Omarchy already binds XF86MonBrightnessUp and XF86MonBrightnessDown for laptop panel brightness. Without the unbind, both the old and new bindings fire — I noticed the SwayOSD indicator was appearing twice per keypress, which was the giveaway. Unbind first, then rebind to the ddcutil script.
unbind = , XF86MonBrightnessUp
unbind = , XF86MonBrightnessDown
bind = , XF86MonBrightnessUp, exec, ~/.local/bin/hdmi_brightness.sh up
bind = , XF86MonBrightnessDown, exec, ~/.local/bin/hdmi_brightness.sh down
If your keyboard doesn’t have dedicated brightness keys, use a custom combo instead:
bind = SUPER, F2, exec, ~/.local/bin/hdmi_brightness.sh down
bind = SUPER, F3, exec, ~/.local/bin/hdmi_brightness.sh up
Reload Hyprland (hyprctl reload) and the keys should immediately control all three monitors in sync, with a SwayOSD brightness bar on screen.