I have an old HP laptop with a touchscreen that keeps registering phantom taps, so I can't use it with Ubuntu Linux unless I find a way to suppress the touchscreen input. This was implemented on Ubuntu 22.10. I'm sure more skilled shell script authors can do this more easily than I did with Python below, but this has worked for me and perhaps it will help you.
The Strategy
The basics are to (a) reliably find the device at boot time, then (b) capture all of its input so it doesn't affect the system. I tried several other tutorials to try and turn off the device at boot time but I was not able to get that strategy to work.
Packages to Install
First up we need two new packages -- libinput-tools
and evtest
-- as well as Python 3.
sudo apt install libinput-tools
sudo apt install evtest
The Commands
This command will show us the devices. One of these will be the touchscreen:
sudo libinput list-devices
Devices are shown in blocks and there are two important fields. The Device
and the Kernel
. I've read that the event number attached to the device can change at boot time.
Here's an example of just two entries in the output of that libinput
command:
Device: eGalax Inc. eGalaxTouch EXC7910-1023-12.00.00
Kernel: /dev/input/event5
Group: 7
Seat: seat0, default
Size: 341x195mm
Capabilities: touch
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: identity matrix
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles: n/a
Rotation: n/a
Device: HP Truevision HD: HP Truevision
Kernel: /dev/input/event17
Group: 8
Seat: seat0, default
Capabilities: keyboard
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: n/a
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles: n/a
Rotation: n/a
The Capabilities: touch
line is the key. I want the "eGalax" device, and the Kernel
event is what we need:
Device: eGalax Inc. eGalaxTouch EXC7910-1023-12.00.00
Kernel: /dev/input/event5
To see if this is the right device, we use this evtest
command to capture the input from that device and send it to null to prevent it from registering touches to the screen:
sudo evtest --grab /dev/input/event5 > /dev/null
We will create a new service to be run by systemd at boot time to do this job for us.
The systemd Game Plan
- Create a .sh file to be run by the service (see file below).
- Copy the script to
/usr/local/bin/
- Make it executable (
sudo chmod +x /usr/local/bin/scriptname.sh
) - Copy the
event_of_device.py
to/root/
(sudo cp event_of_device.py /root/
) - Create a service unit file (see file below).
- Find a name not taken. View results at:
sudo systemctl list-unit-files --type=service
- Place the .service file in
/etc/systemd/system/
folder. - Set permissions on the .service file:
sudo chmod 640 /etc/systemd/system/filename.service
- Check the syntax:
sudo systemctl status filename.service
- Reload the unit file definitions:
sudo systemctl daemon-reload
- Set the service to start at boot time:
sudo systemctl enable servicename
- Start the service:
sudo systemctl start servicename
- Verify it is running:
sudo systemctl status servicename.service
- To stop the service,
sudo systemctl stop servicename.service
- To keep it from being launched at startup:
sudo systemctl disable servicename.service
The Files for Steps 1, 4 and 5 are below.
1. Create a .sh file to be run by the service.
Here's the shell script file. It runs the python program the first time to drop the information into a txt file so we can see what happened at runtime, then runs it again to store the value. You'll replace the eGalax
with the substring matching your particular touchscreen device.
touchscreen_disable.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
4. Copy the event_of_device.py
to /root/
(sudo cp event_of_device.py /root/
)
I created a python program to parse the libinput output and find a particular device by substring of the name. I'm sure experienced Python coders could do a much better job but it works. It's called event_of_device.py
import sys
from os.path import exists
import argparse
# event_of_device.py
#
# Script to parse the text output of sudo libinput list-devices, find a given device, and output
# the part after a colon in the first "kernel" line after the device name is found.
# Written because I have no idea how to use awk to do this, and because I know a little bit about
# python. Oh, really why was it written? Oh because I needed to find a touchscreen device, and
# tell evtest to grab all of its events and send it to null to keep an old laptop from randomly
# giving touches on screen when running Ubuntu 22.10 using the command
# "sudo evtest --grab /dev/input/event5 > /dev/null"
# Where the /dev/input/event5 is an example of what this script will output.
#
# 2023-02-14 by REDACTED
# 2023-02-25 updated to use argparse library to parse arguments.
# variables
sDevice = ""
sInputFile = ""
oFile = None
listIn = None
sLine = ""
nLine = -1
nFound = -1
nDeviceLine = -1
nKernelLine = -1
sEvent = ""
sOut = ""
listError = []
sUsage = ""
sVersion = "2023-02-25.21"
# Debugging flag
bDebug = False
# maximum rows allowed in input file, 12k sounds good
nBytesCap = (12*1024)
# Python doesn't have a null, but the None can be tested using "is" not "==".
# parse the command line arguments
parser = argparse.ArgumentParser(
description='Searches the input file for the block containing the device value, returns the Kernel value from that block.',
epilog='Version '+sVersion
)
parser.add_argument("-d", "--device", required=True, type=str,
help="device string to search for")
parser.add_argument("-i", "--inputfile", required=True, type=str,
help="file containing the output of 'sudo libinput list-devices'")
args = parser.parse_args()
# fetch parameter values
sDevice = args.device
sInputFile = args.inputfile
if(bDebug):
print("Device: " + sDevice)
print("Input File: " + sInputFile)
# does the file with that name exist?
if(not(exists(sInputFile))):
listError.append("InputFilename file \""+sInputFile+"\" not found.")
# show the error if we have one
if(len(listError) > 0):
sError = ""
for sLine in listError:
sError = sError + sLine + "\n"
parser.print_help()
raise ValueError(sError)
# open file is read, text modes
oFile = open(sInputFile, "rt")
# grab the first set of bytes from the file
listIn = oFile.readlines(nBytesCap)
# Each device in the file is separated by a single
# \n new line character blank line.
# find the first row in the list with a
# substring matching the device
# if none is found, throw an error and exit
nFound = -1
nDeviceLine = -1
nLine = 0
while (nLine < len(listIn)) and (nFound == -1):
sLine = listIn[nLine]
nFound = sLine.find(sDevice)
if nFound > -1:
nDeviceLine = nLine
if(bDebug):
print("Line \"" + sLine + "\" nFound = "+str(nFound))
nLine = nLine + 1
if(bDebug):
print("Device found value: " + str(nFound))
print("Device on line " + str(nDeviceLine))
print("Lines searched: "+str(nLine))
# find the Kernel line after the device line.
if nDeviceLine > -1:
nFound = -1
nLine = nDeviceLine + 1
while (nLine < len(listIn) and (nFound == -1)):
sLine = listIn[nLine]
nFound = sLine.find("Kernel:")
if nFound > -1:
nDeviceLine = nLine
nLine = nLine + 1
# did we find it?
if nDeviceLine > -1:
# take the event value after the tab.
listEvent = listIn[nDeviceLine].split(":")
if len(listEvent) > 0:
sEvent = listEvent[1].strip()
if(bDebug):
print("Event value: " + sEvent)
# send out the event
sOut = sEvent
# close the file.
oFile.close()
# show the output value
print(sOut)
5. Create a service unit file
This file is named touchscreen-disable.service
[Unit]
Description=Captures all touchscreen events to effectively disable it.
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/touchscreen-disable.sh
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=default.target
Like I said, I'm sure there are more elegant ways to do it, but this is how I got it to work. I hope it helps you.