4

I have Lenovo ThinkPad X230 Tablet with Ubuntu 16.04. It has a convertible screen and when it is in tablet mode the touchpad is still active and make a mess.

I've created the following script and bound it to one of the built in buttons (by a custom shortcut):

#!/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

The script works properly, but this is a fake solution and yesterday I spent few hours to learn how to do that in a proper way. So I decided to share this experience here.

pa4080
  • 29,831

3 Answers3

2

To check whether the device is in tablet mode or not we could read the value (0 or 1) of:

/sys/devices/platform/thinkpad_acpi/hotkey_tablet_mode

This value is switched by specific events. We can catch these events and could bind scripts to them by using acpid - Advanced Configuration and Power Interface event daemon.


1. Catch the events. Execute acpi_listen or netcat -U /var/run/acpid.socket, turn the lid in tablet mode, then turn it back. Here is an example output:

$ acpi_listen
video/tabletmode TBLT 0000008A 00000001
video/tabletmode TBLT 0000008A 00000000

Please note when the lid is close/open the result is different:

$ acpi_listen
button/lid LID close
button/lid LID open

2. Configure acpid to recognize the events triggered by the device mode change. Run the following lines into a terminal as (single) commands:

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

The above commands will create the files:

  • /etc/acpi/events/thinkpad-tablet-enabled
  • /etc/acpi/events/thinkpad-tablet-disabled

Note: The scripts for lid open/close aren't provided here. But they are similar as the above.


3. Restart acpid so it can re-read the event filters, including the ones you just added:

sudo systemctl restart acpid.service

4. Create the script /etc/acpi/thinkpad-touchpad-in-twist-mode.sh that will disable 1 and enable 0 the touchpad (&& make it executable):

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
  • The script will parse and export the environment variables $DISPAY and $XAUTHORITY of the current user's session, in order to allow root (who runs the acpid process) to access the user's X session, respectively xinput.
  • Then the script will parse the $ID of the touchpad. And depending on the value of the input variable $1 it will enable or disable the touckpad.

Note: The backslashes before the dollar signs \$ are intended to escape the variable (command substitution) expansion within the cat command. So if you copy/paste the script (instead using of the cat approach) you should remove them manually.


References:

pa4080
  • 29,831
1

Using the answer of pa4080, I had to make this change for it to work in Ubuntu 18.04: hard code my user (tim) in the script and run the script in the context of my user.

File /etc/acpi/events/thinkpad-lid-event:

event=button/lid.*
action=su tim -c '/home/tim/scripts/lid.sh.post'

and 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

Pablo Bianchi
  • 15,657
Tim Richardson
  • 2,294
  • 3
  • 25
  • 43
1

Made another variation acting on 'lid' and 'tabletmode' and just 2 rules catching the response from the ACPI events (use "%e" in the action, mind the quotes !):

#!/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

Enjoy using the script ...

Edit: $USER doesn't always return a result when used by root ... So I replaced it using: user1="$(who | cut -d ' ' -f1)"

Bart
  • 271