У моего 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
, но это происходит только при ручном изменении яркости экрана.
Что я могу послушать, чтобы определить, когда изменилось состояние питания экрана? Я хочу написать скрипт, который будет запускаться всякий раз, когда отключается питание экрана, чтобы я мог отключить подсветку клавиатуры.
решение1
Ну, отстой, что я не могу оставить комментарий, потому что у меня нет "репутации". Это скорее комментарий, чем решение.
Я искал что-то похожее, и вместо этого я отслеживаю 'org.gnome.SessionManager.Presence'. У меня есть светодиоды за монитором для подсветки, и я хочу выключать/включать их вместе с монитором.
Это работает, если я блокирую компьютер вручную, однако если я оставляю настройки «экран выключен» и «блокировка экрана через» на разных интервалах, светодиоды выключаются, когда выключается монитор, однако, когда срабатывает блокировка заставки, светодиоды снова включаются.
_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
}
решение2
Я только что установил Ubuntu 18.04, и оказалось, что по умолчанию нет заставки. И честно говоря, она мне не нужна, поэтому я не буду заморачиваться с ее установкой.
Однако я нашел несколько вызовов методов из gnome, которые, похоже, справляются с этой задачей: AddUserActiveWatch
и RemoveWatch
из org.gnome.Mutter.IdleMonitor
interface.
Вот мой сценарий:
#!/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 ()
Результат:
- когда дисплей начинает гаснуть, подсветка моей клавиатуры отключается
- клавиатура загорается только ПОСЛЕ того, как я успешно вхожу в систему, а не на экране входа (но это достаточно близко)
Отказ от ответственности:
- Слово monitor в org.gnome.Mutter.IdleMonitor происходит от действия monitoring, а не от monitor, он же screen. Так что в основном это, похоже, методы, которые вызываются, когда пользователь объявляется бездействующим, а не бездействующим gnome. По сути, в моем случае это совпадает с выключением экрана. В вашем случае это может быть не так.
- Видимо, вы не можете добавить это как запись systemd, потому что для этого нужен экран. Однако вы можете добавить это в
Startup Applications
GUI, и это работает - Я использую исполняемый файл g810-led для включения и выключения подсветки клавиатуры, это следует рассматривать просто как пример, поскольку он, очевидно, не будет работать на других клавиатурах.
PS: нашел "баг". Если прерывать затухание экрана, клавиатура остается неподсвеченной.
решение3
Хорошо, тогда послегодыЧтобы не расстраиваться из-за этого, я наконец что-то сделал и написал скрипт-утилиту на Python, которая отслеживает DBus и правильно принимает события блокировки/разблокировки сеанса.
Theкод размещен здесь, но я также включу его ниже. Моя цель — переписать это на 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
, который будет выполнен, когда экран заблокирован