TGViewer
annFlow annFlow @annsflow · 33 subscribers
Post #85 39
Window Manager в Hammerspoon

Оконный менеджмент в macOS часто сбоит на уровне деталей: фокус, анимации и внутренние состояния приложений. В моем сетапе с Hammerspoon окна управляются напрямую через API Hammerspoon (работа с объектом окна и его геометрией, а не через UI-состояния), поэтому результат получается более стабильным и предсказуемым.


Базовый интерфейс управления окнами у меня построен на слое Ctrl + Option + клавиша. Это быстрые, мышечно-запоминаемые команды:

- Ctrl+Option+A прижимает окно к левому краю (левая половина)

- Ctrl+Option+D прижимает к правому краю (правая половина)

- Ctrl+Option+S ставит окно в центр (и т.д.)


Таких сочетаний много: под каждую “логичную” кнопку заведено своё действие для перемещения или изменения размеров окна. Для скорости работы на Mac это критично: окно перестаёт быть объектом, который “нужно руками расставлять”, и становится состоянием, которое вызывается одной командой.


1) Нулевая анимация

hs.window.animationDuration = 0


2) Два способа позиционирования

2.1) moveToUnit(...)

Надёжный тайлинг в долях экрана (0..1): левый/правый полукран, четверти и т.п. Устойчив к разным экранам и Dock/Menu Bar.

2.2) setFrame(...)

Когда нужна конкретная зона: колонка 25%, нижняя четверть, центрирование и т.д. Пример “правая колонка 25%” из конфига:


local win = hs.window.focusedWindow()
local screenFrame = win:screen():frame()
win:setFrame({
x = screenFrame.x + screenFrame.w * 0.75,
y = screenFrame.y,
w = screenFrame.w * 0.25,
h = screenFrame.h
})


Просто: берётся рабочая область экрана и окну задаётся прямоугольник, где ширина 25%, а x начинается с 75% (то есть край справа).

3) Toggle “разложить / вернуть”


Перед тайлингом сохраняется исходный frame в windowStates, затем можно одним действием вернуть окно “как было”. Это делает раскладки обратимыми.

4) Сетка окон приложения + возврат


Сценарий собирает окна текущего приложения, раскладывает сеткой по экрану, повторным запуском восстанавливает исходные позиции. Быстро наводит порядок и так же быстро возвращает обратно.


5) Перенос между мониторами


Перемещение на соседний экран по топологии: west/east/north/south. Это удобнее, чем “монитор №2”, потому что работает по реальному расположению экранов.

6) Микро-подстройка

Шаговые сдвиги (в конфиге шаг 100px) закрывают кейс “почти идеально, но нужно чуть подвинуть”.


Почему это надёжнее системных хоткеев и части готовых решений

Системные/некоторые сторонние команды часто завязаны на UI-состояние (фокус, анимации, “успел ли апп”). Здесь всё детерминированно: Hammerspoon получает окно, вычисляет целевую геометрию и применяет её напрямую (moveToUnit / setFrame / moveToScreen), при необходимости сохраняя состояние (windowStates). Плюс Hammerspoon в том, что я могу собирать собственные команды под себя и задавать в них любые параметры: точные размеры и координаты, привязку к экрану, шаги смещения, условия, сохранение/восстановление состояния и любые дополнительные характеристики, которые нужны именно моему workflow.

В следующем посте: мой подход к управлению медиа через Hammerspoon с задержками и fallback.

Оглавление темы 📌
Навигация по проектам канала 📍
Все проекты 🎶

#macOSAutomation@annsFlow

💻 annFlow
  • 👍 1
More from @annsflow
  1. Sep 24, 2026LiveContext в реальном разговоре. На видео я разбираюсь с претензией по недоставленному за…
  2. Sep 21, 2026Как LiveContext разделяет мой голос и голос собеседника Чтобы LiveContext мог понимать раз…
  3. Sep 16, 2026Почему мне оказалось недостаточно просто сохранять разговоры В VoxBase я решал проблему то…
  4. Sep 15, 2026Как я построил LiveContext, или Как связать живой разговор с памятью проекта ● Почему мне…
  5. Sep 14, 2026annFlow pinned a video
  6. Sep 14, 2026Самая неожиданная вакансия, которую нашел мой бот Моя система постоянно сама ищет вакансии…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →