Brightness Controller 亮度控制
- 一、概述
- [二、ddcutil 与 xrandr](#二、ddcutil 与 xrandr)
-
- [1. ddcutil](#1. ddcutil)
- [2. xrandr](#2. xrandr)
- 三、部分代码解析
-
- [1. icons](#1. icons)
- [2. ui](#2. ui)
- [3. util](#3. util)
- init.py
一、概述
项目:https://github.com/SunStorm2018/Brightness.git
原理:Brightness Controlle 是我在 Ubuntu 发现上调节亮度的一个工具,我觉得很好用,我后面对它的实现比较感兴趣,就去找了他的源项目来满足我的好奇心,也许后面做项目时候会使用,特此记录。
这个小工具是用的 python3 实现,界面使用 pyqt5 ,控制显示器功能用的命令完成的,会用到 ddcutil 和 xrandr 。
在亮度调节后台的命令优先使用 ddcutil,其次才使用 xrandr。
二、ddcutil 与 xrandr
这里简单介绍一下 ddcutil
1. ddcutil
ddcutil 是一个 Linux 命令行工具,用于通过 DDC/CI(Display Data Channel Command Interface) 协议与支持该协议的显示器进行通信。它允许用户通过软件控制显示器的硬件设置,如亮度、对比度、输入源等。
- . 调整显示器设置:
- 亮度、对比度、音量等。
- 切换输入源(如 HDMI、DP、VGA)。
- 调整色彩设置(如 RGB 值)。
- 查询显示器信息:
- 获取显示器的制造商、型号、支持的 DDC/CI 功能等。
- 自动化控制:
- 通过脚本批量调整多台显示器的设置。
2. xrandr
xrandr 是一个 Linux 命令行工具,用于管理和配置显示器的分辨率、刷新率、旋转、镜像以及多显示器布局。它是 X Window System(Xorg)的一部分,主要用于与 X Server 交互,因此仅适用于运行 Xorg 的 Linux 系统。
三、部分代码解析
1. icons
图标文件夹
2. ui
界面文件夹,包含ui文件,以及通过uic工具对ui文件生成的pyqt脚本文件。
3. util
包含了基础的工具集
- check_displays.py
查询连接的显示器工具,通过运行 xrandr --query 命令,再对输出用正则匹配出显示器名称
python
import subprocess
import shlex
import re
def query_xrandr():
query = "xrandr --query"
xrandr_output = subprocess.Popen(shlex.split(query), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, stderr = xrandr_output.communicate()
return str(stdout, "utf-8")
def extract_displays(output):
pattern = re.compile(r'\b({0})\b'.format("connected"), flags=re.IGNORECASE)
lines = output.splitlines()
connected = [line for line in lines if pattern.search(line)]
connected_displays = list(
map(lambda display: display.split()[0], connected))
return connected_displays
def detect_display_devices():
"""
Detects available displays.
returns connected_displays
This contains the available device names compatible with xrandr
"""
return extract_displays(query_xrandr())
if __name__ == '__main__':
print(detect_display_devices())
- executor.py
封装的进程控制器,是调节亮度这些的后台命令
python
import subprocess
def execute_command(string_cmd):
subprocess.check_output(string_cmd, shell=True)
使用的例子如下
python
def change_value_pr(self, value):
"""Changes Primary Display Red ratio"""
cmd_value = "xrandr\
--output %s \
--brightness %s\
--gamma %s:%s:%s" % \
(self.display1,
self.values[self.ui.primary_brightness.value() - 1],
self.values[value],
self.values[self.ui.primary_green.value()],
self.values[self.ui.primary_blue.value()])
Executor.execute_command(cmd_value)
-
read_config.py 和 write_config.py
读写配置,没有特别内容
-
封装的单例工具,它的核心作用是确保同一时间只有一个应用程序实例运行,并支持在多个实例尝试启动时,将消息传递给已经运行的实例,并激活窗口。使用QLocalSocket 作为进程间通信的工具。
python
class QtSingleApplication(QApplication):
messageReceived = Signal(str)
def __init__(self, id, *argv):
super(QtSingleApplication, self).__init__(*argv)
self._id = id
self._activationWindow = None
self._activateOnMessage = False
# Is there another instance running?
self._outSocket = QLocalSocket()
self._outSocket.connectToServer(self._id)
self._isRunning = self._outSocket.waitForConnected()
if self._isRunning:
# Yes, there is.
self._outStream = QTextStream(self._outSocket)
self._outStream.setCodec('UTF-8')
else:
# No, there isn't.
self._outSocket = None
self._outStream = None
self._inSocket = None
self._inStream = None
self._server = QLocalServer()
self._server.listen(self._id)
self._server.newConnection.connect(self._onNewConnection)
def isRunning(self):
return self._isRunning
def id(self):
return self._id
def activationWindow(self):
return self._activationWindow
def setActivationWindow(self, activationWindow, activateOnMessage=True):
self._activationWindow = activationWindow
self._activateOnMessage = activateOnMessage
def activateWindow(self):
if not self._activationWindow:
return
self._activationWindow.setWindowState(
self._activationWindow.windowState() & ~Qt.WindowMinimized)
self._activationWindow.raise_()
self._activationWindow.activateWindow()
def sendMessage(self, msg):
if not self._outStream:
return False
self._outStream << msg << '\n'
self._outStream.flush()
return self._outSocket.waitForBytesWritten()
def _onNewConnection(self):
if self._inSocket:
self._inSocket.readyRead.disconnect(self._onReadyRead)
self._inSocket = self._server.nextPendingConnection()
if not self._inSocket:
return
self._inStream = QTextStream(self._inSocket)
self._inStream.setCodec('UTF-8')
self._inSocket.readyRead.connect(self._onReadyRead)
if self._activateOnMessage:
self.activateWindow()
def _onReadyRead(self):
while True:
msg = self._inStream.readLine()
if not msg: break
self.messageReceived.emit(msg)
使用例子
python
def main():
UUID = 'PHIR-HWOH-MEIZ-AHTA'
APP = QtSingleApplication(UUID, sys.argv)
if APP.isRunning():
sys.exit(0)
WINDOW = MyApplication()
WINDOW.APP = APP
APP.setActivationWindow(WINDOW)
WINDOW.show()
sys.exit(APP.exec_())
if __name__ == "__main__":
main()
init.py
此文件为完整的应用
-
main:为启动函数
-
class HelpForm :帮助界面
-
class AboutForm :关于界面
-
class LicenseForm :版权页面
-
MyApplication:为主应用
下面change_value_p 开头为 调节主屏幕
下面change_value_s 开头为 调节副屏幕
pbr 是主屏亮度,pr,pg,pb 分别代表 RGB分量
看看调节主屏幕代码,
调节色彩分量均是使用 xrandr