在所有的笔记本电脑生产商中,Apple 是唯一一家从未想明白过盖子为何物的公司:盖上盖子,究竟意味着什么?
一方面,异于其他平台,MacBook 上的绝大多数进程旋即中止,在不破坏系统完整性的前提下,你甚至不能继续听歌,更别说跑本地 AI Agent;另一方面,依然有许多进程在偷偷运行,尤其是根本不能用的蓝牙耳机,依然反复连接、断开、连接、断开、连接、断开……
(当你把电脑放在隔壁房间时,蓝牙信号若隐若现,双耳将被反复断开和连接的提示音覆盖,耳机彻底无法使用,而且耳机也无权主动断开,最终你再也受不了,起身走出房间关死蓝牙。)
有人戏称,已经盖上盖子的 MacBook,还喜欢和手机等正在使用的设备“抢蓝牙”。Apple 的狂热爱好者可能会说,最新发布的、最新固件的、最新批次的、最昂贵的、配备无线充电盒的……(请继续追加条件)……AirPods (Pro) 没有这个问题,真可怜,这些家伙只是还没有遇到——或选择性无视——随机播放音乐的祖传 bug。遇到时,他们轻则享受不便,重则创造一个新的社死传说。
我不关心 MacBook 的设计团队有什么良苦用心,也无所谓异国情报部门会如何利用无法关闭的蓝牙大门(这都不算后门了),我只在乎一件事:怎么彻底关死它?
如何在盒盖时彻底关闭蓝牙?这个问题至少困扰了 MacBook 用户十几年,甚至催生了好几个开源项目。这类软件,显然要惹用心良苦的设计师不开心(或者让可能存在的情报机构不高兴),技术上也是独辟蹊径,均属搭载火山口上,随时可能失效——事实上,好几个已经失效了。
既然反正是临时私搭乱建,何不自己动手?万一失效,也知道如何修补。我随机意识到,Keyboard Maestro 是理想的违建工具,只需逐个击破以下各环节:
- 合上盖子,触发动作;
- 打开盖子,触发动作;
- 打开蓝牙和关掉蓝牙。
真正撸起袖子之后,才会发现,任何一步都没有现成答案。Keyboard Maestro 并不能直接识别盖子何时盖上,反之亦然,不过,这恰恰是重新审视操作流程的好机会:没有直接的触发机关,就看看同步会发生什么,进而尝试共轭控制。
除非接上外置显示器,通常在合上盖子时,电脑也进入休眠模式。那么,顺理成章,System Sleep 条件可以触发合盖后的自动操作。
至于开盖,Keyboard Maestro 论坛有过一场激烈讨论,答案同样是找关联线索:开盖后几乎必然马上要解锁电脑,那么,解锁就足以代表开盖。
涉及外置显示器时,盖子开合状况更复杂,而且此时往往需要外置的键盘和鼠标,蓝牙不能一概关死,有需要的读者可查看 Keyboard Maestro 论坛上的另一串讨论。
设置触发条件后,就要想办法打开和关闭蓝牙。借助 GUI Scripting 显然不妥——不管你多想让 Agent 这么干!——因为盖子盖上后只有瞬间,根本没有时间慢吞吞地模拟键鼠操作。前文提及的第三方软件,大多也是八仙过海,像闯空门一样四处寻找暂未被 macOS 堵死的 API。本文也不例外,我使用了一个官方的蓝牙接口,关闭蓝牙的Swift 代码如下:
import Foundation
import IOBluetooth
@_silgen_name("IOBluetoothPreferenceSetControllerPowerState")
func setBluetoothPower(_ state: Int32)
@_silgen_name("IOBluetoothPreferenceGetControllerPowerState")
func getBluetoothPower() -> Int32
setBluetoothPower(0)
Thread.sleep(forTimeInterval: 2)
if get
