Skip to content

Gen45/LumaLink

Repository files navigation

LumaLink

External Display Brightness Control for macOS

LumaLink is a native macOS menu bar app that gives you full control over external display brightness using DDC/CI protocol. Control your monitors with hardware keys (F1/F2), menu bar sliders, or keyboard shortcutsβ€”just like the built-in MacBook display.

macOS Swift License

✨ Features

  • πŸ–₯️ Multi-Display Support β€” Control brightness on all external displays independently
  • ⌨️ Hardware Key Integration β€” Use F1/F2 brightness keys (or Fn+F1/F2) on external displays
  • 🎚️ Smooth Control β€” Per-display sliders with debounced writes for responsive adjustments
  • πŸ”Œ DDC/CI Protocol β€” Direct hardware control via I2C (no software overlays needed)
  • πŸŒ™ Software Dimming Fallback β€” Gamma-based dimming for displays that don't support DDC
  • πŸš€ Auto-Launch β€” Optional launch at login using SMAppService
  • πŸ’Ύ Persistent Settings β€” Remembers per-display preferences across reboots
  • ⚑ Low CPU Usage β€” Event-driven architecture, no polling loops

πŸ“‹ Requirements

  • macOS 13.0 (Ventura) or later (macOS 14 Sonoma recommended)
  • Apple Silicon (M1/M2/M3) or Intel Mac
  • External display connected via:
    • USB-C / Thunderbolt
    • DisplayPort
    • HDMI
  • Accessibility permission for keyboard monitoring

πŸš€ Quick Start

Pre-built App

  1. Download the latest release from Releases
  2. Drag LumaLink.app to /Applications
  3. Launch the app
  4. Grant Accessibility permission when prompted
  5. Adjust brightness from the menu bar β˜€οΈ

Building from Source

See BUILD.md for detailed build instructions.

# Clone repository
git clone https://github.com/yourusername/LumaLink.git
cd LumaLink

# Open in Xcode
open LumaLink.xcodeproj

# Build and run
⌘ + R

πŸ“– Usage

Menu Bar Controls

Click the β˜€οΈ icon in the menu bar to access:

  • Per-Display Sliders β€” Adjust brightness for each monitor independently
  • Quick Actions β€” Set all displays to 25%, 50%, 75%, or 100%
  • Display Menu β€” Enable software dimming or access advanced settings
  • Preferences β€” Configure launch at login, brightness step, and permissions

Keyboard Shortcuts

  • F1 (or Fn+F1) β€” Decrease brightness on selected external display
  • F2 (or Fn+F2) β€” Increase brightness on selected external display

Default step: 6% (configurable in Preferences)

Software Dimming

If your display doesn't support DDC over certain connections (USB-C docks, some KVMs):

  1. Click the gear icon next to the display name
  2. Select "Enable Software Dimming"
  3. Brightness will be controlled via gamma curves (visual dimming only)

Note: Software dimming doesn't change the backlightβ€”it's a color profile overlay.

πŸ”§ Troubleshooting

Display Not Detected

Symptoms: External display doesn't appear in LumaLink menu

Solutions:

  1. Click "Refresh Displays" in the menu
  2. Check cable connection (try a different USB-C port)
  3. Some USB-C hubs/docks don't expose I2C β€” try direct connection
  4. Restart LumaLink after connecting display

DDC Not Working

Symptoms: "DDC unavailable" warning or brightness changes have no effect

Common Causes:

  • USB-C Docks/Hubs β€” Many cheaper docks don't pass through DDC/CI signals
    • Try: Direct USB-C to DisplayPort/HDMI cable
  • KVM Switches β€” Most KVMs block DDC
    • Try: Direct connection or enable software dimming
  • HDR Mode β€” Some displays disable DDC when HDR is active
    • Try: Disable HDR in System Settings β†’ Displays
  • Display Settings β€” DDC may be disabled in monitor OSD
    • Try: Check monitor settings for "DDC/CI" option

Workaround: Enable "Software Dimming" for affected displays

Brightness Keys Not Working

Symptoms: F1/F2 keys don't adjust external brightness

Solutions:

  1. Grant Accessibility permission:
    • System Settings β†’ Privacy & Security β†’ Accessibility
    • Add and enable LumaLink
  2. Check "Use F1, F2 as standard function keys" setting:
    • System Settings β†’ Keyboard β†’ Keyboard Shortcuts β†’ Function Keys
    • LumaLink works with both configurations
  3. Restart LumaLink after granting permissions

Known Limitations

