0

I'm building a smart mirror (monitor behind a two-way mirror). I have a 27" infrared touch frame, which I want to use with a 22" monitor. One reason for the mismatched sizes is I am placing a camera behind the mirror, and the touch frame must be the size of the mirror since the mirror sits between the monitor and the touch frame.

I'm using the xinput_calibrator tool to calibrate the touch frame, but X assumes the touch frame and the monitor are the same size so the calibration is only correct towards the middle of the screen (where the middle of the touch frame and middle of the monitor overlap). Beyond that the touch inputs skew towards the middle of the screen.

In the image below, everything within the black rectangle is within the infrared touch area. The monitor is the green rectangle.

Mockup of the touch frame and monitor

How can I configure X to use a touch surface that is larger than the physical display?

I'm using Raspbian 10 (buster) on a Raspberry Pi 4.

1 Answer 1

1

xinput can be used to set the coordinate transformation matrix for the touch input device. This is based on steps found on the Arch Linux wiki: https://wiki.archlinux.org/index.php/Calibrating_Touchscreen

First, get a list of input devices recognized by X11:

$ xinput list

One of the results should be the touch frame. Next, get its current settings:

$ xinput list-props "Device Name"

There will be a property named "Coordinate Transformation Matrix" which is what we need to update.

There are two things that need to be accounted for:

  1. Since the touch frame is physically larger than the display, it's pixel dimensions will be larger.
  2. The touch area is offset horizontally and vertically relative to the display.

Gather the following variables. I physically measured these with a tape measure, but as long as everything is in the same base (such as pixel resolution) the math will work out in the end.

Screen width        52cm
Screen height       32.5cm

Touch area width        60.5cm
Touch area height       34cm
Touch area x offset     -4cm (note the negative because the touch area begins beyond the left edge of the display)
Touch area y offset     0 (in my case the top of the touch frame aligned with the top of the display)

Now build the coordinate transformation matrix. There are 4 values in the matrix that must be calculated.

The matrix is

[ c0 0  c1 ]
[ 0  c2 c3 ]
[ 0  0  1  ]

which is represented as a row-by-row array:

c0 0 c1 0 c2 c3 0 0 1

c0 = touch_area_width / total_width
c1 = touch_area_x_offset / total_width
c2 = touch_area_height / total_height
c3 = touch_area_y_offset / total_height

For my measurements this works out to

c0  1.163461538
c1  -0.076923077
c2  1.046153846
c3  0

Now set the new values with xinput:

xinput set-prop "Device Name" --type=float "Coordinate Transformation Matrix" c0 0 c1 0 c2 c3 0 0 1

Plugging in the calculated values:

xinput set-prop "Device Name" --type=float "Coordinate Transformation Matrix" 1.16346 0 -0.0769 0 1.046150 0 0 1

This only sets it for the current session. To make the change whenever the device is plugged in (or on boot) create a udev rule. You'll need to find the vendor ID and device model ID. For my device these are "aaec" and "c021"

/etc/udev/rules.d/99-touch-frame.rules

ENV{ID_VENDOR_ID}=="aaec",ENV{ID_MODEL_ID}=="c021",ENV{WL_OUTPUT}="DVI1",ENV{LIBINPUT_CALIBRATION_MATRIX}="1.16346 0 -0.0769 0 1.046150 0 0 1"

Now whenever the device is plugged in, the calibration matrix will be set automatically.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .