Skip to content

Repository files navigation

LG Rooter

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 键盘音量键 / 亮度键直接控制外接显示器的硬件音量与亮度,并在菜单栏用鼠标精细调节。

CIReleaseLicense: MITmacOS 14+Apple Silicon

Download · 下载

Releases 下载最新的 LG-Rooter-*-macos-arm64.zip,解压后打开 LG Rooter.app

首次打开: GitHub 上的下载包已用 Developer ID 签名并经 Apple 公证。解压后直接打开即可,无需右键绕过。然后在「系统设置 → 隐私与安全性 → 辅助功能」中勾选 LG Rooter。

Features · 功能

  • 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 CLIlgrooter-diag for discovery, set, and ramp stress tests

这不是内核驱动,而是用户态菜单栏应用:通过 IOKit 已暴露的 I2C 通道发送标准 DDC/CI 指令。

Requirements · 系统要求

RequirementDetail
MacApple Silicon (M-series)
OSmacOS 14+
DisplayDDC/CI enabled (LG OSD: DDC/CI / HDMI-DDC)
CableDirect USB-C / DisplayPort / HDMI — DisplayLink docks usually do not forward DDC
PermissionAccessibility (for media-key interception)

Build · 构建

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.sh

First launch:

  1. A status-item icon appears in the menu bar
  2. Open Settings from the panel → grant Accessibility for LG Rooter
  3. 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.

CI signing · 流水线签名

v* 标签后,Release 工作流会用 GitHub Secrets 做 Developer ID 签名 + Apple 公证。日常 ci.yml 仍只做编译检查,不公证。

在仓库里配置这些 Secrets(Settings → Secrets and variables → Actions):

Secret说明
MACOS_CERTIFICATE_P12_BASE64Developer ID Application 证书 .p12 的 base64
MACOS_CERTIFICATE_PASSWORD导出 .p12 时设的密码
APPLE_API_KEYApp Store Connect API 密钥 .p8 全文(推荐)
APPLE_API_KEY_ID密钥 ID,例如 AB12CD34EF
APPLE_API_ISSUERIssuer ID(UUID)

也可以不建 API 密钥,改用本机 luma-notary 那套 Apple ID:APPLE_IDAPPLE_APP_SPECIFIC_PASSWORDAPPLE_TEAM_ID2DZ36MCTK5)。

本机一次性导出并写入 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

Usage · 使用

InputAction
Volume Up / Down / MuteAdjust monitor speaker volume (16-step)
Brightness Up / DownAdjust monitor backlight (16-step)
Hold a media keySmooth accelerating ramp
⌥⌘L or click status itemToggle the control popover
Right-click the status itemMenu: panel · re-scan · launch at login · settings · quit
Sliders in the popoverMouse fine-tune, drag to 100%
Settings → 登录时启动Start LG Rooter when you log in

Diagnostic tool

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 coalescing

Project layout · 结构

Sources/
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

Why Swift (not C++) · 为什么是 Swift

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++.

License

MIT © 2026 Linus Shyu

About

macOS menu bar app: remap volume & brightness keys to external displays over DDC/CI (Apple Silicon)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages