Wednesday, February 10, 2010

Computer assisted Chinese (part VI): Touchscreen 4

Last article, I had a working touchscreen where the whole of the touchscreen surface was mapped to the whole of the display.

Skritter is a flash-based web app.  In scritter, there's an area in the middle of the window in which you can use your input device to enter the strokes for the character:

So I have the requirement that I want to map the touchscreen area just into that rectangular area.

Here's another requirement: A 15cm x 9cm touchscreen is designed to fit over a display, not sit on one's desk.

It's too large to comfortably write on, as my wrist hits the surface when writing and throws off the cursor. So I only want to use a small area of it.

And since I eventually want to build this with a cheap nintendo touchscreen, not a full-sized one, I'd like to just use one corner of the large touchscreen.

Further, I want size and aspect ratio of my small corner of the large touchscreen to be roughly the same as for the nintendo touchscreen. Fair enough.

But it gets better: When I finally use the nintendo touchscreen, I want the aspect area of that touchscreen to be the same as Skritter's on-screen drawing area. Since the aspect ratio of the Skritter writing area is slightly different to the nintendo touchscreen area, I will only use about 85% of the nintendo touchscreen area.

So, somehow I have to map a small corner of the large touchscreen, onto this particular on-screen rectangle.

The 11-eGalax.fdi file mentioned in the last article has a line of calibration data:
<merge key="input.x11_options.Calibration" type="string">32 3990 48 3990</merge>
Those four values are the data values one should expect to get from the touchscreen when touching the minimum x, maximum x, minimum y and maximum y positions on the touchscreen. The reason we can provide the numbers is to allow for variations in the properties of each touchscreen, although in general, the values will be around the minimum and maximum values the touchscreen can produce. But what if I fake these values?  Can I use this to trick X into mapping one area onto another?  Let's try...

One thing to note is that from my testing: I've found that the X axis and the Y axis are reasonably independent of each other: Running the stylus along a horizontal or vertical ruler on the touchscreen shows one axis changing a lot but not the other.  Therefore I think the number crunching for the X and Y axes can be done independently.

Mapping an input range of numbers onto an output range of numbers isn't hard. We can visualise the map as a graph, where the X axis shows the input range, and the Y axis shows the output range. The limits of the input and output range correspond to two points on the graph. We can then find the linear equation which describes the line, and once we know that, find the output value for any input value. This should map the touchscreen area to the on-screen area, but also, if we reverse the mapping and feed in the dimensions of the screen, we should be able to find the four calibration values we need to give us the desired mapping.

The first thing I did was work out how much of the touchscreen I want to use. I first considered the case of the nintendo touchscreen.

The pixels on my LCD display are square, so the aspect ratio is 1:1. When the web page is fully maximised, the size of the Skritter writing area on my screen is 347 pixels by 402 pixels. That's an aspect ratio of 0.86. I want to keep the same ratio on my touchscreen.

If I place the nintendo touchscreen with the long axis vertically, the active area is 47.5mm across by 63.5mm high, which is an aspect ratio of 0.75.  Note the two aspect ratios aren't the same.  If I want to keep the aspect ratio the same, I'll have to give up using a small area of the touchscreen.

If I map the width of the touchscreen to the width of the Skritter writing area, the height of the part of the nintendo touchscreen I'll be using is 47.5mm / 0.86 = 55mm. (I can use the remainder for not-on-screen special functions).

Note this picture is not to the same scale as the previous picture.

I then got an index card and cut out a rectangle 47 x 55mm.  I can then place this on top of the larger touchscreen to show me the useable area of the smaller touchscreen:

For comparison, here's the nintendo touchscreen on top of the larger touchscreen:

(The colour difference is because I took the two pictures at different times of the day)

Then I ran the evtest program again,and recorded the touchscreen values for the top left and bottom right corners of the uncovered area on the card.  (The values are backwards because I'm using the touchscreen rotated by 180°).

Tscreen Point X data value Y data value
top left 1940 1850
bottom right 950 203

Skritter Point X data value Y data value
top left 504 285
bottom right 851 687

Screen Point X pixel Y pixel
top left 0 0
bottom right 1680 1050

Now, time for some number crunching.  Treating the X and Y axes separately, we can find the m and c in y=mx+c to map the touchscreen coordinates to screen coordinates.  Then, using x = (y-c)/m, we can feed in the boundaries of the screen, and found out the effective values if the touchscreen was big enough to cover the whole screen, and mapped our touchscreen area onto the Skritter writing area.

I cooked up a spreadsheet to do the number crunching.  I typed in all the coords, and it spits out the four "calibration values" I needed.  You can find the spreadsheet here:

If I use the data from the tables above, I get the following four values:

Min X 3378
Max X -1415
Min Y 3018
Max Y -1284

Note that two of the four numbers are negative.  That's to be expected.  It just means that with the mapping we have, the lower right corner of the touchscreen is inside the display area.  That's ok for us, because we'll never be sending negative values anyway.  (I'm feeling pretty lucky that whoever wrote the HAL and X stuff didn't disallow negative calibration values....)

So, then I plugged these values into the 11-evdev.fdi file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- 10-synaptics.fdi is claiming all input.touchpad's as its
     own. This file is meant to be loaded afterwards and to undo
     any wrong assignments it did.
<deviceinfo version="0.2">
    <match key="info.capabilities" contains="input.touchpad">
      <match key="info.product" contains="eGalax">
        <merge key="input.x11_driver" type="string">evdev</merge>
        <merge key="input.x11_options.Calibration" type="string">3378 -1415 3018 -1284</merge>

Enough talking, what happened after I restarted HAL and X?  Well, it worked first time!  A light touch to the corners of the restricted touchscreen area goes straight to the corners of my on-screen input area.  I love it when something works first time!  To celebrate, I went and practised Chinese characters for three hours.  So much nicer with a pen rather than a mouse!

What's next?  Well, now that I have the larger touchscreen working, I want to get the cheapy nintendo touchscreen working.  Oh, and practice Chinese more :-)

No comments:

Post a Comment