macOS menu bar app that remaps your keyboard volume and brightness keys to an external display over DDC/CI — so Media Keys control your LG (or any DDC-capable) monitor instead of the Mac speakers / built-in panel.
用 Mac 键盘音量键 / 亮度键直接控制外接显示器的硬件音量与亮度,并在菜单栏用鼠标精细调节。
从 Releases 下载最新的 LG-Rooter-*-macos-arm64.zip,解压后打开 LG Rooter.app。
首次打开: GitHub 上的下载包已用 Developer ID 签名并经 Apple 公证。解压后直接打开即可,无需右键绕过。然后在「系统设置 → 隐私与安全性 → 辅助功能」中勾选 LG Rooter。
- Media keys → monitor — Volume Up / Down / Mute and Brightness Up / Down drive the external display via DDC/CI (VCP
0x62/0x10) - Launch at login — toggle in Settings or the status-item menu; uses macOS Login Items
- 16-step keys — each press lands on the same 0…100 grid as macOS, including a true 100%
- Follow-the-finger sliders — volume and brightness tracks align; dragging writes the latest DDC value as soon as the bus is free
- Single external display — keys always drive that monitor, even if the pointer is on the built-in panel
- Hold to ramp — key-repeat starts a smooth ramp; a tap is always one step (brightness keys often omit key-up)
- Wake & hotplug recovery — I2C handles are dropped on sleep and the display map is retried after wake
- Menu bar panel — click the status item, or press ⌥⌘L, to open the same popover
- Right-click menu — panel, re-scan, launch at login, settings, and quit
- Diagnostic CLI —
lgrooter-diagfor discovery, set, and ramp stress tests
这不是内核驱动,而是用户态菜单栏应用:通过 IOKit 已暴露的 I2C 通道发送标准 DDC/CI 指令。
| Requirement | Detail |
|---|---|
| Mac | Apple Silicon (M-series) |
| OS | macOS 14+ |
| Display | DDC/CI enabled (LG OSD: DDC/CI / HDMI-DDC) |
| Cable | Direct USB-C / DisplayPort / HDMI — DisplayLink docks usually do not forward DDC |
| Permission | Accessibility (for media-key interception) |
git clone https://github.com/Linus-Shyu/LG-Rooter.git
cd LG-Rooter
make bundle # swift build + package dist/LG Rooter.app
make notarize # Developer ID + Apple notarization (local keychain profile)
open "dist/LG Rooter.app"Or step by step:
swift build -c release
./scripts/build-app.shFirst launch:
- A status-item icon appears in the menu bar
- Open Settings from the panel → grant Accessibility for LG Rooter
- Volume / brightness keys now control the external display
If no compatible display is found, the app does not intercept system media keys.
Signing tip: Accessibility grants follow the code-signing identity. Prefer a real Developer ID / Apple Development certificate so you don’t re-grant after every rebuild. The build script picks one up automatically when available.
打 v* 标签后,Release 工作流会用 GitHub Secrets 做 Developer ID 签名 + Apple 公证。日常 ci.yml 仍只做编译检查,不公证。
在仓库里配置这些 Secrets(Settings → Secrets and variables → Actions):
| Secret | 说明 |
|---|---|
MACOS_CERTIFICATE_P12_BASE64 |
Developer ID Application 证书 .p12 的 base64 |
MACOS_CERTIFICATE_PASSWORD |
导出 .p12 时设的密码 |
APPLE_API_KEY |
App Store Connect API 密钥 .p8 全文(推荐) |
APPLE_API_KEY_ID |
密钥 ID,例如 AB12CD34EF |
APPLE_API_ISSUER |
Issuer ID(UUID) |
也可以不建 API 密钥,改用本机 luma-notary 那套 Apple ID:APPLE_ID、APPLE_APP_SPECIFIC_PASSWORD、APPLE_TEAM_ID(2DZ36MCTK5)。
本机一次性导出并写入 Secrets:
# 1. 钥匙串访问 → 登录 → 我的证书 → "Developer ID Application: Faxin Xu"
# 右键导出为 .p12(设一个密码)
base64 -i ~/Desktop/DeveloperID.p12 | pbcopy
gh secret set MACOS_CERTIFICATE_P12_BASE64 # 粘贴
gh secret set MACOS_CERTIFICATE_PASSWORD # 导出时的密码
# 2. https://appstoreconnect.apple.com/access/integrations/api
# Team → App Manager 或 Admin → Generate API Key,下载 AuthKey_*.p8
gh secret set APPLE_API_KEY < ~/Downloads/AuthKey_XXXXXXXXXX.p8
gh secret set APPLE_API_KEY_ID
gh secret set APPLE_API_ISSUER之后发版只需要:
git tag v1.3.0
git push origin v1.3.0| Input | Action |
|---|---|
| Volume Up / Down / Mute | Adjust monitor speaker volume (16-step) |
| Brightness Up / Down | Adjust monitor backlight (16-step) |
| Hold a media key | Smooth accelerating ramp |
| ⌥⌘L or click status item | Toggle the control popover |
| Right-click the status item | Menu: panel · re-scan · launch at login · settings · quit |
| Sliders in the popover | Mouse fine-tune, drag to 100% |
| Settings → 登录时启动 | Start LG Rooter when you log in |
swift run lgrooter-diag
swift run lgrooter-diag --set-volume 30
swift run lgrooter-diag --set-brightness 70
swift run lgrooter-diag --ramp # stress-test write coalescingSources/
LGRooter/ # AppKit / SwiftUI menu bar app
KeyboardInterceptor.swift # 非阻塞 CGEventTap + 超时自愈
AppState.swift
LGRooterCore/ # DDC/CI + 显示器状态
DDCService.swift # I2C 传输层(串行队列)
DDCCommandQueue.swift # 90ms 节流 / latest-wins
DisplayManager.swift # 热插拔 / 唤醒 / 鼠标焦点屏
DDCTypes.swift
CIOAVService/ # C bridge for private IOAVService APIs
lgrooter-diag/ # CLI diagnostics
Bundle/Info.plist
scripts/build-app.sh
scripts/notarize-app.sh # Developer ID + notarytool + stapler
scripts/ci-import-certificate.sh # GitHub Actions: import Developer ID .p12
Monitor control does not need a kernel driver. macOS already exposes an I2C path in user space; the hard parts are the menu bar UI, media-key interception, and Accessibility permissions — AppKit / SwiftUI territory. Tools like MonitorControl and BetterDisplay take the same route. Only a DriverKit system extension would force C++.
MIT © 2026 Linus Shyu