Friday 3 July 2020

Linux Touch Screen transformation for Docking and Undocking laptops

I finally decided to fix the touchscreen calibration of my Linux laptop when I dock and undock it.

If you find the touch screen of your laptop is offset after you dock or undock or even change the screen resolution - this might help you.

The laptop is running XUbuntu 19.10 but this should work with any vanilla X install.

You first need to obtain the following:
  • xrandr - if not already installed run: apt install x11-xserver-utils
  • xinput - this can be installed with: apt install xinput 
  • panelName - the name of your laptop's display panel:
    run xrandr and it should be obvious which it is. On my Dell Precision 5510 it is "eDP-1":
eDP-1 connected 2560x1440+5120+0 (normal left inverted right x axis y axis) 346mm x 194mm 

  • touchScreenName - The name of your touch screen:
    Run xinput. On my laptop this shows as "ELAN Touchscreen": 
⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ ELAN Touchscreen                         id=12 [slave  pointer  (2)]
⎜   ↳ DLL06E5:01 06CB:7A13 Touchpad            id=13 [slave  pointer  (2)]
⎜   ↳ SEM USB Keyboard Consumer Control        id=16 [slave  pointer  (2)]
⎜   ↳ USB Optical Mouse                        id=18 [slave  pointer  (2)]
⎜   ↳ Realtek RTL2832U reference design        id=22 [slave  pointer  (2)]

Once you have these things then you can edit the panelName and touchScreenName shell variables at the top of the script below and run it from the command line to fix the touch positions on your laptop screen.

It works by calculating:
  • the x and y Transform ratios by dividing the panel's width and height by the overall screen's width and height;
  • the x and y Translations by dividing the panel's x and y offset by the screens width and height;
  • it then sets the Coordinate Transformation Matrix to the following:
| xTransform 0          xTranslation |
| 0          yTransform yTranslation |
| 0          0          1            |
See for further details on Transformation Matrices on Wikipedia.

# Set the Touch Transformation matrix for Touch Panels based on output of xrandr
#       Assumptions:
#       - Only one touch screen
#       - No Rotation

touchScreenName="ELAN Touchscreen"

die() {
        echo "$@"
        exit 1

ratio() {
        echo "scale=$dps; $dividend/$divisor" | bc -q


# Eg: Screen 0: minimum 320 x 200, current 7680 x 1440, maximum 16384 x 16384
screenWidth=`echo "$xrandr" | sed -n -e 's/^.*current \([0-9][0-9]*\) x \([0-9][0-9]*\),.*$/\1/p'`
screenHeight=`echo "$xrandr" | sed -n -e 's/^.*current \([0-9][0-9]*\) x \([0-9][0-9]*\),.*$/\2/p'`

# Eg: eDP-1 connected 2560x1440+0+0 (normal left inverted right x axis y axis) 346mm x 194mm
panelWidth=`echo "$xrandr" | sed -n -e 's/^'"$panelName"' connected \([0-9][0-9]*\)x\([0-9][0-9]*\)+\([0-9][0-9]*\)+\([0-9][0-9]*\) .*$/\1/p'`
panelHeight=`echo "$xrandr" | sed -n -e 's/^'"$panelName"' connected \([0-9][0-9]*\)x\([0-9][0-9]*\)+\([0-9][0-9]*\)+\([0-9][0-9]*\) .*$/\2/p'`
panelXOffset=`echo "$xrandr" | sed -n -e 's/^'"$panelName"' connected \([0-9][0-9]*\)x\([0-9][0-9]*\)+\([0-9][0-9]*\)+\([0-9][0-9]*\) .*$/\3/p'`
panelYOffset=`echo "$xrandr" | sed -n -e 's/^'"$panelName"' connected \([0-9][0-9]*\)x\([0-9][0-9]*\)+\([0-9][0-9]*\)+\([0-9][0-9]*\) .*$/\4/p'`

#echo $screenWidth $screenHeight
#echo $panelWidth $panelHeight

[ -z "$screenWidth" -o -z "$screenHeight" -o -z "$panelWidth" -o -z "$panelHeight" -o -z "$panelXOffset" -o -z "$panelYOffset" ]  \
        && die "Missing paramater:" \
                "screenWidth=$screenWidth screenHeight=$screenHeight" \
                "panelWidth=$panelWidth panelHeight=$panelHeight" \
                "panelXOffset=$panelXOffset panelYOffset=$panelYOffset"

xTransform=`ratio $panelWidth $screenWidth 6`
yTransform=`ratio $panelHeight $screenHeight 6`
xTranslate=`ratio $panelXOffset $screenWidth 6`
yTranslate=`ratio $panelYOffset $screenHeight 6`

echo "xinput --set-prop '$touchScreenName' 'Coordinate Transformation Matrix' $xTransform 0 $xTranslate 0 $yTransform $yTranslate 0 0 1"
xinput --set-prop "$touchScreenName" 'Coordinate Transformation Matrix' $xTransform 0 $xTranslate 0 $yTransform $yTranslate 0 0 1