今日已更新 262 条资讯 | 累计 42673 条内容
关于我们

The macOS play/pause key goes to the wrong app, so I built a router for it

Yasin Özmen 2026年09月13日 17:27 2 次阅读 来源:Dev.to

A YouTube tab is playing in Brave. I press play/pause on the keyboard. The video keeps going and Apple Music opens on top of everything, playing a song I did not ask for. I did this for years. Close Music, click the tab, press space. Then one evening I opened Console to find out why, and ended up writing SmartPause, a small menu bar app that sends the key to the app that is actually making sound. Source is on GitHub: github.com/yasinozmeen/smartpause . This is what I learned about media keys on macOS, and the four things that cost me the most time. Where the key actually goes macOS keeps one "Now Playing" slot. Whichever app last registered with the MediaRemote framework owns it, and the play/pause key goes there. Browsers register when a tab starts playing, then lose the slot to another app, or keep it after the tab is gone. From the outside you cannot tell which. When the slot is empty, macOS falls back to Apple Music. That is the "Music opens by itself" moment. The key is routed by memory, not by sound. Ask Core Audio instead Since macOS 14.2 Core Audio exposes the list of audio processes as public API, with a property that says whether each one is outputting right now. No microphone permission, no screen recording, and nothing runs until you press a key. static func runningOutputProcesses () -> [ AudioProcess ] { var a = addr ( kAudioHardwarePropertyProcessObjectList ) var size : UInt32 = 0 let sys = AudioObjectID ( kAudioObjectSystemObject ) guard AudioObjectGetPropertyDataSize ( sys , & a , 0 , nil , & size ) == noErr else { return [] } var ids = [ AudioObjectID ]( repeating : 0 , count : Int ( size ) / MemoryLayout < AudioObjectID >. size ) guard AudioObjectGetPropertyData ( sys , & a , 0 , nil , & size , & ids ) == noErr else { return [] } return ids . compactMap { id in guard ( get ( id , kAudioProcessPropertyIsRunningOutput , UInt32 ( 0 )) ?? 0 ) != 0 , let pid = get ( id , kAudioProcessPropertyPID , Int32 ( 0 )) else { return nil } // bundle id, responsib

本文内容来源于互联网,版权归原作者所有
查看原文