I've had a Wacom graphics tablet for a number of years now. I've never been completely happy with it's performance in either Windows or Linux - pointer movement was jerky and the accleration far too aggressive. Also switching between the configuration options appropriate for particular tasks, such as general desktop use or photo editing was tedious and convoluted. To switch between relative or screen mapped pointer motion, or to change the mapped screen, I would have to bring up the control panel and click through the settings. More often than not I would use the mouse to get something done quickly, although the tablet would have been more suitable.

Recently I tested out the libinput wacom driver on Linux and it's a huge improvement over the Xorg driver in my opinion. No more jerky pointer movement and with a slight tweak to the accleration value, the tablet finally feels really good to use. Also, with libinput being the future Wayland driver, I know that this configuration is future-proofed when I finally have to move from Xorg. With that in mind, I thought it would be worth taking the time myself to address the remaining configuration issues and make the tablet really useful.

To do this, I would need to use udev to detect when the tablet is connected and configure it (it can only be configured with xinput after it is connected). Taking advice from the StackExchange forums, I decided to use pyudev, a Python library providing a high-level interface to udev and greatly simplifiying the process. A single python script without escalated privileges is sufficient to detect tablet connection and trigger reconfiguration. It is triggered as a KDE startup script and kept running as a service:

#!/usr/bin/env python3

import pyudev
import subprocess
import pprint

from evdev import InputDevice,list_devices
devices = [InputDevice(fn) for fn in list_devices()]

def main():
    context = pyudev.Context()
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by(subsystem='input')
    monitor.start()

    for device in iter(monitor.poll, None):
        if 'NAME' in device:
            if device['NAME'] == '"Wacom Bamboo 2FG 6x8 Pen"':
                if device['ACTION'] == 'add':
                    subprocess.call(['/home/rob/scripts/wacom-bamboo/wacom-connect.sh'])
                elif device['ACTION'] == 'remove':
                    subprocess.call(['/home/rob/scripts/wacom-bamboo/wacom-disconnect.sh'])

if __name__ == '__main__':
    main()

The script wacom-connect.sh uses xinput to configure the tablet pointer/buttons and set the default screen mapping.

#!/bin/bash

sleep 1
natscrollpropid=$(xinput list-props "Wacom Bamboo 2FG 6x8 Finger" | grep 'Natural Scrolling Enabled (' | awk -F '[(), \t]*' '{print $6}')
draglockpropid=$(xinput list-props "Wacom Bamboo 2FG 6x8 Finger" | grep 'Tapping Drag Lock Enabled (' | awk -F '[(), \t]*' '{print $7}')
accelspeedpropid=$(xinput list-props "Wacom Bamboo 2FG 6x8 Finger" | grep 'libinput Accel Speed (' | awk -F '[(), \t]*' '{print $5}')

xinput set-button-map "Wacom Bamboo 2FG 6x8 Pad" 18 17 16 4 5 6 7 15
xinput set-prop "Wacom Bamboo 2FG 6x8 Finger" $natscrollpropid 1
xinput set-prop "Wacom Bamboo 2FG 6x8 Finger" $draglockpropid 1
xinput set-prop "Wacom Bamboo 2FG 6x8 Finger" $accelspeedpropid -.2

hdmi=$(xrandr --listmonitors | grep HDMI | awk '{print $4}')
file="/home/rob/scripts/wacom-bamboo/WACOM-PEN-MAPPING-STATE"
state=$(cat $file)

if [ "$state" = "eDP-1" ];then
    xinput map-to-output "Wacom Bamboo 2FG 6x8 Pen Pen (0)" "eDP1"
elif [ "$state" = "HDMI-1" ] && [ "$hdmi" = "HDMI-1" ];then
    xinput map-to-output "Wacom Bamboo 2FG 6x8 Pen Pen (0)" "HDMI1"
fi

notify-send -a 'Wacom Bamboo' 'Wacom Bamboo Connected' -i /usr/share/icons/breeze/devices/64/input-tablet.svg

Lastly it sends me a handy notification to the desktop to let me know that this has all taken place.

The top two tablet buttons now call scripts to change the screen mapping and toggle touch on and off. Further desktop notifications are sent to provide feedback:

#!/bin/bash

hdmi=$(xrandr --listmonitors | grep HDMI | awk '{print $4}')
file="/home/rob/scripts/wacom-bamboo/WACOM-PEN-MAPPING-STATE"
state=$(cat $file)
coordmatrixid=$(xinput list-props "Wacom Bamboo 2FG 6x8 Pen Pen (0)" | grep Coordinate | awk -F '[(), \t]*' '{print $5}')

if [ "$state" = "" ] && [ "$hdmi" = "HDMI1" ];then
    xinput map-to-output "Wacom Bamboo 2FG 6x8 Pen Pen (0)" "HDMI1"
    echo "HDMI1" > /home/rob/scripts/wacom-bamboo/WACOM-PEN-MAPPING-STATE
    notify-send -a 'Wacom Bamboo' 'Wacom Bamboo mapped to HDMI1' -i /usr/share/icons/breeze/devices/64/input-tablet.svg
elif [ "$state" = "HDMI1" ];then
    xinput map-to-output "Wacom Bamboo 2FG 6x8 Pen Pen (0)" "eDP1"
    echo "eDP1" > /home/rob/scripts/wacom-bamboo/WACOM-PEN-MAPPING-STATE
    notify-send -a 'Wacom Bamboo' 'Wacom Bamboo mapped to eDP1' -i /usr/share/icons/breeze/devices/64/input-tablet.svg
else
    xinput set-float-prop "Wacom Bamboo 2FG 6x8 Pen Pen (0)" $coordmatrixid 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000
    echo "" > /home/rob/scripts/wacom-bamboo/WACOM-PEN-MAPPING-STATE
    notify-send -a 'Wacom Bamboo' 'Wacom Bamboo mapped to all displays' -i /usr/share/icons/breeze/devices/64/input-tablet.svg
fi
#!/bin/bash

state=$(xinput list-props "Wacom Bamboo 2FG 6x8 Finger" | grep "Device Enabled" | awk '{print $4}')

if [ $state == '1' ];then
    xinput disable "Wacom Bamboo 2FG 6x8 Finger"
    notify-send -a 'Wacom Bamboo' 'Wacom Bamboo touch disabled' -i /usr/share/icons/breeze/devices/64/input-tablet.svg
else
    xinput enable "Wacom Bamboo 2FG 6x8 Finger"
    notify-send -a 'Wacom Bamboo' 'Wacom Bamboo touch enabled' -i /usr/share/icons/breeze/devices/64/input-tablet.svg
fi

Previous Post Next Post