Custom Touch Panel drivers

Writing a custom touch panel handler for Qt/Embedded is not as hard as the QVrTPanelHandlerPrivate class makes it look. The Vr41XX touch panel handler is complex; it handles filtering of noisy input data, and it generates mouse release events by using a timer.

Many touch panel devices have a much simpler interface, so a port to Qt/Embedded can be written in a few minutes, without expert knowledge of Qt/Embedded.

The Qt/Embedded release contains an example touch panel handler in the class QCustomTPanelHandlerPrivate, located in the file $QTDIR/src/kernel/qwsmouse_qws.cpp. It is protected by#ifdef QWS_CUSTOMTOUCHPANEL.

The example reads data from /dev/ts with the following format: Each packet consists of 5 bytes.

To enable this driver, uncomment the line #define QWS_CUSTOMTOUCHPANEL in the file qwsmouse_qws.cpp.

Chances are, your touch panel device will not match exactly the example device. As an example, take a hypothetical device located at /dev/touchpanel. This device uses 6-byte packets. Byte 0 and 1 give status and pressure information. In particular, bit 5 (0x20) of byte 1 tells whether the stylus is down or up. Bytes 2 and 3 give x position and bytes 4 and 5 give y position. Pressure information is not necessary for basic Qt/Embedded operation, so we will ignore that for now. The following shows the modified touch panel handler for the hypothetical device, with comments marked with //*** indicating the changes made. You can also see some printf calls left over from the (hypothetical) debugging.

//*** Modified Trolltech's example handler to handle the
//*** hypothetical touch panel.
QCustomTPanelHandlerPrivate::QCustomTPanelHandlerPrivate( MouseProtocol, QString )
{
#ifdef QWS_CUSTOMTOUCHPANEL
    //*** changed device name to /dev/touchpanel

    if ((mouseFD = open( "/dev/touchpanel", O_RDONLY)) < 0) {
        qWarning( "Cannot open /dev/touchpanel (%s)", strerror(errno));
	return;
    } 
    //*** removed the delay since our device does not need it.
    //else {
    //    sleep(1);
    //}

    QSocketNotifier *mouseNotifier;
    mouseNotifier = new QSocketNotifier( mouseFD, QSocketNotifier::Read,
					 this );
    connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
#endif
}

QCustomTPanelHandlerPrivate::~QCustomTPanelHandlerPrivate()
{
    if (mouseFD >= 0)
	close(mouseFD);
}

struct CustomTPdata {

  unsigned char status;
  unsigned short xpos;
  unsigned short ypos;

};

void QCustomTPanelHandlerPrivate::readMouseData()
{
#ifdef QWS_CUSTOMTOUCHPANEL
    if(!qt_screen)
	return;
    CustomTPdata data;

    //*** changed size to 6 bytes
    unsigned char data2[6];

    int ret;

    //*** read 6 bytes
    ret=read(mouseFD,data2,6);

    if(ret==6) { //*** change to 6
        //*** all the indexes changed:
	data.status=data2[1]; 
	data.xpos=(data2[2] << 8) | data2[3];
	data.ypos=(data2[4] << 8) | data2[5];
	QPoint q;
	q.setX(data.xpos);
	q.setY(data.ypos);
	mousePos=q;
	if(data.status & 0x20) { //*** Changed to 0x20 (bit 5)
          emit mouseChanged(mousePos,Qt::LeftButton);
          //printf( "Stylus press/move %d,%d\n", data.xpos, data.ypos );
	} else {
	  emit mouseChanged(mousePos,0);
          //printf( "Stylus release %d,%d\n", data.xpos, data.ypos );
	}
    }
    if(ret<0) { 
	qDebug("Error %s",strerror(errno));
    }
#endif
}

Once you have your touch panel handler working, you may choose to keep
it like it is. However, if you want to switch between different
mouse/touch panel devices at run time, you will have to modify
QWSServer::newMouseHandler() (also in qwsmouse_qws.cpp) to instantiate
your new handler(s). You will also need to add to the enum
MouseProtocol and the table mouseConfig[]. Note that
the precise details on how mouse and touch panel drivers are instantiated
may have to be changed in future versions of Qt/Embedded.