Подпишитесь на DBUS событие выключения экрана

Мой MacBook Pro имеет подсветку клавиатуры, что довольно здорово, но есть небольшая ошибка: экран выключается через некоторое время, но подсветка клавиатуры остается включенной.

Я скопировал и запутался с небольшим скриптом DBUS Python, чтобы отслеживать, когда происходят изменения с состоянием экранной заставки, но он не срабатывает, когда экран выключается, только когда экранная заставка активируется или деактивируется:

from dbus.mainloop.glib import DBusGMainLoop

import dbus
import gobject
import logging

logging.basicConfig()

logger = logging.getLogger(__name__)

dbus_loop = DBusGMainLoop(set_as_default=True)

def message_callback(bus, message):
    if message.get_interface() == "org.gnome.ScreenSaver":
        if message.get_member() == "ActiveChanged":
            screensaver_enabled = bool(message.get_args_list()[0])
            logger.info("Screen saver changed. Active: %s", screensaver_enabled)

session = dbus.SessionBus(mainloop=dbus_loop)
session.add_match_string_non_blocking("interface='org.gnome.ScreenSaver'")

session.add_message_filter(message_callback)

logger.info("Starting up.")

loop = gobject.MainLoop()
loop.run()

Это прекрасно работает, когда заставка активирована, но не изменяется при изменении состояния питания экрана, что может происходить независимо от заставки. Зайдя в настройки «Яркость и блокировка» в меню «Настройки», вы можете отключить экраны через 1 минуту и ​​не блокировать их. Затем вы можете установить другое время экрана, например, 10 минут.

Я пытался прослушивать интерфейс org.gnome.SettingsDaemon.Power.Screen для сигнала Changed, но это происходит только тогда, когда яркость экрана изменяется вручную.

Что я могу прослушать, чтобы определить, когда состояние питания экрана изменилось? Я хочу написать сценарий, который запускается всякий раз, когда отключается питание экрана, чтобы я мог отключить подсветку клавиатуры.

2
задан 4 June 2015 в 03:19

3 ответа

Ну, это сосет это, я не могу оставить комментарий, потому что у меня нет "репутации". Это - больше комментария, чем решение.

я искал что-то подобное, и я контролирую 'org.gnome. SessionManager. Присутствие' вместо этого. У меня есть светодиоды позади моего монитора для освещения предвзятости, и я хочу повернуть их прочь/на с монитором.

Это работает, если я блокирую свой компьютер вручную, однако если я оставляю "экран" и "экран блокировки после того, как" настройки в различных интервалах, светодиоды выключают, когда монитор выключает, однако когда удары блокировки экранной заставки в нем включают светодиоды снова.

_getState () {
  dbus-monitor --session "type=signal,interface=org.gnome.SessionManager.Presence,member=StatusChanged" |
  while read x; do
    case "$x" in 
      *"uint32 3"*)
          /home/victor/bin/devices/kasa_cntrl.sh off
          echo -e "$(date)\t-\tTurned off" >> "$log"
          ;;
      *"uint32 0"*)
          /home/victor/bin/devices/kasa_cntrl.sh on
          echo -e "$(date)\t-\tTurned on" >> "$log"
          ;;
    esac
  done
}
<час>

Ссылка : https://www.organicdesign.co.nz/PoisonTap_solution

3
ответ дан 4 June 2015 в 13:19
  • 1
    Вероятно, Вы имеете vte.sh тогда, в случае, если Ваш Ubuntu является более старым. Оставьте те файлы под /etc/profile.d нетронутыми, добавьте отрезанный, который я показал ~/.bashrc (с очевидной корректировкой имени файла, которое она отсылает к). – egmont 13 September 2016 в 03:55

Я только что установил Ubuntu 18.04, и это поворачивается, там не подарок экранной заставки по умолчанию. И честно, я не хочу один, таким образом, я не потружусь устанавливать тот.

Однако я нашел некоторые вызовы метода от гнома, которые, кажется, добиваются цели: AddUserActiveWatch и RemoveWatch от org.gnome.Mutter.IdleMonitor интерфейс.

Вот мой сценарий:

#!/usr/bin/env python

import dbus, gobject
from dbus.mainloop.glib import DBusGMainLoop
from subprocess import call

def filter_cb(bus,message):
    if message.get_member() == "AddUserActiveWatch":
        print("Monitor off")
        call("/usr/bin/g810-led -dv 046d -dp c337 -a 000000", shell=True)
    elif message.get_member() == "RemoveWatch":
        print("Monitor on")
        call("/usr/bin/g810-led -dv 046d -dp c337 -p /etc/g810-led/profile", shell=True)
    return

DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()

bus.add_match_string_non_blocking("interface='org.gnome.Mutter.IdleMonitor',eavesdrop='true'")
bus.add_message_filter(filter_cb)

mainloop = gobject.MainLoop ()
mainloop.run ()

Результат:

  • когда дисплей начинает потускнение, моя подсветка клавиатуры закрывается
  • клавиатура освещает только ПОСЛЕ ТОГО, КАК я успешно вхожу в систему, не на экране входа в систему (но это достаточно близко),

Отказ от ответственности:

  1. Монитор слова в org.gnome. Бормотание. IdleMonitor происходит из контролирующего действия, не из монитора иначе экранируют. Таким образом, в основном они, кажется, методы, которые называют, когда пользователь объявляется неактивный и не неактивный гномом. На самом деле, в моем случае, это совпадает с экраном, приводимым в действие прочь. В Вашем случае это не могло бы.
  2. По-видимому, Вы не можете добавить это как systemd запись, потому что ей нужен экран. Однако можно включить его Startup Applications GUI и это работают
  3. Я использую g810-ведомый исполняемый файл для включения и выключения моей подсветки клавиатуры, которую нужно рассматривать так просто пример, как это, очевидно, не будет работать над другими клавиатурами

PS: найденный "ошибкой". Если Вы прерываете экран, исчезают, клавиатура остается неосвещенной.

2
ответ дан 2 December 2019 в 01:59

Хорошо, после лет разочарования по этому поводу, я, наконец, что-то сделал и написал служебный скрипт Python, который отслеживает DBus и правильно получает события блокировки/разблокировки сеанса.

Код размещен здесь, но я также приведу его ниже. Моя цель — переписать это на Rust по ряду причин, но в основном для того, чтобы облегчить людям использование без необходимости устанавливать пакеты для установки правильных библиотек Python.


Предварительные требования

Для запуска этого кода вам понадобятся:

  • Последняя версия Python 3, я написал это на Python 3.8.5.
  • Яйца:
    • dbus-python >=1.2,<2
    • PyGObject >=3.36,<4

Эти яйца Python предоставляются некоторыми пакетами Ubuntu, но могут быть неправильными версиями. Я считаю, что в 16.04 необходимы следующие пакеты:

  • python3-gi , то есть PyGObject
  • python3-dbus , то есть dbus-python

в другом дистрибутиве. версиях эти пакеты могут отличаться. Это одна из многих причин, почему я хочу переписать это на Rust, я перечислю другие мотивы в конце этого ответа.

Код

Перейдем к коду.

dbus-session-lock-watcher.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from dbus.mainloop.glib import DBusGMainLoop

from gi.repository import GLib

import dbus
import logging
import sys


class ScreenSaverEventListener(object):

    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.mainloop = DBusGMainLoop()
        self.loop = GLib.MainLoop()
        self.session_bus = dbus.SessionBus(mainloop=self.mainloop)

        self.receiver_args, self.receiver_kwargs = None, None

    def setup(self):
        self.receiver_args = (self.on_session_activity_change,)
        self.receiver_kwargs = dict(dbus_interface="org.freedesktop.DBus.Properties", path="/org/gnome/SessionManager",
                                    signal_name="PropertiesChanged",
                                    # callback arguments
                                    sender_keyword="sender", destination_keyword="dest",
                                    interface_keyword="interface", member_keyword="member", path_keyword="path",
                                    message_keyword="message")

        self.session_bus.add_signal_receiver(*self.receiver_args, **self.receiver_kwargs)

    def on_session_activity_change(self, target: dbus.String, changed_properties: dbus.Dictionary, *args, **kwargs):
        if target != "org.gnome.SessionManager" or "SessionIsActive" not in changed_properties:
            return

        if changed_properties.get("SessionIsActive"):
            self.on_session_unlock()
        else:
            self.on_session_lock()

    def on_session_lock(self):
        self.logger.info("Session Locked")

    def on_session_unlock(self):
        self.logger.info("Session Unlocked")

    def run(self):
        self.logger.debug("Starting event loop.")
        self.loop.run()

    def shutdown(self):
        self.logger.debug("Stopping event loop.")
        self.session_bus.remove_signal_receiver(*self.receiver_args, **self.receiver_kwargs)
        self.loop.quit()


def main():
    setup_logging()

    listener = ScreenSaverEventListener()
    listener.setup()

    try:
        listener.run()
    except KeyboardInterrupt:
        sys.stderr.write("ctrl+c received, shutting down...\n")
        listener.shutdown()


def setup_logging():
    console = logging.StreamHandler(sys.stderr)
    console.setFormatter(
        logging.Formatter("%(asctime)s [%(levelname)-5s] %(name)s: %(message)s", datefmt="%Y-%m-%dT%H:%M:%S%z"))
    logging.addLevelName(logging.WARNING, "WARN")
    logging.getLogger().addHandler(console)
    logging.getLogger().setLevel(logging.DEBUG)


if __name__ == "__main__":
    main()

Чтобы сделать этот код интересным, отредактируйте:

  • ScreenSaverEventListener.on_session_lock, который будет выполняться при блокировке экрана
  • ScreenSaverEventListener.on_session_unlock, который будет выполняться, когда экран будет разблокирован.

