Название - отсылка к 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 и pypi. Кстати. где бы ещё разместить программу? Хочется донести её для десктопных юзеров. Возможно, придется добавить gui, но там слишком много функций. Удобней просто редактировать конфиг.