A better script for Wacom with screen geometry changes

Why and how

This is a better script to set your stylus setting to match a changed resolution, like if you plugged in to a projector. If you are mirroring screens, the geometry may change, so that instead of using your whole 16/9 ratio screen, you’re only using a 4/3 box in the middle. The problem you may run into is that your stylus does not adjust and so where you’re pointing the stylus may differ significantly from where the pointer appears on the screen. This script fixes that.
There are some dependencies: xsetwacom xrandr, and wcalc. Make sure you have xsetwacom by typing:

which xsetwacom

If it doesn’t give you a path, you need to:

sudo apt-get install xsetwacom

Do the same for xrandr. Finally, you need wcalc, which is not installed by default. Type:

sudo apt-get install wcalc

The script is below. To save it, copy it to the clipboard starting from just below the ‘Script’ subheader and ending just above the ‘Commentary’ subheader. Then type the following in the terminal:

cd
mkdir bin
cd bin
touch stylus_script.sh
chmod +x stylus_script.sh
gedit stylus_script.sh

Don’t worry if you get an error saying bin already exists. Just carry on.

Gedit should open with a blank file. Paste the script into that file. Then save and quit. You may not need to make any changes. (See commentary.)
You’ll want to run this script when you plug into a projector (after you set the resolution you’re going to use) and then again when you unplug from it. Do this in the terminal by typing:

~/bin/stylus_script.sh

You can run these from any terminal window, at any time and it should work. If you get errors or it just doesn’t do anything, see the commentary below.

Script

#!/bin/bash


function touch_ratio {
 #get pen geometry
 LINE=`xsetwacom get "Wacom ISDv4 E6 Pen stylus" area`
 echo ${LINE}
 TabTx=`echo ${LINE} | awk '{ print $1 }'`
 TabTy=`echo ${LINE} | awk '{ print $2 }'`
 TabBx=`echo ${LINE} | awk '{ print $3 }'`
 TabBy=`echo ${LINE} | awk '{ print $4 }'`

 TouchHeight=$((${TabBy} -${TabTy}))
 TouchWidth=$((${TabBx} -${TabTx}))

 TouchRatio=`wcalc -q ${TouchWidth}/${TouchHeight}`

}



# get screen geometry
LINE=`xrandr -q | grep Screen`
WIDTH=`echo ${LINE} | awk '{ print $8 }'`
HEIGHT=`echo ${LINE} | awk '{ print $10 }' | awk -F"," '{ print $1 }'`
RATIO=`wcalc -q ${WIDTH}/${HEIGHT}`



touch_ratio

# is the touch ratio different from the screen ratio?
change=`wcalc -q abs(${TouchRatio}-${RATIO})>0.01`
wcalc -q abs(${TouchRatio}-${RATIO})
if [[ ${change} != 0 ]] 
  then

 #they differ

 # first try resetting
 xsetwacom set "Wacom ISDv4 E6 Pen stylus" ResetArea
 xsetwacom set "Wacom ISDv4 E6 Pen eraser" ResetArea 
 xsetwacom set "Wacom ISDv4 E6 Finger touch" ResetArea

 # how about now?
 touch_ratio
 
 if [[ `wcalc -q abs(${TouchRatio}-${RATIO})>0.01` != 0 ]] #they differ
   then

  if [[ ${TouchRatio} > ${RATIO} ]] # width has shrunk
    then
   # use existing height values
   TYOFFSET=${TabTy};
   BYOFFSET=${TabBy};

   # calculate new width values
   # width = ratio * height
   
   NewTabWidth=`wcalc -q -P0 ${RATIO}*${TouchHeight}`
   TabDiff=$(( (${TouchWidth} - ${NewTabWidth}) / 2));

   TXOFFSET=$((${TabTx} + ${TabDiff}));
   BXOFFSET=$((${TabBx}- ${TabDiff}));

    else # height has shrunk

   # use existing width values
   TXOFFSET=${TabTx};
   BXOFFSET=${TabBx};

   # calculate new height values
   # height = width / ratio

   NewTabHeight=`wcalc -q -P0 ${TouchWidth}/${RATIO}`
   TabDiff=`wcalc -q (${TouchHeight}-${NewTabHeight})/2`
   
   TYOFFSET=`wcalc -q ${TabTy}+${TabDiff}`
   BYOFFSET=`wcalc -q ${TabBy}-${TabDiff}`

    fi


  echo ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Pen stylus" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Pen eraser" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Finger touch" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}

   fi
 #gnome-control-center wacom
  else
 echo normal resolution
fi

Commentary

If this script doesn’t work, it may be because the name of your wacom devices differs from mine. To find the names of your devices, type:

xsetwacom --list

You will get a list of your wacom devices. Mine looks like this:

Wacom ISDv4 E6 Pen stylus        id: 10 type: STYLUS    
Wacom ISDv4 E6 Finger touch      id: 11 type: TOUCH     
Wacom ISDv4 E6 Pen eraser        id: 15 type: ERASER    

In this script, I use the information at the far left: ‘Wacom ISDv4 E6 Pen stylus’ and the two identifiers below that. If your device list has different names, then replace the names in the script with the names of your devices. So if you have, ‘Wacom ISDv7 E13 Pen Stylus’, you would use that instead. These lines show up multiple places in the script, so if you need to change it, make sure you get it every time, down to the bottom of the file.

How it works

This script gets the geometry of your screen and the geometry of your stylus and calculates the width/height ratio for each. If this differs by more than a fractional amount, it calculates a new width or height for your stylus.

Script to modify wacom tablet settings to reflect a changed screen geometry

Update

This script has now been replaced with a better version: http://www.celesteh.com/blog/2013/05/26/a-better-script-for-wacom-with-screen/. You will want to use the newer script instead.

Why you would need this and how to use it

Ok, let’s say you have a tablet computer and you want to mirror your display to a projector and you want to use your stylus. Your screen geometry may change, so that instead of using your whole 16/9 ratio screen, you’re only using a 4/3 box in the middle. The problem you may run into is that your stylus does not adjust and so where you’re pointing the stylus may differ significantly from where the pointer appears on the screen. This script fixes that.
There are some dependencies. Make sure you have xsetwacom by typing:

which xsetwacom

If it doesn’t give you a path, you need to: sudo apt-get install xsetwacom
and you need wcalc, which is not installed by default. Type:

sudo apt-get install wcalc

The script is below. To save it, copy it to the clipboard starting from just below the ‘Script’ subheader and ending just above the ‘Commentary’ subheader. Then type the following in the terminal:

cd
mkdir bin
cd bin
touch stylus_script.sh
chmod +x stylus_script.sh
gedit stylus_script.sh

Don’t worry if you get an error saying bin already exists. Just carry on.
Gedit should open with a blank file. Paste the script into that file. Before you save and quit, you will need to make a small change to the top of the script with your own default screen geometry. To find this out, unplug all projectors, etc and open your system settings and look at displays. Set your display to however it is normally. The resolution should have two numbers. In my case they are 1366 x 768. The first is the width and the second is the height. Therefore, at the top of my script, I have:

# change these lines to match your normal screen geometry (note: we assume this normally takes up your whole screen)
NormalWidth=1366
NormalHeight=768

If your display is 1280 x 720, then you would change that to:

NormalWidth=1280
NormalHeight=720

Once you have the correct values in there, save it and you don’t need to change it again. You only have to do all of the above just the one time.
You’ll want to run this script when you plug into a projector (after you set the resolution you’re going to use) and then again when you unplug from it. Do this in the terminal by typing:

source stylus_script.sh

Do it in the same terminal both times.(Further optional commentary about that and other issues is at the bottom of the post.) When you run it the second time, after unplugging the projector, it should put your stylus settings back to normal. Your settings should also reset to normal if you log out and log back in again. If you can’t run this twice from the same terminal, or if that doesn’t work, then you will need to log out and back in.

Script

#!/bin/bash

# check the screen geometry

