Sunday, May 15, 2016

Setting up Ugee 1910b Tablet Display in Linux (Ubuntu 16.04 LTS)

I recently decided to migrate from OS X to Ubuntu, and one of the most difficult (or rather easy once you figure out) things to setup is the Ugee Tablet Monitor on Ubuntu. Fortunately, the drivers for the Ugee monitor and touch screen input are already configured and makes the display and touch input drivers load automatically when the monitor is plugged in and turned on. The tricky part is getting the calibration settings correct.

Anyway, below are the steps you need to take to calibrate the Ugee.

1. Figure out what displays are available and which one corresponds to the Ugee display.

$ xrandr

Screen 0: minimum 8 x 8, current 4000 x 1715, maximum 16384 x 16384
DP-0 disconnected (normal left inverted right x axis y axis)
DP-1 connected primary 1440x900+2560+815 (normal left inverted right x axis y axis) 575mm x 323mm
   1440x900      59.89*+
   1360x768      60.02  
   1280x960      60.00  
   1280x800      59.81  
   1280x720      60.00  
   1024x768      75.03    70.07    60.00  
   800x600       75.00    72.19    60.32    56.25  
   640x480       75.00    72.81    59.94  
DP-2 connected 2560x1440+0+0 (normal left inverted right x axis y axis) 597mm x 336mm
   2560x1440     59.95*+
   1280x720      59.86  
DP-3 disconnected (normal left inverted right x axis y axis)
DP-4 disconnected (normal left inverted right x axis y axis)


The Ugee is highlighted in yellow. Its resolution matches 1440x900 (which can be seen inside Settings->Displays). It's display name is DP-1 .

My primary display (iMac 27" display) is highlighted in green . It's display name is DP-2 .

2. Figure out the input id for the touch display input.  You can do this as follows:

$ xinput_calibrator --list
Device "UC-Logic 19" Tablet Monito" id=13

Where I've highlighted the important part in yellow. The id for my display is 13.

3. Just in case, jot-down the previous calibration and transformation matrix values. Replace the value 13 with your id value from step 2. You may/may not need to do this. I never did, but then had a lengthy process of trying to recover those values when I got my display into a badly calibrated state. This step also let's me explain what the calibration parameters are and what they affect.

$ xinput list-props 13
Device 'UC-Logic 19" Tablet Monito':
Device Enabled (151): 1
Coordinate Transformation Matrix (153): 0.360000, 0.000000, 0.640000, 0.000000, 0.524781, 0.475219, 0.000000, 0.000000, 1.000000
Device Accel Profile (274): 0
Device Accel Constant Deceleration (275): 1.000000
Device Accel Adaptive Deceleration (276): 1.000000
Device Accel Velocity Scaling (277): 10.000000
Device Product ID (268): 21827, 71
Device Node (269): "/dev/input/event6"
Evdev Axis Inversion (278): 0, 0
Evdev Axis Calibration (279): -67, 32212, 146, 20332
Evdev Axes Swap (280): 0
Axis Labels (281): "Abs X" (297), "Abs Y" (298), "Abs Pressure" (299)
Button Labels (282): "Button Left" (154), "Button Middle" (155), "Button Right" (156), "Button Wheel Up" (157), "Button Wheel Down" (158)
Evdev Scrolling Distance (283): 0, 0, 0
Evdev Middle Button Emulation (284): 0
Evdev Middle Button Timeout (285): 50
Evdev Third Button Emulation (286): 0
Evdev Third Button Emulation Timeout (287): 1000
Evdev Third Button Emulation Button (288): 3
Evdev Third Button Emulation Threshold (289): 20
Evdev Wheel Emulation (290): 0
Evdev Wheel Emulation Axes (291): 0, 0, 4, 5
Evdev Wheel Emulation Inertia (292): 10
Evdev Wheel Emulation Timeout (293): 200
Evdev Wheel Emulation Button (294): 4
Evdev Drag Lock Buttons (295): 0

I've highlighted the important lines to jot-down in green above. A quick explanation of each setting:

Coordinate Transformation Matrix - This is a 3x3 matrix that creates an affine transformation that warps a rectangular coordinate system to the coordinate system of the display. The transform needs to be changed to match the desktop layout/geometry if this gets updated (e.g., by dragging the display layout around in Settings->Display, changing the aspect ratio, or updating the rotation of the desktop).

Evdev Axis Calibration: This is the calibration value. The settings are written in the order:
   xmin xmax ymin ymax
They control the bounds of the cursor in the x- and y- directions relative to some local coordinate system of the Ugee display. For mine, I roughly figured out that the coordinate system was something like 0 to 32210 for x and 0 to 20330 for y through trial and error. Tweaking the bounds around these values stretches the coordinate system along x and y to fit plane. If the display plane gets shifted from the touch display plane, the shift would be reflected by the lower or higher values.

Evdev Axes Swap: I haven't messed with this, but I'm speculating that a non-zero value flips the x- and y- coordinates so that the x-axis becomes the y-axis and vice versa. 

4.  Turn off all displays except Ugee. From step 1, my Ugee display is DP-1 and my iMac display is DP-2. I need to turn off my iMac display (DP-2) first:

   $ xrandr --output DP-2 --off

5.  Sync the coordinate system with the display. This step automagically populates the "Coordinate Transformation Matrix" values with the right values. Recall from step 1 that my Ugee display name is DP-1. From step 2, the Ugee input ID is 13.
   $ xinput map-to-output 13 DP-1

You will want to replace the 13 and DP-1 with your values. If you're curious about how this updates the coordinate transformation matrix, feel free to check it out by running the command in step 3, xinput list-props 13

6.  Run the calibrator.

   $ xinput_calibrator \
    --device 13 \
    --verbose \
    --output-type xorg.conf.d 

This will bring up a gray display with some targets to click on.  If you run into issues like I did where tapping a target gets rejected or ignored because the tap is way out of bounds and gets clipped by the screen resolution, it means your display has gotten into a poorly calibrated state. The work around is to input a precalibrated value that is close to the Ugee's calibrated state. I had to figure out what these values were by trial and error. Anyway, you can also just use my calibrated values as well.  

# Do this if the last run kept rejecting your taps:
  $ xinput_calibrator \
    --device 13 \
    --verbose \
    --output-type xorg.conf.d \
    --precalib -54 32210 137 20332

Make sure to look at the output. I've highlighted the important part.

DEBUG: XInputExtension version is 2.3
DEBUG: Skipping virtual master devices and devices without axis valuators.
DEBUG: Selected device: UC-Logic 19" Tablet Monito
DEBUG: Setting precalibration: -54, 32210, 137, 20332
DEBUG: Not usbtouchscreen calibrator: Not a usbtouchscreen device
DEBUG: Read axes swap value of 0.
DEBUG: Read InvertX=0, InvertY=0.
Calibrating EVDEV driver for "UC-Logic 19" Tablet Monito" id=13
current calibration values (from XInput): min_x=-67, max_x=32212 and min_y=146, max_y=20332
DEBUG: Found that 'UC-Logic 19" Tablet Monito' is a sysfs name.
DEBUG: Adding click 0 (X=178, Y=113)
DEBUG: Adding click 1 (X=1253, Y=115)
DEBUG: Adding click 2 (X=180, Y=787)
DEBUG: Adding click 3 (X=1257, Y=790)

Doing dynamic recalibration:
Setting calibration data: -74, 32085, 182, 20353
DEBUG: Successfully applied axis calibration.
--> Making the calibration permanent <--
DEBUG: Found that 'UC-Logic 19" Tablet Monito' is a sysfs name.
  copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf' (/usr/share/X11/xorg.conf.d/ in some distro's)
Section "InputClass"
Identifier "calibration"
MatchProduct "UC-Logic 19" Tablet Monito"
Option "Calibration" "-74 32085 182 20353"
Option "SwapAxes" "0"
EndSection

Copy and paste the above highlighted yellow into some scratch file or text editor. If you want to restore the calibration after each reboot, we will need to create a calibration file later on. But first to finish the calibration.

7. Turn on all of the displays you turned off in step 4. I turned off DP-2, so to turn it back on:
   $ xrandr --output DP-2 --auto

8. Reset the layout of your desktop. I had to rearrange the monitor layouts in Settings->Display so that the layouts are side-by-side instead of overlapping each other.

9. Update and sync the updated coordinate system by repeating step 5: 

   $ xinput map-to-output 13 DP-1

10. By now, everything should be calibrated. Try out the stylus on the touch display. It should all work out. You may need to run the calibrator a second time if there's still an offset.

