Rebase to flake parts #6
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# DDC/CI helper + i2c-dev + ddcutil (implementation under `package/`).
|
||||
{ ... }: {
|
||||
flake.nixosModules.systemMonitorInput =
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.chiasson.system.monitorInput;
|
||||
monitorInputPkg = pkgs.callPackage ./package { };
|
||||
in
|
||||
{
|
||||
options.chiasson.system.monitorInput.enable = lib.mkEnableOption ''
|
||||
`i2c-dev`, ddcutil, and `monitor-input` for DDC/CI input switching.
|
||||
'';
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
boot.kernelModules = [ "i2c-dev" ];
|
||||
environment.systemPackages = [
|
||||
pkgs.ddcutil
|
||||
monitorInputPkg
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# DDC/CI monitor input control: list displays, get/set input by bus or name.
|
||||
{ pkgs }:
|
||||
let
|
||||
script = builtins.readFile ./monitor-input.sh;
|
||||
unwrapped = pkgs.writeShellScriptBin "monitor-input" script;
|
||||
in
|
||||
pkgs.runCommand "monitor-input" { nativeBuildInputs = [ pkgs.makeWrapper ]; } ''
|
||||
mkdir -p $out/bin
|
||||
cp ${unwrapped}/bin/monitor-input $out/bin/monitor-input
|
||||
chmod +x $out/bin/monitor-input
|
||||
wrapProgram $out/bin/monitor-input --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.ddcutil ]}
|
||||
''
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
VCP_INPUT=0x60
|
||||
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/monitor-input"
|
||||
CACHE_FILE="$CACHE_DIR/displays"
|
||||
CACHE_TTL=60
|
||||
|
||||
# Output one line per DDC-capable display: BUS MODEL MFG (from ddcutil detect, cached for CACHE_TTL seconds).
|
||||
list_ddc_displays() {
|
||||
mkdir -p "$CACHE_DIR"
|
||||
local now ts
|
||||
now=$(date +%s)
|
||||
ts=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0)
|
||||
if [[ -s "$CACHE_FILE" ]] && (( ts + CACHE_TTL > now )); then
|
||||
cat "$CACHE_FILE"
|
||||
return
|
||||
fi
|
||||
ddcutil detect 2>/dev/null | awk '
|
||||
/^Display [0-9]+$/ { bus=""; model=""; mfg=""; next }
|
||||
/^Invalid display|^ DDC communication failed/ { next }
|
||||
/^ I2C bus:/ { if (match($0, /i2c-[0-9]+/)) bus=substr($0, RSTART+4, RLENGTH-4); next }
|
||||
/^ Mfg id:[[:space:]]+/ { mfg=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", mfg); next }
|
||||
/^ Model:[[:space:]]+/ { model=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", model); next }
|
||||
/^ VCP version:/ { if (bus != "") print bus "\t" model "\t" mfg }
|
||||
' | tee "$CACHE_FILE"
|
||||
}
|
||||
|
||||
# Resolve DISP (bus number or name substring) to bus number. Exits 1 if not found or ambiguous.
|
||||
# When DISP is numeric, use it directly (no slow ddcutil detect).
|
||||
resolve_display() {
|
||||
local disp="$1"
|
||||
if [[ "$disp" =~ ^[0-9]+$ ]]; then
|
||||
echo "$disp"
|
||||
return 0
|
||||
fi
|
||||
local bus r
|
||||
bus=$(list_ddc_displays | awk -v disp="$disp" '
|
||||
BEGIN { d = tolower(disp); found = 0 }
|
||||
{
|
||||
if (index(tolower($2), d) || index(tolower($3), d)) {
|
||||
if (found) exit 2
|
||||
found = $1
|
||||
}
|
||||
}
|
||||
END { if (found) print found; exit (found ? 0 : 1) }
|
||||
')
|
||||
r=$?
|
||||
[[ $r -eq 2 ]] && { echo "monitor-input: '$disp' matches multiple displays (use bus number)" >&2; return 1; }
|
||||
[[ $r -eq 0 && -n "$bus" ]] || { echo "monitor-input: no DDC display matching '$disp'" >&2; return 1; }
|
||||
echo "$bus"
|
||||
}
|
||||
|
||||
# Map input name to VCP 0x60 value (common assignments; use hex for others).
|
||||
input_to_hex() {
|
||||
case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
|
||||
dp|dp1) echo "0x0f" ;;
|
||||
dp2) echo "0x10" ;;
|
||||
hdmi|hdmi1) echo "0x11" ;;
|
||||
hdmi2) echo "0x12" ;;
|
||||
0x*) echo "$1" ;;
|
||||
*) echo "monitor-input: unknown input '$1' (use dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN)" >&2; return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
list)
|
||||
echo "Bus Model Mfg"
|
||||
list_ddc_displays
|
||||
;;
|
||||
*)
|
||||
[[ -n "${1:-}" ]] || { echo "Usage: monitor-input list | monitor-input <display> get|set [input]" >&2; exit 1; }
|
||||
case "${2:-}" in
|
||||
get)
|
||||
bus=$(resolve_display "$1") || exit 1
|
||||
exec ddcutil --bus "$bus" getvcp "$VCP_INPUT"
|
||||
;;
|
||||
set)
|
||||
[[ -n "${3:-}" ]] || { echo "Usage: monitor-input <display> set <input>" >&2; exit 1; }
|
||||
bus=$(resolve_display "$1") || exit 1
|
||||
hex=$(input_to_hex "$3") || exit 1
|
||||
exec ddcutil --bus "$bus" setvcp "$VCP_INPUT" "$hex"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: monitor-input list" >&2
|
||||
echo " monitor-input <display> get" >&2
|
||||
echo " monitor-input <display> set <input>" >&2
|
||||
echo " display: bus number (e.g. 23) or name match (e.g. benq, zowie, lg, 34GL750)" >&2
|
||||
echo " input: dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user