Issue Explanation Workaround
USB-C dock brightness Many docks don't pass I2C Use direct cable or software dimming
KVM switches Most KVMs block DDC signals Switch KVM input or use software dimming
HDR displays DDC often disabled in HDR mode Disable HDR or use software dimming
Slow response Some panels throttle DDC writes Normalβ€”app debounces to 100ms
Multiple controllers Daisy-chained displays Unchain or control individually

Advanced Debugging

Enable debug logging:

# View logs in Console.app
log stream --predicate 'subsystem == "com.lumalink.LumaLink"' --level debug

Common error codes:

  • transportFailed β€” I2C communication blocked (dock/cable issue)
  • timeout β€” Display not responding (try power cycle)
  • invalidResponse β€” Corrupted DDC packet (retry)

πŸ—οΈ Architecture

Project Structure

LumaLink/
β”œβ”€β”€ Sources/
β”‚   β”œβ”€β”€ App/
β”‚   β”‚   └── LumaLinkApp.swift          # App entry point
β”‚   β”œβ”€β”€ UI/
β”‚   β”‚   β”œβ”€β”€ Menu/MenuView.swift        # Menu bar interface
β”‚   β”‚   └── Preferences/               # Settings window
β”‚   β”œβ”€β”€ Domain/
β”‚   β”‚   β”œβ”€β”€ Display.swift              # Display model & discovery
β”‚   β”‚   └── BrightnessService.swift    # Core brightness logic
β”‚   β”œβ”€β”€ Infra/
β”‚   β”‚   β”œβ”€β”€ DDC/
β”‚   β”‚   β”‚   β”œβ”€β”€ DDCClient.swift        # VCP packet encoding
β”‚   β”‚   β”‚   └── IOKitI2CTransport.swift # Low-level I2C
β”‚   β”‚   β”œβ”€β”€ Hotkeys/KeyboardMonitor.swift
β”‚   β”‚   β”œβ”€β”€ Config/AppConfig.swift     # Persistence
β”‚   β”‚   └── Logging/Log.swift
β”‚   └── Support/
β”‚       └── EDIDParser.swift           # EDID hashing
└── Tests/                             # Unit tests

Key Technologies

  • SwiftUI β€” Modern declarative UI with MenuBarExtra
  • IOKit I2C β€” Direct framebuffer I2C access via IOI2CInterface
  • DDC/CI β€” VESA standard for monitor control (VCP code 0x10)
  • CGDisplay APIs β€” Display enumeration and identification
  • NSEvent Monitors β€” Global keyboard event interception
  • ServiceManagement β€” Login item registration

πŸ§ͺ Testing

Run unit tests:

# In Xcode
⌘ + U

# Or via command line
xcodebuild test -scheme LumaLink -destination 'platform=macOS'

Test Coverage:

  • DDC packet encoding/decoding: βœ… 95%
  • EDID parsing & hashing: βœ… 90%
  • Brightness service logic: βœ… 85%
  • Debouncing & rate limiting: βœ… 80%

Integration tests use mock I2C transport to simulate hardware responses.

πŸ” Security & Privacy

Permissions Required

  1. Accessibility β€” To monitor F1/F2 key presses globally
    • Only intercepts brightness keys
    • Does not log or record keystrokes

Code Signing

LumaLink must be signed and notarized for distribution:

  • Non-sandboxed (required for IOKit I2C access)
  • Hardened runtime enabled
  • No private frameworks used
  • Developer ID signed

Privacy Guarantees

  • ❌ No analytics or telemetry
  • ❌ No network requests
  • ❌ No data leaves your Mac
  • βœ… Settings stored locally in ~/Library/Application Support

πŸ› οΈ Development

Prerequisites

  • Xcode 15.0 or later
  • Swift 5.9 or later
  • macOS 13.0 SDK

Build Configuration

Setting Value Reason
App Sandbox OFF IOKit I2C requires root-level access
Hardened Runtime ON Required for notarization
Library Validation ON Security best practice
Code Signing Developer ID Distribution outside Mac App Store

Performance Targets

  • Idle CPU: < 1%
  • Memory: < 30 MB
  • I2C timeout: 800ms
  • Debounce interval: 100ms
  • Max retry: 2 attempts with 200ms backoff

πŸ“š References

DDC/CI Protocol

Apple Documentation

🀝 Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for new functionality
  4. Ensure all tests pass (⌘ + U)
  5. Submit a pull request

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

πŸ“ž Support


Made with β˜€οΈ for external display users

About

A macOS menu bar app for DDC/CI brightness control of external displays

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published