虽然 AirPods 或 AirPlay 技术已经很好地解决了音频设备配对繁琐的问题,但是在 Mac 上切换输出依然不便。每当用触控板或鼠标费力地点选音量图标时,我常常感到总有一天我会忍不住去简化一下这个过程,like today。

当然 App Store 上已经有了很好的解决方案: Tooth Fairy 。不过如果需求比较简单,只是希望便捷地在常用设备间切换(通过快捷键、Touch Bar 或者绑定其它的工作流),那么用 macOS 上的万能胶水 AppleScript 就可以做到

用 BetterTouchTool 给 Touch Bar 增加了一个切换按钮
用 BetterTouchTool 给 Touch Bar 增加了一个切换按钮

通过点选菜单栏音量图标进行切换

最简单的,就是跟我们平常操作方式一样,点击音量图标,选中设备,只不过我们用脚本来自动执行,以 Keyboard Maestro 为例,绑定快捷键即可

点选菜单切换效果
点选菜单切换效果

Keyboard Maestro 宏
Keyboard Maestro 宏

需要给 Keyboard Maestro Engine 赋予辅助功能权限,其它工具同

辅助功能权限
辅助功能权限

脚本如下:

tell application "System Events" to tell process "SystemUIServer"
    tell (menu bar item 1 of menu bar 1 whose description contains "volume")
        click
        set target to "Jay's AirPods" -- 修改为自己设备的名称
        set alternative to "内置扬声器" -- 相互切换设备名称
        set retry to 1 -- 重试次数,可为 0
        set interval to 1 -- 重试间隔(秒),可为小数
        if exists (menu item 1 of menu 1 whose title is target and value of attribute "AXMenuItemMarkChar" is "✓") then
            set target to alternative
        end if
        repeat with counter from 0 to retry
            try
                click (menu item target of menu 1)
                exit repeat
            end try
            if counter < retry then
                delay (interval)
            else
                key code 53
            end if
        end repeat
    end tell
end tell
  • 需要在「系统偏好设置」->「声音」中勾选「在菜单栏中显示音量」
  • 脚本中只要指定 target 设备名称即可。默认与系统内建设备相互切换,可以修改 alternative 为其它设备名称
  • 因为蓝牙设备的发现需要时间,有时菜单会有少许延迟,因此增加了一个未发现设备时延时重选的机制,默认 1 次,可以修改 retry 为其它值,可为 0。默认间隔 1 秒,可由 interval 指定
  • 如果用 Bartender 隐藏了音量图标,脚本仍然可以正常工作,同时屏幕上不会显示操作过程

通过「系统偏好设置」进行切换

上个方法很直观,但是对视线的干扰比较大(可以用 Bartender 隐藏,但通常我们并不想这么做),另外如果在脚本执行的同时我们操作了鼠标,可能会导致脚本点选设备失败

所以还可以有另外一种思路,就是使用「系统偏好设置」,而且不必在前台显示,隐藏状态下操作后自动退出,这样就只会在 Dock 栏跳一下图标

通过「系统偏好设置」切换效果
通过「系统偏好设置」切换效果

为演示方便,在前台显示了切换过程,并加入了一些延时,实际只有 Dock 栏跳动图标的效果

脚本如下:

tell application "System Preferences"
    reveal anchor "output" of pane "com.apple.preference.sound"
end tell
tell application "System Events"
    tell application process "System Preferences"
        repeat until exists tab group 1 of window 1
        end repeat
        tell table 1 of scroll area 1 of tab group 1 of window 1
            set target to "Jay's AirPods" -- 修改为自己设备的名称
            # 相互切换设备名称,默认用了第一行设备的名称
            set alternative to value of text field 1 of row 1
            set retry to 1 -- 重试次数,可为 0
            set interval to 1 -- 重试间隔(秒),可为小数
            if value of text field 1 of (row 1 whose selected is true) is target then
                set target to alternative
            end if
            repeat with counter from 0 to retry
                try
                    select (row 1 whose value of text field 1 is target)
                    exit repeat
                end try
                if counter < retry then
                    delay (interval)
                end if
            end repeat
        end tell
    end tell
end tell
tell application "System Preferences" to quit

特殊情况

如果使用了 Boom 3D 之类的音效增强类 App,输出设备会被固定为一个聚集设备,用以上两种方法无从判断当前实际连接设备,就不能在设备间双向切换,不过单向切换到 target 设备总是可行的(如果 target 是 AirPlay 则不受影响,嗯,就是「隔空播放」)

Boom 3D 生成的聚集设备
Boom 3D 生成的聚集设备

开启 Boom 3D 后当前设备标识(✓)消失
开启 Boom 3D 后当前设备标识(✓)消失