我有一台联想 ThinkPad X230 平板电脑,装有 Ubuntu 16.04。它有一个可转换屏幕当它处于平板电脑模式时,触摸板仍然处于活动状态并造成混乱。
我创建了以下脚本并将其绑定到一内置按钮(通过自定义快捷方式):
#!/bin/bash -e
# Find the TouchPad device ID
ID="$(xinput | grep -ioP 'touchpad.*id=\K[0-9]*')"
if [ "$(LANG=C xinput --list-props "$ID" | awk 'NR==2{print $4}')" == "0" ]; then
# If the device is disabled, then enable it and kill 'onboard' virtual keyboard
xinput enable "$ID"; killall onboard; xrandr -o normal
elif [ "$(LANG=C xinput --list-props "$ID" | awk 'NR==2{print $4}')" == "1" ]; then
# If the device is enabled, then disable it and run 'onboard' virtual keyboard
xinput disable "$ID"; nohup onboard >/dev/null 2>&1 &
fi
脚本运行正常,但这是一个虚假的解决方案,昨天我花了几个小时学习如何以正确的方式做到这一点。所以我决定在这里分享这个经验。
答案1
要检查设备是否处于平板电脑模式,我们可以读取以下值(0
或1
):
/sys/devices/platform/thinkpad_acpi/hotkey_tablet_mode
此值由特定事件切换。我们可以捕获这些事件,并使用以下方法将脚本绑定到它们:acpid
- 高级配置和电源接口事件守护进程。
1.捕获事件。执行acpi_listen
或netcat -U /var/run/acpid.socket
,将盖子转入平板电脑模式,然后将其转回。以下是示例输出:
$ acpi_listen
video/tabletmode TBLT 0000008A 00000001
video/tabletmode TBLT 0000008A 00000000
请注意,当盖子关闭/打开时结果是不同的:
$ acpi_listen
button/lid LID close
button/lid LID open
2.配置acpid
以识别由设备模式更改触发的事件。将以下几行作为(单个)命令运行到终端中:
cat << EOF | sudo tee /etc/acpi/events/thinkpad-tablet-enabled
# /etc/acpi/events/thinkpad-tablet-enabled
# This is called when the lid is placed in tablet position on
# Lenovo ThinkPad X230 Tablet
event=video/tabletmode TBLT 0000008A 00000001
action=/etc/acpi/thinkpad-touchpad-twist-mode.sh 1
EOF
cat << EOF | sudo tee /etc/acpi/events/thinkpad-tablet-disabled
# /etc/acpi/events/thinkpad-tablet-disabled
# This is called when the lid is placed in normal position on
# Lenovo ThinkPad X230 Tablet
event=video/tabletmode TBLT 0000008A 00000000
action=/etc/acpi/thinkpad-touchpad-twist-mode.sh 0
EOF
上述命令将创建以下文件:
/etc/acpi/events/thinkpad-tablet-enabled
/etc/acpi/events/thinkpad-tablet-disabled
注意:这里不提供盖子打开/关闭的脚本。但它们与上面的类似。
3.重新启动acpid
以便它可以重新读取事件过滤器,包括您刚刚添加的过滤器:
sudo systemctl restart acpid.service
4./etc/acpi/thinkpad-touchpad-in-twist-mode.sh
创建禁用1
和启用0
触摸板的脚本(&&
使其可执行):
cat << EOF | sudo tee /etc/acpi/thinkpad-touchpad-twist-mode.sh && sudo chmod +x /etc/acpi/thinkpad-touchpad-twist-mode.sh
#!/bin/sh
LANG=C # Ensure stable parsing
export DISPLAY="\$(w | awk 'NF > 7 && \$2 ~ /tty[0-9]+/ {print \$3; exit}' 2>/dev/null)" # Get and export the current user's \$DISPAY
export XAUTHORITY="/home/\$(w | awk 'NF > 7 && \$2 ~ /tty[0-9]+/ {print \$1; exit}' 2>/dev/null)/.Xauthority" # Get and export the currentuser's \$XAUTHORITY
ID="\$(xinput | grep -ioP 'touchpad.*id=\K[0-9]*')" # Find the TouchPad device ID
if [ "\${1}" -eq 0 ]; then xinput enable "\$ID" # Laptop mode or Lid is open
elif [ "\${1}" -eq 1 ]; then xinput disable "\$ID" # Tablet mode or Lid is closed
fi
EOF
- 该脚本将解析并导出当前用户会话的环境变量
$DISPAY
和$XAUTHORITY
,以便分别允许root
(运行该acpid
进程的人)访问用户的 X 会话xinput
。 - 然后脚本将解析
$ID
触摸板。并根据输入变量的值$1
启用或禁用触摸板。
注意:美元符号前的反斜杠\$
用于转义cat
命令中的变量(命令替换)扩展。因此,如果您复制/粘贴脚本(而不是使用该cat
方法),则应手动将其删除。
参考:
- ArchWiki:
acpid
- 高级配置和电源接口事件守护进程。 - 询问 Ubuntu:当盖子放下时如何禁用触摸板?
- 思考维基:在 Thinkpad Twist 上安装 Ubuntu 12.10|Thinkpad-acpi|Wacom 数位板触控笔
- Ubuntu 论坛:触摸板打开/关闭|为什么这个 acpi 事件不起作用?
- 关于解析请阅读:
w
以编程方式使用和查找 DISPLAY 的当前值awk
和使用以下方法从行中删除特定单词grep -P '\K'
。
答案2
使用 pa4080 的答案,我必须进行以下更改才能使其在 Ubuntu 18.04 中运行:tim
在脚本中硬编码我的用户()并在我的用户上下文中运行该脚本。
文件/etc/acpi/events/thinkpad-lid-event
:
event=button/lid.*
action=su tim -c '/home/tim/scripts/lid.sh.post'
和lid.sh.post
:
#! /bin/bash
# toggle touchpad enabled status when lid changes (lid closed,touchpad off)
# is run in user context
#
# example rule /etc/acpi/events/thinkpad-lid-close
# event=button/lid.*
# action=su tim -c '/home/tim/scripts/lid.sh.post'
#
# see https://askubuntu.com/questions/91534/disable-touchpad-while-the-lid-is-down
# and https://askubuntu.com/questions/980997/how-do-i-disable-the-touchpad-when-the-lid-is-twisted-or-closed/980999#980999
# this needs an event defined in /etc/acpi/events to call this script when lid status changes
# these variables need to be set to use xinput properly
user="tim"
export XAUTHORITY=$(ls -1 /home/$user/.Xauthority | head -n 1)
export DISPLAY=":$(ls -1 /tmp/.X11-unix/ | sed -e s/^X//g | head -n 1)"
export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")
grep -q closed /proc/acpi/button/lid/*/state
LidClosedResult=$?
xinput set-int-prop $TouchPadID "Device Enabled" 8 $LidClosedResult
if [ $? -eq 0 ]; then
echo "for user: $user xinput device $TouchPadID enabled status changed to $LidClosedResult because of LID ACPI event" | systemd-cat
else
echo "failed to change xinput device $TouchPadID enabled status after LID ACPI event" | systemd-cat
fi
答案3
对‘lid’和‘tabletmode’进行了另一种变化,仅 2 条规则捕获来自 ACPI 事件的响应(在操作中使用“%e”,注意引号!):
#!/bin/bash
# toggle 'touchpad enabled status' off/on when lid changes (lid closed or tablet mode => touchpad off)
#
# let it act on 2 rules in /etc/acpi/events/: lid-change and tabletmode-change:
#
# event=button/lid.*
# action=/etc/acpi/touchpad-toggle.sh "%e"
#
# event=video/tabletmode.*
# action=/etc/acpi/touchpad-toggle.sh "%e"
#
# variables needed to use xinput properly
user1="$(who | cut -d ' ' -f1)"
export XAUTHORITY="$(ls -1 /home/$user1/.Xauthority | head -n 1)"
export DISPLAY=":$(ls -1 /tmp/.X11-unix/ | sed -e s/^X//g | head -n 1)"
export TPdID="$(xinput | grep -ioP 'touchpad.*id=\K[0-9]*')"
if [ "${@}" == "" ]; then
echo "ACPI event didn't return trigger values." | systemd-cat
elif [ "$user1" == "" ]; then
echo "ACPI event action didn't find current user." | systemd-cat
else
false
if [ "${@}" == "button/lid LID open" ]; then xinput enable $TPdID
elif [ "${@}" == "button/lid LID close" ]; then xinput disable $TPdID
elif [ "${@}" == "video/tabletmode TBLT 0000008A 00000000" ]; then xinput enable $TPdID
elif [ "${@}" == "video/tabletmode TBLT 0000008A 00000001" ]; then xinput disable $TPdID
fi
if [ $? -eq 0 ]; then
echo "ACPI event: xinput device $TPdID status changed on ${@}." | systemd-cat
else
echo "ACPI event failed: xinput device $TPdID status NOT changed on ${@}." | systemd-cat
fi
fi
享受使用脚本...
编辑:$USER 在由 root 使用时并不总是返回结果...因此我使用以下命令替换它:user1="$(who | cut -d ' ' -f1)"