Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

CI Release License: MIT macOS 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 · 系统要求

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)

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_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_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 · 使用

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

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