
Почему запись экрана захватывает не тот монитор (и как мы это исправили)
На конфигурации с двумя мониторами GeekBye записывал и снимал скриншоты с основного дисплея независимо от того, на каком экране вы работали. Фикс уместился в одну небольшую функцию — но первая её версия была неверной, и код-ревью поймало почему.
Вот баг, который существует, только если у вас два монитора, — потому он какое-то время и жил тихо. Вы работаете на боковом дисплее, запускаете запись GeekBye, а она записывает ваш основной монитор. Тот, что с меню-баром. Тот, на который вы не смотрели.
Тот же дефект, тише и хуже, ударил по скриншотам, которые GeekBye отправляет ИИ для контекста: жмёте горячую клавишу скриншота на втором мониторе, а ИИ получает картинку первого. Никакого визуального признака — ассистент просто отвечает про не тот экран, и вы недоумеваете, почему он в замешательстве. GeekBye v2.0.10 исправил оба.
Два конвейера, один ленивый дефолт
Захват экрана на десктопе — это два отдельных пути кода, и оба независимо выбрали основной дисплей:
- Запись видео перечисляла доступные источники экрана и брала первый —
sources[0]. На macOS это фактически всегда основной дисплей. Ни выбора, ни логики о том, где вы на самом деле были. Комментарий в нашем собственном коде буквально гласил «auto-select first screen source» (автовыбор первого источника экрана). - Скриншоты использовали macOS-команду
screencaptureс флагом-m. У этого флага ровно одно значение: только основной дисплей. Зашито намертво.
Ни один из путей ни разу не задал вопрос, который важен: на каком экране пользователь?
Одно, что никогда не было сломано, и это стоит прояснить, потому что люди думают иначе: переключение между пространствами (Spaces) macOS на том же мониторе всегда работало. Захват происходит на уровне дисплея — он берёт то пространство, что видно на выбранном дисплее. Баг никогда не был про пространства. Он всегда был про выбор не того физического дисплея.
Фикс, который выглядел очевидным — и был неверным
Правильный сигнал кажется простым: захвати дисплей, на котором пользователь. Наша первая реализация привязалась к окну оверлея GeekBye — захватывай тот дисплей, на котором живёт оверлей.
Код-ревью справедливо его зарубило. Оверлей GeekBye создаётся как окно на всю рабочую область на основном дисплее, в позиции (0,0). Он перемещается на другой монитор, только если вы физически перетащите туда его «пилюлю» — а горячие клавиши, которые его подвигают, зажаты размерами основного дисплея, так что они не могут перенести его на второй монитор вообще. Привязка захвата к оверлею означала: для каждого пользователя, который не перетащил оверлей на свой рабочий экран, «фикс» разрешался обратно в основной дисплей. Он не исправил бы почти никого — а при быстром тесте на одномониторной машине разработчика выглядел бы как работающий.
Правильная точка привязки — курсор. Где бы ни была ваша мышь, это и есть дисплей, на котором вы работаете, — и это верно для любого способа начать захват: горячая клавиша срабатывает там, куда вы указываете, а клик по кнопке «Запись» по определению помещает ваш курсор на этот дисплей. Итоговый фикс — двухстрочная функция: дисплей, ближайший к курсору. Видео сопоставляет свой источник захвата с id этого дисплея; скриншоты передают границы этого дисплея в screencapture -R (конкретный прямоугольник) вместо флага -m (только основной дисплей).
Мы намеренно выбрали -R (явный прямоугольник в глобальных координатах экрана) вместо -D (индекс дисплея): индекс дисплея в ОС не имеет гарантированного соответствия порядку дисплеев во фреймворке, так что индекс был бы второй игрой в угадайку. Прямоугольник из реальных границ дисплея однозначен — и поведение флага мы проверили, включая отрицательные координаты для дисплеев слева от основного, на настоящей многомониторной сборке перед выпуском.
Почему это хороший учебный баг
- «Захвати экран» скрывает решение. На одном дисплее решения нет, поэтому решение никогда не проектируется — оно назначается по умолчанию. Несколько мониторов — это место, где всплывает каждый неявный дефолт.
- Тихо-неверно хуже, чем видимо-неверно. Баг с видео раздражал людей. Баг со скриншотом вводил в заблуждение ИИ, незримо. Когда вы строите функции, питающие модель контекстом, неверный вход даёт уверенно неверный выход без единой ошибки где-либо. Именно такие отказы стоит выслеживать усерднее всего.
- Фикс, проходящий на вашей машине, может провалиться на любой чужой. Версия, привязанная к оверлею, работала в одномониторном тесте. Весь смысл бага — несколько мониторов, — а ревьюер рассудил о реальном положении окна, вместо того чтобы доверять зелёному тесту. Ревью — не штамп на работающем коде; это вторая модель того, почему код работает.
GeekBye v2.0.10 выпускает основанный на курсоре фикс и для записи, и для скриншотов. Если у вас несколько дисплеев, захват теперь следует за вами.
Соседние релизы этой серии смотрите в почему ваш ИИ-ассистент для заметок останавливает запись посреди встречи (v2.0.9) и почему ИИ-транскрипция перевирает технические термины (v2.0.11). О том, как оверлей ведёт себя во время звонков, читайте в как оставаться невидимым во время демонстрации экрана.