Qt 触摸屏校准程序

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);
 }

 

 

 

你可能感兴趣的:(Qt 触摸屏校准程序)