acpid

出自 ArchWiki

acpid2 是一个灵活且可扩展的守护进程,用于传递 ACPI 事件。 当事件发生时,它会执行程序来处理该事件。 这些事件由某些操作触发,例如

  • 按下特殊按键,包括电源/睡眠/挂起按钮
  • 合上笔记本电脑盖子
  • (拔下)笔记本电脑的交流电源适配器
  • (拔下)电话插孔等。
注意: 桌面环境,例如 GNOMEsystemd 登录管理器和一些 额外的按键处理 守护进程可能会实现它们自己的事件处理方案,独立于 acpid。 同时运行多个系统可能会导致意外行为,例如在按下一次睡眠按钮后连续挂起两次。 您应该意识到这一点,并且仅激活所需的处理程序。

安装

安装 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/powerbutton/lidbutton/suspendbutton/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 识别对这些文件的更改。

使用此方法,可以轻松创建任意数量的单独事件/操作脚本。

技巧与诀窍

注意: 此处描述的某些操作(例如 Wi-Fi 开关和背光控制)可能已由驱动程序直接管理。 如果是这种情况,您应该查阅相应内核模块的文档。

示例事件

以下是可以在 /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+
注意: 这些命令可能无法与 PulseAudio 按预期工作。 [1] 为了实现完整功能,请在指定 XDG_RUNTIME_DIR 环境变量 时,以当前用户身份运行命令,例如使用
# sudo -u user XDG_RUNTIME_DIR=/run/user/user_id pactl
提示: 禁用或绑定 Xorg 中的音量按钮以防止与其他应用程序冲突。 有关详细信息,请参阅 Xmodmap

另请参阅 [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 显示以及 MIT 魔法 cookie 文件(通过 XAUTHORITY)。 后者是安全凭据,提供对 X 服务器、显示和任何输入设备的读写访问权限(请参阅 xauth(1))。

有关使用 xinitrc 时的示例函数,请参见 [3]

注意
  • 如果在盖子关闭时 LCD 背光灯未关闭,您可以手动执行此操作,方法是在盖子关闭和盖子打开事件时分别运行 getXuser xset dpms force offgetXuser xset dpms force on。 如果显示器已变黑,但背光灯仍然亮着,请改用 vbetool 以及 vbetool dpms offvbetool dpms on。 另请参阅 XScreenSaver#配置
  • 当使用 whow 时,请确保在启动时创建 /run/utmp。 有关详细信息,请参阅 utmp(5)

连接到 acpid 套接字

除了规则文件外,acpid 还接受 UNIX 域套接字上的连接,默认情况下为 /var/run/acpid.socket。 用户应用程序可以连接到此套接字。

#!/bin/bash
coproc acpi_listen
trap 'kill $COPROC_PID' EXIT

while read -u "${COPROC[0]}" -a event; do
    handler.sh "${event[@]}"
done

其中 handler.sh 可以是类似于 /etc/acpi/handler.sh 的脚本。

在 Wayland 下笔记本电脑盖子关闭时禁用键盘和触摸板

此示例使用输入设备驱动程序的 inhibited 属性来代替 xinput,后者在 Wayland 下不起作用。

	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
	;;

参见