Sunday, September 13, 2009

Better touch

My professional life changed quite a bit recently and that's why I have not been posting as frequently as usual. I finally seem to have reached some balance and now's the time to resume my blog work.

One of the faults I found in the last version of the published code concerned finger sensitivity. This is a real issue in touch screens based on resistive technology (see a discussion about this topic on Marcus Perryman's blog). The bottom line is simple: resistive screens were made for a stylus, not for your finger. They are much more precise than capacitive screens (like the one found on the iPod Touch and iPhone), but require pressure. Capacitive screens are less precise but require only a very soft finger contact in order to operate. Resistive screens expect a very small pressure area (the tip of a stylus). An adult index finger uses up a very large area on the touch screen and the net result is noise and erratic motion messages.

You can see this in the last sample code I published: flick the list and then click it. It should stop the list but it doesn't (that's how it works on my HTC Touch Pro). What happens is that a single finger press is interpreted by the highly sensitive resistive screen as a sequence of one WM_LBUTTONDOWN message, a couple of WM_MOUSEMOVE messages and the final WM_LBUTTONUP. Inspecting the LPARAM parameter you will see that the POINT structure shows some fluctuations on the x and y coordinates. This means that a single finger press is actually equivalent to a small doodle drawn with your stylus. You will be lucky if the first and last POINT values are the same (they almost never are).

To mitigate this issue and provide better (more reliable) finger action feedback I made some adjustments to the code. The first thing I realized is that one of the sources of "position noise" was the first WM_MOUSEMOVE message. The offset between the WM_LBUTTONDOWN position and the first WM_MOUSEMOVE message seems to provide more variance than the offset to the second WM_MOUSEMOVE. To even things out a little bit I now discard the first offset and start calculating the gesture from the first WM_MOUSEMOVE message. Also, I brought back the concept of sensitivity to filter out smaller movements. Finally take a look at the code in CTouchGesture::Move method. Instead of calculating the move offset in a single if clause, I split the code into two, one for the vertical motion and the other for the horizontal motion.

The final result feels a bit better and more reliable on all the machines I have tested the code with, but the final word is yours.

Sample code: (164 KB)

No comments: