Название — отсылка к devilspie, похожей утилитой. Она примечательна тем, что конфиг пишется на диалекте лисп, несмотря на это у неё весьма ограниченные возможности. Тем более у утилит типа wmctl и т.п.
С помощью библиотеки wnck можно делать куда больше, а ещё больше если задействовать gdk.
Для глобальный горячих клавиш я использовал libkeybinder, раньше я делал такое на «голой» xlib, но так удобней(и переносимей). Впрочем xlib/xtest тоже используется — чтобы эмулировать нажание кнопок. Но эти функции опциональны.
В качестве формата конфига я выбрал yaml. Более старые версии использовали конфиг на питоне, но я решил что yaml удобней конечным пользователям. Тем более в него можно встраивать код на python и sh.
В детали реализации я вдаваться не буду. Там много магии и метапрограммирования, часть кода сгенерирована.
Лучше покажу пример конфига, который использует часть возможностей. Кстати, новые правила можно генерировать из командной строки, оно возьмет name и class_group активного окна.
click_with_F1: if: key: F1 then: click: 3
Самый простой пример. При нажатии F1 будет эмулировать нажатие правой кнопки мыши.
save_image: if: key: F2 class_group: Google-chrome then: - click: 3 - sleep: 0.1 - press: v - enable: autosave
При нажатии F2 нажмет правую кнопку, v(save as) и активирует правило autosave
# Would type "filename" and press alt+s to save when Save file dialog of chrome appears. But only after we pressed F2. autosave: if: name: Save File class_group: Google-chrome enabled: false then: - press: f i l e n a m e Alt+S # Disable autosaving every 2 secs. timer_test: if: event: timer 2 then: disable: autosave
При появлении окна Save File запонит имя файла и сохранит. Через 2 секунды это правило отключается. Имя файла будет автоматически заполняться только при нажатии F2, а не у любых окон.
print_debug: if: event: never then: debug: win_changed: if: event: active_window_changed then: echo: "window changed {name} {class_group}" switched_to_xterm: if: name: contains: mc class_group: XTerm then: - maximize: - disable: win_changed - trigger: print_debug not_in_mc: if: or: class_group: ne: xterm name: contains_not: mc then: - sh: date - py: from datetime import datetime;print(datetime.now())
print_debug можно вызвать только вручную с помощью trigger, остальное думаю очевидно. это просто пример. доступны все манипуляции с окнами из wnck и gdk. список методов есть в командной строке или доках по wnck. возможных условий в if тоже куча, включая вызов кода на питоне или sh.
Важно — если горячая клавиша прописана только для определенного окна или условий. она будет мапиться только при переключении на это окно. При потере фокуса, хоткей отключается и кнопка работает как обычно. Это то чего нехватает многим гломальным менеджерам горячих кравиш.
Например у меня есть скрипт, который обрезает видео на текущем моменте, если активное окно — mpv. В других окнах такая функция была бы бесполезно, а кнока бы не работала.
Кстати. хоть в коде и много магии, я думаю, там неплохая архитектура. Хотелось бы услышать критику. Но тут важен баланс между понятностью кода и его универсальностью / компакностью. Упор сделан на последнее.
Код доступен на github https://github.com/pawnhearts/angelspie и pypi. Кстати. где бы ещё разместить программу? Хочется донести её для десктопных юзеров. Возможно, придется добавить gui, но там слишком много функций. Удобней просто редактировать конфиг.
ссылка на оригинал статьи https://habr.com/ru/post/562304/
Добавить комментарий