Установка

Сначала сохраните приведенный выше скрипт в файл, желательно в ~/.local/bin.Далее, конечно, нужно убедиться, что он помечен как исполняемый, через chmod +x ~/.local/bin/dbus-session-lock-watcher.py.

Я бы посоветовал запускать это как службу, поэтому давайте создадим пользовательскую единицу systemd для запуска службы.

Вот пример устройства:

~/.config/systemd/user/session-lock-watcher.service

[Unit]
Description=DBus Session Lock Watcher

[Service]
ExecStart=$HOME/.local/bin/dbus-session-lock-watcher.py

[Install]
WantedBy=default.target

Далее включим службу:

systemctl --user enable session-lock-watcher.service

Наконец, запустим ее:

systemctl --user start session-lock-watcher.service

Для просмотреть журналы службы:

journalctl --user-unit session-lock-watcher.service

И теперь мы можем выполнять пользовательский код или сценарии всякий раз, когда сессия заблокирована или разблокирована!


Другая информация

На это ушло много работы, поэтому я хотел предоставить некоторую информацию на случай, если она будет интересной.

Обучение

D-Bus сложен, но я попытаюсь обобщить его. D-Bus является связующим звеном между различными приложениями и предоставляет множество наворотов. Если вы знакомы с JMX для JVM, это похоже на то, за исключением того, что служебная шина является внешним процессом.

Как правило, существует две шины D-Bus: системная шина и сеансовая шина. системная шина предназначена для всей ОС, тогда как сеансовая шина предназначена для каждого пользователя и, скорее всего, является основной вещью, с которой вам нужно взаимодействовать.

D-Bus содержит реестр имен, каждое из которых имеет ряд путей к объектам, которые он поддерживает, и каждый из этих путей к объектам имеет один или несколько интерфейсов. Интерфейсы имеют методы, свойства и сигналы. Вы можете вызывать методы с аргументами или без них и получать результаты, если метод возвращает значения.Вы можете читать, а иногда и записывать свойства, а сигналы — это события, на которые вы можете подписаться и которые несут данные.

Точная связь между именами, путями к объектам и интерфейсами мне все еще не ясна, поэтому я просто собираюсь двигаться дальше. Короче говоря, у вас есть куча зарегистрированных имен/приложений, которые реализуют определенные интерфейсы, которые определяют методы, сигналы и свойства, и именно так вы взаимодействуете между приложениями, используя D-Bus.

Я попытаюсь найти дополнительную документацию, чтобы понять логику всего механизма D-Bus, но пока этого достаточно.

Что было исключительно разочаровывающим, так это то, сколько разных вещей я пытался просто получить обратный вызов, когда экран был заблокирован или разблокирован.

Я попробовал org.gnome.ScreenSaver, который поддерживает несколько интерфейсов с одинаковыми атрибутами, org.freedesktop.ScreenSaver и org.gnome.ScreenSaver. . Оба они поддерживают сигнал ActiveChanged, который несет логическое значение, по-видимому, для указания, активна ли заставка. Я никогда не ловил этот сигнал, никогда.

Я попробовал org.gnome.SessionManager и его соответствующий интерфейс, который выдавал сигналы SessionOver и SessionRunning. Я никогда не ловил ни один из этих сигналов.

После перебора тонны различных имен, интерфейсов и сигналов я почти разочаровался в поиске сигнала, показывающего, когда сеанс был заблокирован и разблокирован.Я настроил общий приемник сигналов, который перехватывал все сигналы, устанавливал точку останова и проходил через все из них, пока не нашел сигнал изменения свойства для свойства SessionIsActive, принадлежащего org. .gnome.SessionManager. Бинго.

Наконец,Я настроил свой приемник сигналов на фильтрацию, насколько это возможно, при получении только соответствующих сигналов, когда это свойство изменено.

Я использую производную версию Ubuntu, поэтому этот код может работать не во всех дистрибутивах Ubuntu. Запустите сценарий, заблокируйте и разблокируйте сеанс и посмотрите, создает ли сценарий журналы блокировки и разблокировки.

Будущая работа

Я бы очень хотел переписать все это в простом демоне Rust, так как бинарный файл будет гораздо проще распространять, с небольшим количеством зависимостей во время выполнения или вообще без них. Я также хотел бы предоставить какой-то каталог, в котором можно хранить столько скриптов, сколько они хотели бы запускать при событиях блокировки и разблокировки, возможно, что-то вроде ~/.config/nosleep/on-{lock,unlock }/*. Будет получен отсортированный список файлов, и каждый исполняемый файл будет запускаться в отсортированном порядке, что значительно упростит написание сценариев для событий блокировки и разблокировки.


Надеюсь, это кому-нибудь поможет и будет информативным. Я знаю, что многому научился, когда писал это!

0
ответ дан 25 July 2020 в 01:46

Другие вопросы по тегам:

Похожие вопросы: