Repository navigation
Design: display control surface for smctl #15
Copy link
Copy link
Open
Description
Problem
External displays are part of System Control, but macOS exposes weak hardware control for third-party monitors. Users need scriptable brightness, contrast, volume, input switching, and a reliable way to diagnose why control is unavailable.
BetterDisplay already owns the broad GUI/display-experience space. smctl should not clone BetterDisplay. The useful smctl scope is external-display hardware control plus CLI-first diagnostics.
Research PR: #14
Research doc: docs/research-display-control.md
Proposed scope
Start with a read-only surface:
smctl display list --jsonsmctl display statussmctl display edid --display <id>smctl display capabilities --display <id>smctl display doctor
Then add safe hardware controls:
smctl display brightness get/set --display <id>smctl display contrast get/set --display <id>smctl display volume get/set --display <id>smctl display input list/get/set --display <id>
Non-goals
- BetterDisplay clone
- GUI-first display settings app
- virtual displays
- PIP/PBP/KVM
- custom EDID or EDID override
- HDR/XDR extra brightness
- display mode/resolution writes in the first implementation
- silently falling back from hardware brightness to software dimming
Design requirements
- Enumerate displays with stable identity, not only display name.
- Combine CoreGraphics state, IOKit/IODisplay identity, EDID hash, and DDC capability results.
- Report a DDC capability matrix before exposing writes.
- Distinguish unsupported, blocked, timeout, broken-read, unverified-write, and verified-write states.
- Map common input names like
hdmi1,hdmi2,dp1,dp2, andusb_c, while allowing per-display aliases. - Avoid default writes to an ambiguous display when multiple external monitors are connected.
- Keep software dimming visibly separate from hardware brightness.
- Decide whether DDC read/write belongs in the CLI process, the daemon, or a split model.
Open questions
- Should the first implementation be Apple Silicon only, or should Intel be included if DDC transport is portable?
- Which Swift DDC transport path is most stable on current macOS?
- How should smctl identify Apple Studio Display, LG UltraFine, built-in panels, and other native/Apple-protocol displays?
- What should
--no-verifymean for displays that apply writes but return unreliable MCCS data? - Where should display aliases live:
/etc/smctl/config.toml, per-user config, or both? - Should compatibility reporting exist, and if so how does it stay default-off and privacy-preserving?
Acceptance criteria for the design pass
- A command contract for V0 read-only inventory and doctor output.
- A JSON schema sketch for display identity, EDID, transport, and DDC capability state.
- A decision on CLI vs daemon ownership for DDC probing and writes.
- A safety model for write verification and degraded states.
- A small hardware test matrix that covers direct USB-C/DisplayPort, HDMI, docked monitors, DisplayLink, and at least one unsupported display path.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
leaperone-bot commentedon Jun 23, 2026
技术评估如下:
结论
Issue #15 是一个新功能 / 设计阶段请求,不是 bug。目标是为
smctl增加外接显示器硬件控制面:先做只读 inventory / diagnostics,再逐步开放 DDC/CI 硬件亮度、对比度、音量、输入源切换。需求对“设计 pass”来说足够清晰;但还不适合直接进入完整实现,因为 DDC transport、CLI/daemon 边界、显示器身份模型、Apple/native display 分类仍需先定案并用硬件验证。
当前代码架构观察
仓库目前是 Swift 6 / macOS 14+ 的 SPM 项目,主要模块:
Sources/SMCCore:SMC IOKit 通信、capability probing、verified write。Sources/PolicyEngine:风扇 / 电池策略逻辑。Sources/SMCtlProtocol:XPC DTO / 协议。Sources/SMCtlDaemonCore:root daemon、配置、写入授权、安全恢复。Sources/smctl/main.swift:CLI,使用swift-argument-parser。Sources/smctld/main.swift:daemon entrypoint。目前没有任何 display / DDC / EDID / CoreGraphics 相关实现。
docs/research-display-control.md只存在于 PR #14,尚未合入 main。功能范围
建议拆成两阶段:
V0:只读面
实现:
smctl display list --jsonsmctl display statussmctl display edid --display <id>smctl display capabilities --display <id>smctl display doctor重点是建立事实层:
V1:安全写入
再开放:
get/setget/setget/setlist/get/set对应 MCCS/VCP:
0x10brightness0x12contrast0x62volume0x60input source不应在第一版做:GUI、虚拟屏、HDR/XDR 增亮、EDID override、系统分辨率写入、PIP/PBP/KVM、软件调暗伪装成硬件亮度。
受影响文件 / 模块
建议新增而不是塞进
SMCCore,因为显示器控制不是 SMC:Package.swiftDisplayCoretarget。CoreGraphics、IOKit,必要时ApplicationServices。Sources/DisplayCore/DisplayInventory.swiftDisplayIdentity.swiftEDID.swiftIODisplayBridge.swiftDDCTransport.swiftMCCS.swiftDisplayDoctor.swiftSources/smctl/main.swiftDisplaycommand group。Sources/SMCtlProtocol/SMCtlProtocol.swiftSources/SMCtlDaemonCore/Daemon.swiftdocs/design.mddocs/research-display-control.mdTests/DisplayCoreTests/Tests/smctlTests/建议实现路线
DisplayCore,先做纯只读 inventory:CGGetOnlineDisplayListCGGetActiveDisplayListedidHashvendorID、productID、serialcgDisplayID0x10/0x12/0x62/0x60supported、unsupported、blocked、timeout、broken-read、unverifieddisplay doctor:--display--no-verify只能输出 degraded / unverified 状态,不能假装成功。CLI vs daemon 建议
建议采用分层 / split model:
DisplayCore放通用实现。如果项目坚持“所有硬件写入必须经 daemon”,需要先验证:
JSON schema 草案方向
V0
display list --json应至少包含:{ "id": "dell-u2723qe-a1b2", "name": "DELL U2723QE", "identity": { "vendorID": 1234, "productID": 5678, "serial": "ABC123", "edidHash": "sha256:...", "ioRegistryPath": "..." }, "coreGraphics": { "cgDisplayID": 1, "online": true, "active": true, "main": false, "mirrored": false, "bounds": { "x": 0, "y": 0, "width": 3840, "height": 2160 }, "refreshRate": 60, "rotation": 0 }, "transport": { "kind": "usb_c", "confidence": "inferred" }, "ddc": { "state": "supported", "capabilitiesRead": true, "controls": { "brightness": { "vcp": "0x10", "read": "ok", "write": "available" }, "contrast": { "vcp": "0x12", "read": "ok", "write": "available" }, "volume": { "vcp": "0x62", "read": "unsupported", "write": "unavailable" }, "input": { "vcp": "0x60", "read": "ok", "write": "available" } } } }复杂度评估
主要难点不在 CLI 命令,而在 macOS DDC transport 稳定性、硬件差异、失败状态建模、身份稳定性、多显示器歧义处理。
风险 / 未决问题
--no-verify语义:只能表示 write sent but unverified,脚本输出必须可区分。/etc/smctl/config.toml适合共享机器策略;per-user config 更适合个人显示器命名。设计需同时预留。建议下一步
先把本 issue 收敛为设计产出,不直接实现写入:
docs/design-display-control.md。DisplayCore inventory + smctl display list/status/doctor。