11. The remaining steps are to setup Ubuntu such that the calibration is restored on reboot. First, we need to create the file /usr/share/X11/xorg.conf.d/99-calibration.conf  (or if the parent folder doesn't exist, then try creating /etc/X11/xorg.conf.d/99-calibration.conf ). The highlighted output from step 6 goes into the 99-calibration.conf file with some tweaks:

Section "InputClass"
Identifier "calibration"
MatchProduct "UC-Logic 19"
Option "Calibration" "-74 32085 182 20353"
Option "SwapAxes" "0"
EndSection

Notice that I've updated the value in green. This step is necessary since " would cause the string to terminate and create errors in the xorg configuration file.  Since MatchProduct matches substrings, the new value works (unless you happen to have another input device that contains the string "UC-Logic 19").

12. One more final issue. After rebooting into X11, the coordinate transformation for the input gets reset to the identity matrix. This means you'll need to update the coordinate transformation with the correct value after every reboot. E.g., I could manually run : xinput map-to-output 13 DP-1
after every reboot, but I'm lazy. So, I wrote a script in ~/bin/sync_coordinate_transform.sh with the contents:

#!/bin/sh
xinput map-to-output  13   DP-1


(Actually, I made mine more generic since I worry the id values and DP values can change. I used the following script instead:

#!/bin/sh
get_tablet_input_id() {
    xinput_calibrator --list | grep "UC-Logic 19" | cut -f2 -d"="
}

get_tablet_display_id() {
    xrandr | grep "DP" | grep "1440x900" | cut -f1 -d" "
}

INPUT_ID="$(get_tablet_input_id)"
DISPLAY_ID="$(get_tablet_display_id)"

xinput map-to-output  "${INPUT_ID}" "${DISPLAY_ID}"


And then added this script to Startup Applications:
  $ gnome-session-properties

Name: Calibrate touchscreen
Command: ~/bin/sync_coordinate_transform.sh

=====================================================

That's it. Also, if you're lazy and want to try out my automated script of grabbing the display and input ids automatically and running xinput_calibrator, I did try and write one. It may/may not parse properly, but you can always tweak it. You'll still need to do the restore calibration part manually. You can name this file calibrate_touch.sh:

#!/bin/bash
get_connected_display_ids() {
    xrandr | grep " connected" | cut -f1 -d" " | tr "\n" " "
}

get_tablet_display_id() {
    xrandr | grep "DP" | grep "1440x900" | cut -f1 -d" "
}

get_tablet_input_id() {
    xinput_calibrator --list | grep "UC-Logic 19" | cut -f2 -d"="
}

turnoff() {
    id="${1}"
    xrandr --output "${id}" --off
}

turnon() {
    id="${1}"
    xrandr --output "${id}" --auto
}

CONNECTED_IDS="$(get_connected_display_ids)"
DISPLAY_ID="$(get_tablet_display_id)"
INPUT_ID="$(get_tablet_input_id)"

# Power off other displays
for id in ${CONNECTED_IDS}; do
    if [ "${id}" != "${DISPLAY_ID}" ]; then
        turnoff "${id}"
    fi
done

xinput map-to-output "${INPUT_ID}" "${DISPLAY_ID}"
xinput_calibrator \
    --device ${INPUT_ID} \
    --verbose \
    --output-type xorg.conf.d \
    --precalib -54 32210 137 20332

# Power on other displays
for id in ${CONNECTED_IDS}; do
    if [ "${id}" != "${DISPLAY_ID}" ]; then
        turnon "${id}"
    fi
done

xinput map-to-output "${INPUT_ID}" "${DISPLAY_ID}"


[Updated 2016-06-04]
Getting Right Click to work

If you're like me and you need to remap the stylus buttons, do the following:

Create the following file  /usr/share/X11/xorg.conf.d/52-tablet.conf  with the following contents:

Section "InputClass"
        Identifier "Graphics tablet mouse"
        MatchIsPointer "on"
        MatchProduct "UC-Logic 19"
        MatchDevicePath "/dev/input/event*"
        Driver "evdev"
        # Apply custom Options below.

EndSection

Section "InputClass"
        Identifier "Graphics tablet pen"
        MatchIsTablet "on"
        MatchProduct "UC-Logic 19"
        MatchDevicePath "/dev/input/event*"
        Driver "evdev"
        # Apply custom Options below.
        Option "ButtonMapping" "1 3 2"
EndSection


You'll need to experiment with the ordering of the ButtonMapping numbers to get the desired mapping.