macOS · CLI + Menu Bar

LED ON · NOISE CANCELLATION

Simulated — click the key. The real app moves your actual AirPods.

Caps Lock now controls your AirPods.

AirCaps remaps the physical Caps Lock key into a hardware switch for noise mode. LED on is Noise Cancellation. LED off is Adaptive or Transparency, your call — synced across the built-in keyboard and every Magic Keyboard on your desk.

Mechanism

Four steps happen before the LED moves.

  1. 01

    Remap

    hidutil turns Caps Lock into a no-op, system-wide, the moment the app launches. Text-input locking stops. So does the OS auto-driving the LED — nothing else is watching it anymore.

  2. 02

    Listen

    IOHIDManager watches for the key's raw down-transition anyway, underneath the remap, on every matched keyboard — built-in and every connected Magic Keyboard.

  3. 03

    Automate

    Accessibility drives Control Center's Sound popover: press Sound, wait for the dialog, expand the AirPods section, press the target mode's checkbox.

  4. 04

    Illuminate

    IOHIDDeviceSetValue writes the Caps Lock LED element directly, on every connected keyboard at once. The app owns the light now — it has to.

Internals

Eight things worth knowing.

HID

Raw HID capture

Reads keyboard input reports directly — independent of, and unaffected by, the hidutil remap sitting above it.

AX

Control Center automation

No private API left to call, so it drives the same Sound popover a person would click through by hand.

N·KB

Multi-keyboard sync

LED state applies to every matched device at once. A keyboard that connects mid-session gets synced and remapped immediately.

TCC

Two-permission gate

Accessibility for the popover, Input Monitoring for raw HID. Both re-checked every time the menu opens.

LED

Explicit LED ownership

Once the remap is live, macOS stops driving the light entirely. Every state change is a direct write.

SPM

One shared core

Audio, Bluetooth, battery, and noise control live in a library that powers both the CLI and the menu-bar app.

DBC

Debounced state machine

Only idle or transitioning. A press mid-transition is dropped, not queued — the popover flow can't overlap itself.

CA

CoreAudio switching

The same menu flips default and system output device between AirPods and built-in speakers.

Reference

The usage IDs this app touches.

Three HID usage IDs, one remap, and the three checkbox labels inside Control Center's Sound popover — that's the entire vocabulary.

HID usage table

PageUsageMeaningRole
0x010x06Generic Desktop → KeyboardMatches every connected keyboard
0x070x39Keyboard/Keypad → Caps LockThe physical key being watched
0x080x02LEDs → Caps Lock indicatorThe light being written

Noise modes

CodeControl Center labelLED state
ANCNoise CancellationOn
ATAdaptiveOff — default
TRTransparencyOff — alternate

The remap, verbatim

hidutil property --set '{"UserKeyMapping":[{
  "HIDKeyboardModifierMappingSrc": 0x700000039,
  "HIDKeyboardModifierMappingDst": 0x700000000
}]}'

Reverted to {"UserKeyMapping":[]} on quit — or by hand, any time, with the same command.

Commands

The CLI underneath.

The menu-bar app is built on this. It works standalone too — aircaps [command], no menu required.

CommandDoes
statusShows connection, audio output, and battery — the default
onSwitches audio output to AirPods
offSwitches audio output to built-in speakers
toggleSwitches between the two
listLists every audio and Bluetooth device
ANCSets noise control to Noise Cancellation
ATSets noise control to Adaptive
TRSets noise control to Transparency
Setup

From clone to lit LED.

  1. 01

    Build the CLI

    make install — builds a release binary and copies it to /usr/local/bin/aircaps.

  2. 02

    Bundle the app

    make bundle-install — wraps the menu-bar app and installs it to /Applications.

  3. 03

    Grant permissions

    Accessibility for the popover, Input Monitoring for the key. The app's menu links straight to both panes.

  4. 04

    Pick your off-mode

    Settings — Adaptive or Transparency for when the LED is off. Adaptive by default.

Status

What's shipped, what's next.

  • Caps Lock → noise-mode toggle, LED-synced
  • Multi-keyboard sync, live on connect
  • CoreAudio output switching
  • Control Center automation for ANC/Adaptive/Transparency
  • Battery parsing via system_profiler
Requirements

What you'll need.

  • macOS 13.0+ (Ventura or later)
  • AirPods Pro, or other AirPods with ANC/Adaptive/Transparency
  • Accessibility permission, for noise-mode switching
  • Input Monitoring permission, for the menu-bar app's Caps Lock capture

CoreAudio · IOBluetooth · ApplicationServices · IOKit HID · SwiftUI · Swift Package Manager