我的 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”。我的显示器后面有用于偏置照明的 LED,我想用显示器关闭/打开它们。
如果我手动锁定计算机,此方法可行,但是,如果我以不同的时间间隔保留“屏幕关闭”和“锁定屏幕”设置,则当显示器关闭时,LED 也会关闭,但是,当屏幕保护程序锁定启动时,LED 会再次打开。
_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
界面的调用。
这是我的脚本:
#!/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 ()
结果是:
- 当显示屏开始变暗时,我的键盘背光就会关闭
- 仅在我成功登录后键盘才会亮起,而不是在登录屏幕上亮起(但已经足够接近了)
免责声明:
- org.gnome.Mutter.IdleMonitor 中的单词“monitor”来自监控操作,而不是监视器(又称屏幕)。因此,基本上这些似乎是在用户被声明为空闲且 gnome 未空闲时调用的方法。事实上,在我的情况下,它与屏幕关闭同时发生。在您的情况下,可能并非如此。
- 显然你不能将其添加为 systemd 条目,因为它需要一个屏幕。但是,你可以在
Startup Applications
GUI 中添加它,而且它可以工作 - 我正在使用 g810-led 可执行文件来打开和关闭键盘背光,这应该只是一个例子,因为它显然不适用于其他键盘
PS:发现一个“bug”。如果你中断屏幕淡入淡出,键盘将保持不亮状态。
答案3
好的,之后年对此感到沮丧,我终于采取了一些措施并编写了一个 Python 实用程序脚本来监视 DBus 并正确接收会话锁定/解锁事件。
这代码托管在这里,但我也会在下面包含它。我的目标是用 Rust 重写它,原因有很多,但主要是为了让人们更容易使用,而不必安装软件包来安装正确的 Python 库。
先决条件
要运行此代码,您需要:
- 最近用的是 Python 3,我在 Python 3.8.5 上写了这个。
- 蛋:
dbus-python >=1.2,<2
PyGObject >=3.36,<4
这些 Python egg 由某些 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
,它将在屏幕锁定时执行