InputCoordinateTransformation

Introduction

Recent X.org servers have incorporated a property for setting how input device events are translated to screen coordinates. This property can be used to ensure a touchscreen is not stretched across a multi-monitor setup or to rotate the touch screen input when you rotate the physical device.

Printing the Coordinate Transformation Matrix

First, we need to determine the name of the input device. Run the following:

$ xinput list

You will see output like:

⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=11   [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)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Power Button                              id=8    [slave  keyboard (3)]
    ↳ HID 413c:8161                             id=9    [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=10   [slave  keyboard (3)]

We'll operate on the "SynPS/2 Synaptics TouchPad". To print the Coordinate Transformation Matrix (CTM), run the following:

$ xinput list-props 'SynPS/2 Synaptics TouchPad' | grep "Coordinate Transformation Matrix"

By default, this will output:

Coordinate Transformation Matrix (137): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000

This is a 3x3 coordinate transformation matrix. It's encoded in row-major order, so the matrix would look like the following in a text book:

⎡ 1 0 0 ⎤
⎜ 0 1 0 ⎥
⎣ 0 0 1 ⎦

Astute readers will recognize that this is the identity matrix.

Using the Coordinate Transformation Matrix

By default, the CTM for every input device in X is the identity matrix. As an example, lets say you touch a touchscreen at point (400, 197) on the screen:

⎡ 1 0 0 ⎤   ⎡ 400 ⎤   ⎡ 400 ⎤
⎜ 0 1 0 ⎥ · ⎜ 197 ⎥ = ⎜ 197 ⎥
⎣ 0 0 1 ⎦   ⎣  1  ⎦   ⎣  1  ⎦

The X and Y coordinates of the device event are input in the second matrix of the calculation. The result of the calculation is where the X and Y coordinates of the event are mapped to the screen. As shown, the identity matrix maps the device coordinates to the screen coordinates without any changes.

The transformation matrix used is called an affine transformation matrix. Note that the translation values are in normalized floating point coordinates.

Left rotate (clockwise 90°)

Lets say we physically rotate the screen by 90° (from left) to the right. The X server screen can be rotated so that the display output matches the new orientation:

$ xrandr -o left

Warning /!\ Not all graphics drivers support rotation

Now we want to map our touchscreen to the new orientation (90° (from left) to the right) as well. Using the affine transformation rules we would want our transformation matrix to be:

⎡ 0 -1 1 ⎤
⎜ 1  0 0 ⎥
⎣ 0  0 1 ⎦

Right rotate (counterclockwise 90°)

For 90° (from right) to the left.

$ xrandr -o right

Warning /!\ Not all graphics drivers support rotation

with a transformation matrix of:

⎡  0 1 0 ⎤
⎜ -1 0 1 ⎥
⎣  0 0 1 ⎦

Invert rotate (clockwise or counterclockwise 180°)

$ xrandr -o inverted

Warning /!\ Not all graphics drivers support rotation

with a transformation matrix of:

⎡ -1  0 1 ⎤
⎜  0 -1 1 ⎥
⎣  0  0 1 ⎦

Limit Range

Instead, lets say we have two monitors side by side, and our touchscreen is on the right monitor. They have the same resolution in the X direction. We don't want our touchscreen mapped across both monitors, so we need to map the device coordinates to only the right half of the screen. Again, using the affine transformation rules we would want our transformation matrix to be:

⎡ 0.5 0 1 ⎤
⎜  0  1 0 ⎥
⎣  0  0 1 ⎦

Setting the Coordinate Transformation Matrix

Once we have determined the CTM, we need to set the matrix for the input device. We'll assume the device name has been retrieved using 'xinput list' as described above. To set the matrix, run:

$ xinput set-prop '<device name>' 'Coordinate Transformation Matrix' <matrix in row-order>

For example, to set the CTM to:

⎡ 0.5 0 1 ⎤
⎜  0  1 0 ⎥
⎣  0  0 1 ⎦

run:

xinput set-prop '<device name>' 'Coordinate Transformation Matrix' 0.5 0 1 0 1 0 0 0 1

X/InputCoordinateTransformation (last edited 2014-09-04 02:33:09 by yangrongwei)