# change these lines to match your normal screen geometry (note: we assume this normally takes up your whole screen)
NormalWidth=1366
NormalHeight=768

# the script


NormalRatio=`wcalc -q ${NormalWidth}/${NormalHeight}`

LINE=`xrandr -q | grep Screen`
WIDTH=`echo ${LINE} | awk '{ print $8 }'`
HEIGHT=`echo ${LINE} | awk '{ print $10 }' | awk -F"," '{ print $1 }'`
RATIO=`wcalc -q ${WIDTH}/${HEIGHT}`


if  [[ ${NormalRatio} != ${RATIO} ]] # screen is not in normal configuration
  then
 if [[ (! $ALREADYRECALIBRATED ) || ($ALREADYRECALIBRATED == 0)]] # we haven't already adjusted
   then
  LINE=`xsetwacom get "Wacom ISDv4 E6 Pen stylus" area`

  export TabTx=`echo ${LINE} | awk '{ print $1 }'`
  export TabTy=`echo ${LINE} | awk '{ print $2 }'`
  export TabBx=`echo ${LINE} | awk '{ print $3 }'`
  export TabBy=`echo ${LINE} | awk '{ print $4 }'`

  OldTabHeight=$((${TabBy} -${TabTy}))
  OldTabWidth=$((${TabBx} -${TabTx}))

  if [[ ${NormalRatio} > ${RATIO} ]] # width has shrunk
    then
   # use old height values
   TYOFFSET=${TabTy};
   BYOFFSET=${TabBy};

   # calculate new width values
   # width = ratio * height
   
   NewTabWidth=`wcalc -q -P0 ${RATIO}*${OldTabHeight}`
   TabDiff=$(( (${OldTabWidth} - ${NewTabWidth}) / 2));

   TXOFFSET=$((${TabTx} + ${TabDiff}));
   BXOFFSET=$((${TabBx}- ${TabDiff}));

    else # height has shrunk

   # use old width values
   TXOFFSET=${TabTx};
   BXOFFSET=${TabBx};

   # calculate new height values
   # height = width / ratio

   NewTabHeight=`walc -q -P0 ${OldTabWidth}/${RATIO}`
   TabDiff= $(( (${OldTabHeight} - ${NewTabHeight}) / 2));
   
   TYOFFSET=$((${TabTy} + ${TabDiff}));
   BYOFFSET=$((${TabBy}- ${TabDiff}));

    fi
  #echo ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Pen stylus" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Pen eraser" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}
  xsetwacom set "Wacom ISDv4 E6 Finger touch" Area ${TXOFFSET} ${TYOFFSET} ${BXOFFSET} ${BYOFFSET}

  export ALREADYRECALIBRATED=1
   fi
 #gnome-control-center wacom
  else
 echo normal resolution
 # check if we've done some past calibration
 if [[ $ALREADYRECALIBRATED  && $ALREADYRECALIBRATED == 1 ]]
   then
  xsetwacom set "Wacom ISDv4 E6 Pen stylus" Area $TabTx $TabTy $TabBx $TabBy
  echo previous calibration restored
  export ALREADYRECALIBRATED=0
   fi
fi

Commentary

If you chose to run this some other way than typing ‘source stylus_script.sh’ in the terminal when plugging in a projector and then running it the same way again in the same terminal when unplugging the projector, it will not be able to restore your normal settings. You can try running the calibration tool to fix your settings or else log out and log back in again. The reason it needs to be run twice from the same terminal is because it stores your default settings in environment variables. There are undoubtedly better ways of doing this, so please leave a comment if you’ve got code that does it better.
If you normally run your screen display in a different ratio than the physical device, I’m not 100% the maths for this script will be correct for you. Let me know in the comments if you need help in this case.
The tablet height as seen by the wacom device is very different than the height in pixels. This makes sense because pixel size can change dramatically but the physical size of screen in use will stay the same. I assume that any change in display size will be letter-boxed either on the top and bottom or on the sides, but will always be centred and will never have blank space on both the sides and the top and bottom at the same time. If you don’t follow these assumptions, this script will require some modifications to work for you.