Qt 下触摸屏的驱动
Qt/Embedded 中与用户输入事件相关的信号,是 建立在对底层输入设备的接口调用之上的,一般通过 对设备文件的 I/O 读写来实现。大部分这样的驱动程序已经被封装进 Qt 库当中,形成了相应的设备驱动接口,如显示卡驱动、鼠标、键盘、串口和并口等。 其中鼠标设备的抽象基类为 QWSMouse Handler,从 该类又重新派生出一些具体的鼠标类设备的实现类。在 3.3.4 版本系列的 Qt/Embedded 中,鼠标类设备的派生结构如图 3 所示。
图 3 鼠标类设备的派生结构图(灰色线框表示可省略类结构)
鼠标类设备的加载方式与 KeyBoard 设备加载方 式是类似的,在系统构造 QWSServer 对象时,调用成 员函数 QWSServer:: openMouse,程序在QWSServer:: openMouse 函数中再调用QmouseDriverFactory::create () 或QmouseDriverPlugin:: create ()。该函数根据 Linux 系统的环境变量QWS_MOUSE_PROTO获得鼠标类设备的设备类型和设备节点。打开并返回相应设备的基类指针 QWSMouseHandler 给系统,系统通过操作该基类派生出的具体子类设备指针QWSCustomMouseHandler,获得对具体鼠标类设备的调用操作(见图 4)。
图 4 软件流程图
触摸屏和鼠标类设备在功能上基本是一致的,因 此,在 Qt 库中一般把触摸屏模拟成鼠标设备来实现 对触摸屏设备的操作。
基于Qt的触摸屏校准程序
/****************************************************************************
****************************************************************************/
#ifndef CALIBRATION_H
#define CALIBRATION_H
#include <QDialog>
#include <QWSPointerCalibrationData>
//! [0]
class Calibration : public QDialog
{
// Q_OBJECT
public:
Calibration();
~Calibration();
int exec();
void init();
void calibration_quit();
protected:
void paintEvent(QPaintEvent*);
void mouseReleaseEvent(QMouseEvent*);
void accept();
private:
QWSPointerCalibrationData data;
int pressCount;
QWSPointerCalibrationData data_read;
};
//! [0]
#endif
/****************************************************************************
****************************************************************************/
#include "calibration.h"
#include <QWSPointerCalibrationData>
#include <QPainter>
#include <QFile>
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QScreen>
#include <QWSServer>
#include <QDebug>
#include <QMessageBox>
#include <QWSCalibratedMouseHandler>
#include <QtGui>
#include "Qtglobal.h"
//! [0]
static QWSPointerCalibrationData initial_data;
static bool flag=false;
Calibration::Calibration()
{
}
//! [2]
void Calibration::init() //触摸屏的坐标信息等初始化, 使鼠标焦点校准窗口上,
{
this->setCursor(QCursor(Qt::BlankCursor));
QRect desktop = QApplication::desktop()->geometry();
desktop.moveTo(QPoint(0, 0));
setGeometry(desktop);
setFocusPolicy(Qt::StrongFocus);
setFocus();
setModal(true);
//! [0]
//! [1]
int width = qt_screen->deviceWidth();
int height = qt_screen->deviceHeight();
int dx = width / 10;
int dy = height / 10;
QPoint *points = data.screenPoints;
points[QWSPointerCalibrationData::TopLeft] = QPoint(dx, dy);
points[QWSPointerCalibrationData::BottomLeft] = QPoint(dx, height - dy);
points[QWSPointerCalibrationData::BottomRight] = QPoint(width - dx, height - dy);
points[QWSPointerCalibrationData::TopRight] = QPoint(width - dx, dy);
points[QWSPointerCalibrationData::Center] = QPoint(width / 2, height / 2);
//! [1]
//! [2]
pressCount = 0; //屏幕校准点计数
}
//! [3]
Calibration::~Calibration()
{
}
//! [3]
//! [4]
int Calibration::exec() //本校准类是从Qdialog继承过来,当这个类实例化这个对象后首先执行exec这个函数
{
qDebug("exec:1");
QWSServer::mouseHandler()->clearCalibration(); //清楚校准系数
grabMouse(); //或者鼠标,防止焦点到屏幕外缘
activateWindow(); //设置本窗口时活动窗口
int ret = QDialog::exec();
releaseMouse();
qDebug("over");
// QMessageBox message;
// message.setText("<p>Please press once at each of the marks "
// "shown in the next screen.</p>"
// "<p>This messagebox will timout after 10 seconds "
// "if you are unable to close it.</p>");
// QTimer::singleShot(10 * 1000, &message, SLOT(accept()));
// message.exec();
return ret;
}
//! [4]
//! [5]
void Calibration::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
QPoint point = data.screenPoints[pressCount];
// Map to logical coordinates in case the screen is transformed
QSize screenSize(qt_screen->deviceWidth(), qt_screen->deviceHeight());
point = qt_screen->mapFromDevice(point, screenSize);
p.fillRect(point.x() - 6, point.y() - 1, 13, 3, Qt::black);
p.fillRect(point.x() - 1, point.y() - 6, 3, 13, Qt::black);
}
//! [5]
//! [6]
void Calibration::mouseReleaseEvent(QMouseEvent *event)
{
// Map from device coordinates in case the screen is transformed
QSize screenSize(qt_screen->width(), qt_screen->height());
QPoint p = qt_screen->mapToDevice(event->pos(), screenSize);
data.devPoints[pressCount] = p;
if (++pressCount < 5)
repaint();
else
accept();
}
//! [6]
//! [7]
void Calibration::accept()
{
Q_ASSERT(pressCount == 5);
flag = true;
initial_data=data;
QWSServer::mouseHandler()->calibrate(&data);
//save the calibrated data to setup file
QSettings *writeini = new QSettings(INIT_PATH, QSettings::IniFormat, 0);
writeini->beginGroup("calibrat_data");
writeini->setValue("screen_Topleft",data.screenPoints[0]);
writeini->setValue("screen_BottomLeft",data.screenPoints[1]);
writeini->setValue("screen_BottomRight",data.screenPoints[2]);
writeini->setValue("screen_TopRight",data.screenPoints[3]);
writeini->setValue("screen_Center",data.screenPoints[4]);
writeini->setValue("dev_Topleft",data.devPoints[0]);
writeini->setValue("dev_BottomLeft",data.devPoints[1]);
writeini->setValue("dev_BottomRight",data.devPoints[2]);
writeini->setValue("dev_TopRight",data.devPoints[3]);
writeini->setValue("dev_Center",data.devPoints[4]);
writeini->endGroup();
delete writeini;
QDialog::accept();
// QDialog::done(1);
}
void Calibration::calibration_quit()
{
releaseMouse();
if(flag)
{
QWSServer::mouseHandler()->calibrate(&initial_data);
}
else
{
QPoint *points_seceen = data_read.screenPoints;
QPoint *points_dev = data_read.devPoints;
//reade the calibrated data from setup file
QSettings *readini = new QSettings(INIT_PATH, QSettings::IniFormat, 0);
readini->beginGroup("calibrat_data");
points_seceen[QWSPointerCalibrationData::TopLeft] = readini->value("screen_Topleft").toPoint();
points_seceen[QWSPointerCalibrationData::BottomLeft] = readini->value("screen_BottomLeft").toPoint();
points_seceen[QWSPointerCalibrationData::BottomRight] = readini->value("screen_BottomRight").toPoint();
points_seceen[QWSPointerCalibrationData::TopRight] = readini->value("screen_TopRight").toPoint();
points_seceen[QWSPointerCalibrationData::Center] = readini->value("screen_Center").toPoint();
points_dev[QWSPointerCalibrationData::TopLeft] = readini->value("dev_Topleft").toPoint();
points_dev[QWSPointerCalibrationData::BottomLeft] = readini->value("dev_BottomLeft").toPoint();
points_dev[QWSPointerCalibrationData::BottomRight] = readini->value("dev_BottomRight").toPoint();
points_dev[QWSPointerCalibrationData::TopRight] = readini->value("dev_TopRight").toPoint();
points_dev[QWSPointerCalibrationData::Center] = readini->value("dev_Center").toPoint();
readini->endGroup();
delete readini;
QWSServer::mouseHandler()->calibrate(&data_read);
}
QDialog::accept();
qDebug("will release mouse");
}
//! [7]
static bool processflag = false;
static bool calibrating = false;
class Q_GUI_EXPORT QWSMouseHandler
{
public:
explicit QWSMouseHandler(const QString &driver = QString(),
const QString &device = QString());
virtual ~QWSMouseHandler();
virtual void clearCalibration() {}
virtual void calibrate(const QWSPointerCalibrationData *) {}
virtual void getCalibration(QWSPointerCalibrationData *) const {}
virtual void resume() = 0;
virtual void suspend() = 0;
void limitToScreen(QPoint &pt);
void mouseChanged(const QPoint& pos, int bstate, int wheel = 0);
const QPoint &pos() const { return mousePos; }
void setScreen(const QScreen *screen);
protected:
QPoint &mousePos;
QWSMouseHandlerPrivate *d_ptr;
};
class Q_GUI_EXPORT QWSCalibratedMouseHandler : public QWSMouseHandler
{
public:
explicit QWSCalibratedMouseHandler(const QString &driver = QString(),
const QString &device = QString());
virtual void clearCalibration();
virtual void calibrate(const QWSPointerCalibrationData *);
virtual void getCalibration(QWSPointerCalibrationData *) const;
protected:
bool sendFiltered(const QPoint &, int button);
QPoint transform(const QPoint &);
void readCalibration();
void writeCalibration();
void setFilterSize(int);
private:
int a, b, c;
int d, e, f;
int s;
QPolygon samples;
int currSample;
int numSamples;
};
void QWSCalibratedMouseHandler::calibrate(const QWSPointerCalibrationData *data)
{
// Algorithm derived from
// "How To Calibrate Touch Screens" by Carlos E. Vidales,
// printed in Embedded Systems Programming, Vol. 15 no 6, June 2002
// URL: http://www.embedded.com/showArticle.jhtml?articleID=9900629
const QPoint pd0 = data->devPoints[QWSPointerCalibrationData::TopLeft];
const QPoint pd1 = data->devPoints[QWSPointerCalibrationData::TopRight];
const QPoint pd2 = data->devPoints[QWSPointerCalibrationData::BottomRight];
const QPoint p0 = data->screenPoints[QWSPointerCalibrationData::TopLeft];
const QPoint p1 = data->screenPoints[QWSPointerCalibrationData::TopRight];
const QPoint p2 = data->screenPoints[QWSPointerCalibrationData::BottomRight];
const qint64 xd0 = pd0.x();
const qint64 xd1 = pd1.x();
const qint64 xd2 = pd2.x();
const qint64 yd0 = pd0.y();
const qint64 yd1 = pd1.y();
const qint64 yd2 = pd2.y();
const qint64 x0 = p0.x();
const qint64 x1 = p1.x();
const qint64 x2 = p2.x();
const qint64 y0 = p0.y();
const qint64 y1 = p1.y();
const qint64 y2 = p2.y();
qint64 scale = ((xd0 - xd2)*(yd1 - yd2) - (xd1 - xd2)*(yd0 - yd2));
int shift = 0;
qint64 absScale = qAbs(scale);
// use maximum 16 bit precision to reduce risk of integer overflow
if (absScale > (1 << 16)) {
shift = ilog2(absScale >> 16) + 1;
scale >>= shift;
}
s = scale;
a = ((x0 - x2)*(yd1 - yd2) - (x1 - x2)*(yd0 - yd2)) >> shift;
b = ((xd0 - xd2)*(x1 - x2) - (x0 - x2)*(xd1 - xd2)) >> shift;
c = (yd0*(xd2*x1 - xd1*x2) + yd1*(xd0*x2 - xd2*x0) + yd2*(xd1*x0 - xd0*x1)) >> shift;
d = ((y0 - y2)*(yd1 - yd2) - (y1 - y2)*(yd0 - yd2)) >> shift;
e = ((xd0 - xd2)*(y1 - y2) - (y0 - y2)*(xd1 - xd2)) >> shift;
f = (yd0*(xd2*y1 - xd1*y2) + yd1*(xd0*y2 - xd2*y0) + yd2*(xd1*y0 - xd0*y1)) >> shift;
writeCalibration();
}
void QWSCalibratedMouseHandler::readCalibration()
{
QString calFile = QString::fromLocal8Bit(qgetenv("POINTERCAL_FILE"));
if (calFile.isEmpty())
calFile = QLatin1String("/etc/pointercal");
#ifndef QT_NO_TEXTSTREAM
QFile file(calFile);
if (file.open(QIODevice::ReadOnly)) {
QTextStream t(&file);
t >> a >> b >> c >> d >> e >> f >> s;
if (s == 0 || t.status() != QTextStream::Ok) {
qCritical("Corrupt calibration data");
clearCalibration();
}
} else
#endif
{
qDebug() << "Could not read calibration:" <<calFile;
}
}
void QWSCalibratedMouseHandler::writeCalibration()
{
QString calFile;
calFile = QString::fromLocal8Bit(qgetenv("POINTERCAL_FILE"));
if (calFile.isEmpty())
calFile = QLatin1String("/etc/pointercal");
#ifndef QT_NO_TEXTSTREAM
QFile file(calFile);
if (file.open(QIODevice::WriteOnly)) {
QTextStream t(&file);
t << a << ' ' << b << ' ' << c << ' ';
t << d << ' ' << e << ' ' << f << ' ' << s << endl;
} else
#endif
{
qCritical("QWSCalibratedMouseHandler::writeCalibration: "
"Could not save calibration into %s", qPrintable(calFile));
}
}
调用Qt的触摸屏校准程序
calibrating = true;
cal.init();
cal.exec();
当有Qt最底层来关机或者睡眠选择的消息
void Maintenance_State::listenChannel()
{
channel = new QCopChannel("/System/Key_related", this);
connect(channel, SIGNAL(received(const QString &, const QByteArray &)),
this, SLOT(handleCopMsg(const QString &, const QByteArray &)));
}
void Maintenance_State::handleCopMsg(const QString &message, const QByteArray &data)
{
// usleep(10); //wait for the child app is closed
qDebug("maintenancestate:receive message from input method");
QDataStream in(data);
if (message == "desktop_or_shutdown(int)")
{
if(calibrating)
{
cal.calibration_quit();
qDebug("calibration will be closed");
calibrating = false;
activateWindow();
}
}
}
class MyinputMethod : public QWSInputMethod
{
Q_OBJECT
public:
MyinputMethod();
~MyinputMethod();
virtual bool filter(const QPoint &, int state, int wheel);
virtual bool filter(int unicode, int keycode, int modifiers,bool isPress, bool autoRepeat );
QTimer *timer_shut;
public slots:
void timer_shut_slot();
void handleCopMsg(const QString &message, const QByteArray &data);
signals:
private:
QCopChannel *channel;
QCopChannel *system_channel;
void sendCopMsg(int desknumber);
void listenChannel();
};
bool MyinputMethod::filter(int unicode, int keycode, int modifiers,bool isPress, bool autoRepeat )
{
timer_shut->start(time_to_shut);
// qDebug("inputmethod:enter keyboard filter");
if(screensave_state)
{
key_filter_flag++;
// qDebug("inputmetgod:save mode keyvalue is fileterd");
if(key_filter_flag >= 2)
{
key_filter_flag = 0;
screensave_state = false;
}
return true;
}
else
{
// qDebug("unicode is %d,keycode is %d",unicode,keycode);
if(((unicode == 48) || (unicode == 50)) && isPress)
{
// qDebug("key0 or key1 is pressed");
sendCopMsg(unicode);
// qDebug("keycode is sent");
return true;
}
}
return false;
}
void MyinputMethod::listenChannel()
{
channel = new QCopChannel("/System/Key_related", this);
connect(channel, SIGNAL(received(const QString &, const QByteArray &)),
this, SLOT(handleCopMsg(const QString &, const QByteArray &)));
system_channel = new QCopChannel("/System/system_related", this);
connect(system_channel, SIGNAL(received(const QString &, const QByteArray &)),
this, SLOT(handleCopMsg(const QString &, const QByteArray &)));
}
void MyinputMethod::sendCopMsg(int keynumber)
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
out << keynumber;
QCopChannel::send("/System/Key_related", "desktop_or_shutdown(int)",data);
}