acpid
acpid2 是一个灵活且可扩展的守护进程,用于传递 ACPI 事件。当事件发生时,它会执行程序来处理该事件。这些事件由某些动作触发,例如:
- 按下特殊按键,包括电源/睡眠/暂停按钮
- 关闭笔记本电脑盖子
- (拔)插笔记本电脑的 AC 电源适配器
- (拔)插电话插孔等
安装
安装 acpid 软件包。然后 启动/启用 acpid.service。
配置
acpid 附带了许多针对触发事件的预定义动作,例如按下机器电源按钮时应该发生什么。默认情况下,这些动作定义在 /etc/acpi/handler.sh 中,该脚本在检测到任何 ACPI 事件后执行(由 /etc/acpi/events/anything 确定)。
确定事件
遗憾的是,并非每台计算机对 ACPI 事件的标注方式都相同。例如,睡眠按钮在一部机器上可能被识别为 SLPB,而在另一部机器上则为 SBTN。
要确定你的按钮或 Fn 快捷键是如何被识别的,请运行以下命令:
# journalctl -f
现在按下机器上的电源按钮和/或睡眠按钮(例如 Fn+Esc)。结果应该看起来像这样:
logger: ACPI action undefined: PBTN logger: ACPI action undefined: SBTN
如果不起作用,请运行:
# acpi_listen
或者使用 openbsd-netcat:
$ netcat -U /var/run/acpid.socket
然后按下电源按钮,你会看到类似这样的内容:
button/power PBTN 00000000 00000b31
acpi_listen 的输出会作为 $1, $2 , $3 和 $4 参数发送到 /etc/acpi/handler.sh。示例:
$1 button/power $2 PBTN $3 00000000 $4 00000b31
定义事件动作
以下是一个此类动作的简短示例。在这种情况下,当按下睡眠按钮时,acpid 运行命令 echo -n mem >/sys/power/state,这应该会将计算机置于睡眠(暂停)状态。
button/sleep)
case "$2" in
SLPB) echo -n mem >/sys/power/state ;;
*) logger "ACPI action undefined: $2" ;;
esac
;;
不同机器上的事件可能不同。例如,如果睡眠按钮实际被识别为 SBTN,而不是默认 /etc/acpi/handler.sh 中指定的 SLPB 标签。为了让睡眠功能在该机器上正常工作,我们需要将 SLPB) 替换为 SBTN)。
以此信息为基础,你可以轻松自定义 /etc/acpi/handler.sh 文件,以根据触发的事件执行各种命令。请参阅下面的 #技巧与窍门 部分了解其他常用命令。
button/power, button/lid, button/suspend 和 button/hibernate 等事件默认由 systemd-logind.service(8) 处理,请参阅 电源管理#ACPI 事件。如果使用 acpid 处理这些事件,则应先禁用或抑制 logind 对这些事件的处理。替代配置
默认情况下,所有 ACPI 事件都通过 /etc/acpi/handler.sh 脚本传递。这是由于 /etc/acpi/events/anything 中概述的规则集决定的。
# Pass all events to our one handler script event=.* action=/etc/acpi/handler.sh %e
虽然这样做完全没问题,但一些用户可能更喜欢在自己的独立脚本中定义事件规则和动作。以下是如何使用单个事件文件和相应动作脚本的示例:
以 root 身份创建以下文件:
/etc/acpi/events/sleep-button
event=button/sleep.* action=/etc/acpi/actions/sleep-button.sh %e
/etc/acpi/actions/sleep-button.sh
#!/bin/sh
case "$3" in
SLPB) echo -n mem >/sys/power/state ;;
*) logger "ACPI action undefined: $3" ;;
esac
使脚本 可执行,并 重新加载 acpid.service,以便 acpid 识别这些文件的更改。
使用此方法,可以轻松创建任意数量的独立事件/动作脚本。
技巧与提示
事件示例
以下是在 /etc/acpi/handler.sh 脚本中可使用的事件示例。这些示例应根据你的具体环境进行修改,例如更改 acpi_listen 解释的事件变量名称。
根据是否接入电源设置笔记本屏幕亮度(数字可能需要调整,请参阅 /sys/class/backlight/acpi_video0/max_brightness):
ac_adapter)
case "$2" in
AC*|AD*)
case "$4" in
00000000)
echo -n 50 > /sys/class/backlight/acpi_video0/brightness
;;
00000001)
echo -n 100 > /sys/class/backlight/acpi_video0/brightness
;;
esac
启用音量控制
找出音量按钮的 acpi 标识(见上文),并将其替换为下面文件中的 acpi 事件。
/etc/acpi/events/vol-d
event=button/volumedown action=amixer set Master 5-
/etc/acpi/events/vol-m
event=button/mute action=amixer set Master toggle
/etc/acpi/events/vol-u
event=button/volumeup action=amixer set Master 5+
XDG_RUNTIME_DIR 环境变量 的情况下,以当前用户身份运行命令,例如:# sudo -u user XDG_RUNTIME_DIR=/run/user/user_id pactl
另请参阅 [2]。
启用背光控制
与音量控制类似,acpid 可以启用对屏幕背光的控制;为此,请编写一个如下的处理器:
/etc/acpi/handlers/bl
#!/bin/sh bl_dev=/sys/class/backlight/acpi_video0 step=1 case $1 in -) echo $(($(< $bl_dev/brightness) - $step)) >$bl_dev/brightness;; +) echo $(($(< $bl_dev/brightness) + $step)) >$bl_dev/brightness;; esac
acpi_listen 中的事件应该是类似这样的:
video/brightnessdown BRTDN 00000087 00000000 video/brightnessup BRTUP 00000086 00000000
将它们连接到 ACPI 事件:
/etc/acpi/events/bl_d
event=video/brightnessdown.* action=/etc/acpi/handlers/bl -
/etc/acpi/events/bl_u
event=video/brightnessup.* action=/etc/acpi/handlers/bl +
启用 Wi-Fi 开关
你还可以通过按下 WLAN 按钮创建一个简单的无线电源开关。这是一个示例:
/etc/acpi/events/wlan
event=button/wlan action=/etc/acpi/handlers/wlan
及其处理器:
/etc/acpi/handlers/wlan
#!/bin/sh rf=/sys/class/rfkill/rfkill0 case $(< $rf/state) in 0) echo 1 >$rf/state;; 1) echo 0 >$rf/state;; esac
禁用普通按键事件
自从 b336c96 以来,acpid 为某些普通按键(如方向键)生成事件。这会导致事件/处理器刷屏,在系统日志或 top 中可见。这些按钮的事件可以在配置文件中丢弃:
/etc/acpi/events/buttons
event=button/(up|down|left|right|kpenter) action=<drop>
获取当前显示器的用户名
要运行依赖于 Xorg 的命令,需要定义 X display 以及 MIT magic cookie 文件(通过 XAUTHORITY)。后者是一种安全凭证,提供对 X 服务器、显示器和任何输入设备的读写访问权限(请参阅 xauth(1))。
- 如果关闭盖子时 LCD 背光没有关闭,你可以通过在盖子关闭和打开事件上分别运行
getXuser xset dpms force off和getXuser xset dpms force on来手动关闭。如果显示屏已黑屏但背光仍然开启,请改用 vbetool 运行vbetool dpms off和vbetool dpms on。另请参阅 XScreenSaver#Configuration。 - 使用 who 或 w 时,请确保在启动时创建了
/run/utmp。详情请参阅 utmp(5)。
连接到 acpid socket
除了规则文件,acpid 还在 UNIX 域 socket(默认 /var/run/acpid.socket)上接受连接。用户应用程序可以连接到此 socket。
#!/bin/sh
acpi_listen | while read -r event; do
handler.sh "$event"
done
其中 handler.sh 可以是一个类似于 /etc/acpi/handler.sh 的脚本。
在 Wayland 下笔记本盖子关闭时禁用键盘和触摸板
本示例使用输入设备驱动程序的 inhibited 属性来替代在 Wayland 下不起作用的 xinput。
button/lid) if echo "$3" | grep -iq "open"; then echo 'LID opened' disabled=0 fi if echo "$3" | grep -iq "close"; then echo 'LID closed' disabled=1 fi find /sys/devices/platform/i8042/serio* -prune -type d | while IFS= read -r serionumber; do find $serionumber/input/* -prune -type d | while IFS= read -r inputdevicepath; do if grep -q -i -e "keyboard" -e "touchpad" $inputdevicepath/name; then logger "found $(cat $inputdevicepath/name) and set to $disabled" echo $disabled > $inputdevicepath/inhibited fi done done ;;