Display Preferences


updates.atom
View - Graphics tablet calibration on Linux
Izaya, 2021-04-14 15:28

Graphics tablet configuration on Linux

Following on from my previous article about configuring my mildly cursed WP8060U graphics tablet, I finally got around to setting it up for real use on my desktop.

The situation

The WP8060U is a 4:3 graphics tablet from the early 2000s. My desktop, on the other hand, has two portrait 1440x900 (16:10) displays and a landscape 1680x1050 display. This combination does not mesh well. Without configuration, the horizontal axis of the graphics tablet represents the full 3480px width of my displays, and the vertical axis the 1440px of the portrait displays on either side, stretching the 4:3 input area of the tablet to 29:12.

Input considerations

Essentially, I want the tablet's area to cover a 4:3 area in the centre of the middle monitor, to use with Krita. What we need to do is:

  • Figure out the resolution of the display
  • Divide the smaller axis by the relevant part of the tablet's aspect ratio
  • Multiply the result by the other part of the aspect ratio
  • Figure out the in-display offset for the area we want
  • Calculate the total offset for the whole display server for the area

So, let's take a look at the output of xrandr, ignoring the different mode lines:

DisplayPort-1 connected primary 1680x1050+900+0 (normal left inverted right x axis y axis) 473mm x 296mm   
HDMI-A-1 connected 900x1440+0+0 left (normal left inverted right x axis y axis) 410mm x 256mm   
DVI-D-0 connected 900x1440+2580+0 left (normal left inverted right x axis y axis) 410mm x 260mm

My middle display is hooked up to the DisplayPort output of my graphics card, making it DisplayPort-1. It's resolution is 1680x1050, and it's positioned 900px from the left and 0px from the top.

First, the working area. We take the smaller half of the resolution - 1050, in this case - and divide that by the relevant half of the tablet's aspect ratio - the 3 in 4:3:
1050 ÷ 3 = 350
Now we multiply that by the other half of the aspect ratio - 4 - to get the width of the area:
350 × 4 = 1400
This means our working area is going to be 1400x1050.

Next, the internal offset:
We take the total width of the display and subtract the working area's width from it, then divide it by two, to get the margin on either side:
1680 - 1400 = 280
280 ÷ 2 = 140

If the smaller side was the width rather than the height, like if you wanted to use your graphics tablet on a portrait display, you'd be doing these two in reverse.

Finally, the total offsets. We're going to gloss over the vertical offset because my display has no vertical offset, but essentially, all you need to do is add together the display's offset and the internal offset you just worked out. xrandr said the display's offset was +900+0, so it's 900px from the left and 0px from the top of the display server.
900 + 140 = 1040

To summarise:

  • Input area is 1400x1050
  • Input area offset is +1040+0

Pixels to floats

The xinput property we're going to modify takes floating point numbers - that is, non-integer numbers - between 0 and 1 for mapping, so we need to convert the pixel positions we just worked out into floats to feed into the command. You'll want a calculator for this one.

Working area width (c0): Divide the working area width by the total display server width:
1400 ÷ 3480 = 0.40229885057471

Working area height (c2): Divide the working area height by the total display server height:
1050 ÷ 1440 = 0.72916666666667

Working area horizontal offset (c1): Divide the working area horizontal offset by the total display server width:
1040 ÷ 3480 = 0.29885057471264

Working area vertical offset (c3): Divide the working area offset by the total display server height: 0 ÷ 1440 = 0

Finding the device

Before we can configure the device, we need to find out it's True Name - or at least, it's xinput name. If you run xinput, it will tell you all the input devices attached to your X session. Here's mine:

[izaya@nagato ~]$ xinput  
⎡ Virtual core pointer                        id=2    [master pointer  (3)]  
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]  
⎜   ↳ Logitech MX518 Gaming Mouse               id=13   [slave  pointer  (2)]  
⎜   ↳ Logitech MX518 Gaming Mouse Consumer Control  id=15   [slave  pointer  (2)]  
⎜   ↳ Valve Software Wired Controller           id=19   [slave  pointer  (2)]  
⎜   ↳ UC-LOGIC Tablet WP8060U Mouse             id=22   [slave  pointer  (2)]  
⎜   ↳ UC-LOGIC Tablet WP8060U Pen Pen (0)       id=23   [slave  pointer  (2)]  
⎣ Virtual core keyboard                       id=3    [master keyboard (2)]  
    ↳ Virtual core XTEST keyboard                 id=5    [slave  keyboard (3)]  
    ↳ Power Button                                id=6    [slave  keyboard (3)]  
    ↳ Power Button                                id=7    [slave  keyboard (3)]  
    ↳ Sleep Button                                id=8    [slave  keyboard (3)]  
    ↳ Logitech MX518 Gaming Mouse Keyboard        id=14   [slave  keyboard (3)]  
    ↳ Dell Dell USB Keyboard System Control       id=11   [slave  keyboard (3)]  
    ↳ HD Webcam C615                              id=12   [slave  keyboard (3)]  
    ↳ Dell Dell USB Keyboard                      id=9    [slave  keyboard (3)]  
    ↳ USB 2.0 Camera: HD 720P Webcam              id=17   [slave  keyboard (3)]  
    ↳ Logitech MX518 Gaming Mouse System Control  id=16   [slave  keyboard (3)]  
    ↳ Valve Software Wired Controller             id=18   [slave  keyboard (3)]  
    ↳ Logitech MX518 Gaming Mouse Consumer Control    id=20   [slave  keyboard (3)]  
    ↳ Dell Dell USB Keyboard Consumer Control     id=10   [slave  keyboard (3)]  
    ↳ UC-LOGIC Tablet WP8060U Pen                 id=21   [slave  keyboard (3)]

The relevant input device in this case is the "UC-LOGIC Tablet WP8060U Pen Pen (0)", device ID 23. The device ID changes depending on the order devices are initialised, so the name is the most reliable way to configure the device.

Application

Now we can put together our command. The structure is:
xinput set-prop "Device name" --type float "Coordinate Transformation Matrix" c0 0 c1 0 c2 c3 0 0 1

All you need to do is substitute in the device name and the numbers you worked out earlier; for my setup, the command is:

xinput set-prop "UC-LOGIC Tablet WP8060U Pen Pen (0)" --type=float "Coordinate Transformation Matrix" 0.40229885057471 0 0.29885057471264 0 0.72916666666667 0 0 0 1

I suspect this could be automated with udev but I haven't experimented with that yet. Perhaps for a part 3?

Bonus: Changing mapping of buttons

The pen on my graphics tablet has two buttons, which are mapped to middle and right click, in addition to the main left-clicking pressure sensitive input. The right click is further up the pen and is as such, inconvenient to press. In Krita, however, right click is used to open the brushes and colour selection dialog. As such, I switched them with the command:

xinput --set-button-map "UC-LOGIC Tablet WP8060U Pen Pen (0)" 1 3 2

You can get the current button map with
xinput --get-button-map "Device name"
and re-order it to your preferences.

References


Back to top