- SignalDesk3小时前
做 LayoutKeeper 的时候,我以为最难的是把窗口搬回原来的桌面(前面两篇日志写过这个)。后来发现,排第二难的是一个看起来很 trivial 的问题:怎么认出"这是哪块屏"。 LayoutKeeper 是个 macOS 菜单栏小工具(开源 GPL-3.0 ),干的事很简单:记住外接屏上每个窗口的位置和它所在的 Mission Control 桌面,拔线再插回来时一键还原。家里和公司各一块屏,就得各存一份布局——认错了屏,恢复出来的就是另一套布局,灾难。 macOS 给每个显示器分配的
CGDirectDisplayID,拔插一次就可能变,根本不能当身份证用。真正靠谱的是 EDID:显示器固件里的一小块数据,里面有厂商 ID 、型号、序列号。我一开始的做法是直接拿"厂商+型号+序列号"拼成 key ,每块屏一份布局文件,存在本机~/Library/Application Support/LayoutKeeper/里,JSON ,明文,谁都能打开看。 然后翻车了,而且是连环翻车: 翻车一:有些屏的序列号是假的。 不少便宜显示器 EDID 里的序列号直接填 0 ,两台同型号的屏插上去,key 一模一样,布局互相覆盖。后来加了 fallback:序列号为 0 或重复时,再叠加上端口信息和首次见到它的时间戳做区分,至少保证"这次插的这两台"不会打架。完美吗?不完美,但比覆盖强。 翻车二:同一台屏,换根线/换个扩展坞,macOS 给的标识会变。 EDID 本体没变,但系统侧的 display UUID 变了。我最早只认系统 UUID ,结果用户(就是我自己)换了个扩展坞,布局"丢了"。0.6.7 把这块重写了:认屏以 EDID 为主,系统标识只当辅助,换线换坞不再丢布局,换一台没见过的显示器也能正常走"新屏"流程而不是报错。 翻车三:窗口认错。 认出屏只是第一步,还得认出窗口。Chrome 是个大坑:我公司和家里登的是不同 profile ,但进程名和 bundle id 一模一样。以前按 bundle id 匹配,经常把"公司 profile 的窗口"塞进"家里 profile 的位置"。0.6.7 改成按 Chrome 的用户配置( profile )目录匹配,世界清净了。同理,同名窗口实在分不清的,LayoutKeeper 会标"需要确认"让你手动选,绝不猜着移——这个原则从第一版就没变过。 布局数据本身长什么样?每块屏一个 JSON:窗口列表( bundle id 、窗口标题、frame 、所在桌面序号),外加最近 5 个历史版本自动轮换。恢复时先逐窗口预览,搬一个回读确认一个,没到位的回滚,整轮还能一键撤销(⌃⌥⌘Z )。数据只存本机,不收集任何东西,唯一的联网是去 GitHub 查更新(可关)。 局限照例写前面,不藏着: - 只支持一块外接屏,多屏用户先别试。 - 跨桌面恢复要 macOS 26+(同桌面内的位置恢复 macOS 14+ 就行),用的是 SkyLight 私有接口,不用关 SIP 、不用注入 Dock ,只要"辅助功能"权限;系统大更新后可能失效,启动时自动检测,失效就自动关掉这个功能。 - Finder 窗口没法跨桌面移动(拿不到进程启动时间)。 仓库: https://github.com/tumingke0/LayoutKeeper 如果你也在写跟显示器打交道的 macOS 工具,EDID 解析这块欢迎交流——我踩过的坑,Issue 里基本都记着。上一帖有朋友说 AI 味重,这篇尽量说人话了,继续求拍砖。- 情报分类:硬件与数码
- 分类依据:内容涉及硬件、数码产品或通信卡
- 信息来源:服务器 / V2EX
- 发布时间:2026/10/20 18:30:28
- 暂无回复