跳转至内容

acpid

来自 ArchWiki

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

  • 按下特殊按键,包括电源/睡眠/暂停按钮
  • 关闭笔记本电脑盖子
  • (拔)插笔记本电脑的 AC 电源适配器
  • (拔)插电话插孔等
注意 桌面环境(如 GNOME)、systemd 登录管理器以及一些 额外按键处理 守护进程可能会实现自己独立于 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/power, button/lid, button/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 display 以及 MIT magic cookie 文件(通过 XAUTHORITY)。后者是一种安全凭证,提供对 X 服务器、显示器和任何输入设备的读写访问权限(请参阅 xauth(1))。

在使用 xinitrc 时的示例函数请参阅 [3]

  • 如果关闭盖子时 LCD 背光没有关闭,你可以通过在盖子关闭和打开事件上分别运行 getXuser xset dpms force offgetXuser xset dpms force on 来手动关闭。如果显示屏已黑屏但背光仍然开启,请改用 vbetool 运行 vbetool dpms offvbetool dpms on。另请参阅 XScreenSaver#Configuration
  • 使用 whow 时,请确保在启动时创建了 /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
	;;

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.