背景知识:
http://doc.qt.nokia.com/4.6/qt-embedded-architecture.html Qt for Embedded Linux Architecture
http://doc.qt.nokia.com/4.6/qt-embedded-pointer.html#available-drivers Qt for Embedded Linux Pointer Handling
QTSRC/src/gui/embeded/qmouselinuxinput_qws.cpp
主要的要点是:
1. EQT 默认只支持“pc”类型的鼠标驱动,具体来说就是如下类型:Auto、IntelliMouse、Microsoft、MouseSystems。
要使EQT 支持Linux input子系统的鼠标驱动,在编译QT时 configure 要添加参数: -qt-mouse-linuxinput
(具体的configure的帮助请运行: ./configure -embedded -help .)
2. 确保触摸屏提交到Linux input子系统的坐标数据是正确的,我们需要通过解析/dev/event0 的数据来证明
原理说明:
1. 分辨率转化和校准
其实,这一款32寸的IRTOUCH产生的坐标值是绝对坐标,范围x、y均为 0~4096。所以,我们运行的QT程序如果直接获取
event0产生的坐标的话,鼠标位置便会超出屏幕的显示范围,因此,我们需要进行一下坐标值转化,具体的函数如下:
void adjuest(int* pX,int* pY)
{
//* pX = 1280.0f / 1248 * (2272 - *pX); // 中间版本
* pY = 720.0f / 700 * (*pY - 1030);
* pX = (int)(1280.0f / 4062 * (*pX - 7)); // 最旧版本
* pY = (int)(720.0f / 4071 * (*pY));
*pX = (int)((*pX)*1280.0f/4050);
*pY = (int)((*pY)*720.0f/4080);
* pX = (int)((*pX)*1280.0f/4095); // 最新版本
* pY = (int)((*pY)*720.0f/4095);
}
该函数就可以将原来4096*4096的分辨率转换成 1280*720;至于具体的数值,我们需要根据实际的屏幕产生的数据进行修改,
重点在于四角和中间点。
分辨率一旦设置合适,屏幕鼠标也就会校准,该函数的作用类似于void QWSLinuxInputMousePrivate::readMouseData()函数中
调用的 pos = m_handler->transform(pos)。transform()函数会根据/etc/pointercal来进行校准,如果你没有运行过校准程序
默认会没有该文件的。(QT自带的例子里面有一个校准程序:qt\examples\qws\mousecalibration。但是,由于不同的嵌入式
平台采用的芯片差异性很大,所以,这个校准程序往往无法使用,所以,才会自己编写一个adjuest()函数来调整原始坐标值。)
2. 触摸屏的降噪和去抖动
由于触摸屏本身的原因导致每次产生的数据并不是都准确和正确的,所以,我们需要对坐标进行一些处理,
主要目的在于尽量消除误差,提高触摸屏的准确度。由于不用硬件会有不同的情况,我们需要变通的处理。这一点也是比较
让人头疼的地方。下面就简单的贴出代码:
http://doc.qt.nokia.com/4.6/qt-embedded-architecture.html Qt for Embedded Linux Architecture
http://doc.qt.nokia.com/4.6/qt-embedded-pointer.html#available-drivers Qt for Embedded Linux Pointer Handling
QTSRC/src/gui/embeded/qmouselinuxinput_qws.cpp
主要的要点是:
1. EQT 默认只支持“pc”类型的鼠标驱动,具体来说就是如下类型:Auto、IntelliMouse、Microsoft、MouseSystems。
要使EQT 支持Linux input子系统的鼠标驱动,在编译QT时 configure 要添加参数: -qt-mouse-linuxinput
(具体的configure的帮助请运行: ./configure -embedded -help .)
2. 确保触摸屏提交到Linux input子系统的坐标数据是正确的,我们需要通过解析/dev/event0 的数据来证明
原理说明:
1. 分辨率转化和校准
其实,这一款32寸的IRTOUCH产生的坐标值是绝对坐标,范围x、y均为 0~4096。所以,我们运行的QT程序如果直接获取
event0产生的坐标的话,鼠标位置便会超出屏幕的显示范围,因此,我们需要进行一下坐标值转化,具体的函数如下:
void adjuest(int* pX,int* pY)
{
//* pX = 1280.0f / 1248 * (2272 - *pX); // 中间版本
* pY = 720.0f / 700 * (*pY - 1030);
* pX = (int)(1280.0f / 4062 * (*pX - 7)); // 最旧版本
* pY = (int)(720.0f / 4071 * (*pY));
*pX = (int)((*pX)*1280.0f/4050);
*pY = (int)((*pY)*720.0f/4080);
* pX = (int)((*pX)*1280.0f/4095); // 最新版本
* pY = (int)((*pY)*720.0f/4095);
}
该函数就可以将原来4096*4096的分辨率转换成 1280*720;至于具体的数值,我们需要根据实际的屏幕产生的数据进行修改,
重点在于四角和中间点。
分辨率一旦设置合适,屏幕鼠标也就会校准,该函数的作用类似于void QWSLinuxInputMousePrivate::readMouseData()函数中
调用的 pos = m_handler->transform(pos)。transform()函数会根据/etc/pointercal来进行校准,如果你没有运行过校准程序
默认会没有该文件的。(QT自带的例子里面有一个校准程序:qt\examples\qws\mousecalibration。但是,由于不同的嵌入式
平台采用的芯片差异性很大,所以,这个校准程序往往无法使用,所以,才会自己编写一个adjuest()函数来调整原始坐标值。)
2. 触摸屏的降噪和去抖动
由于触摸屏本身的原因导致每次产生的数据并不是都准确和正确的,所以,我们需要对坐标进行一些处理,
主要目的在于尽量消除误差,提高触摸屏的准确度。由于不用硬件会有不同的情况,我们需要变通的处理。这一点也是比较
让人头疼的地方。下面就简单的贴出代码:
#include "qmouselinuxinput_qws.h"
#include <QScreen>
#include <QSocketNotifier>
#include <qplatformdefs.h>
#include <private/qcore_unix_p.h> // overrides QT_OPEN
#include <errno.h>
#include <linux/input.h>
QT_BEGIN_NAMESPACE
class QWSLinuxInputMousePrivate : public QObject
{
Q_OBJECT
public:
QWSLinuxInputMousePrivate(QWSLinuxInputMouseHandler *, const QString &);
~QWSLinuxInputMousePrivate();
void enable(bool on);
void setButton(int num){m_buttons = num;}
private Q_SLOTS:
void readMouseData();
private:
QWSLinuxInputMouseHandler *m_handler;
QSocketNotifier * m_notify;
int m_fd;
int m_x, m_y;
int m_buttons;
};
QWSLinuxInputMouseHandler::QWSLinuxInputMouseHandler(const QString &device)
: QWSCalibratedMouseHandler(device)
{
printf("Enter QWSLinuxInputMouseHandler \n");
d = new QWSLinuxInputMousePrivate(this, device);
}
QWSLinuxInputMouseHandler::~QWSLinuxInputMouseHandler()
{
delete d;
}
void QWSLinuxInputMouseHandler::suspend()
{
d->enable(false);
}
void QWSLinuxInputMouseHandler::resume()
{
d->enable(true);
}
QWSLinuxInputMousePrivate::QWSLinuxInputMousePrivate(QWSLinuxInputMouseHandler *h, const QString &device)
: m_handler(h), m_notify(0), m_x(0), m_y(0), m_buttons(0)
{
setObjectName(QLatin1String("LinuxInputSubsystem Mouse Handler"));
QString dev = QLatin1String("/dev/event0");
if (device.startsWith(QLatin1String("/dev/")))
dev = device;
m_fd = QT_OPEN(dev.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);
if (m_fd >= 0) {
m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData()));
} else {
qWarning("Cannot open mouse input device '%s': %s", qPrintable(dev), strerror(errno));
return;
}
}
QWSLinuxInputMousePrivate::~QWSLinuxInputMousePrivate()
{
if (m_fd >= 0)
QT_CLOSE(m_fd);
}
void QWSLinuxInputMousePrivate::enable(bool on)
{
if (m_notify)
m_notify->setEnabled(on);
}
void adjuest(int* pX,int* pY)
{
//* pX = 1280.0f / 1248 * (2272 - *pX); // 中间版本
* pY = 720.0f / 700 * (*pY - 1030);
* pX = (int)(1280.0f / 4062 * (*pX - 7)); // 最旧版本
* pY = (int)(720.0f / 4071 * (*pY));
*pX = (int)((*pX)*1280.0f/4050);
*pY = (int)((*pY)*720.0f/4080);
* pX = (int)((*pX)*1280.0f/4095); // 最新版本
* pY = (int)((*pY)*720.0f/4095);
}
void QWSLinuxInputMousePrivate::readMouseData()
{
if (!qt_screen)
return;
struct ::input_event buffer[32];
int n = 0;
static bool setXflag = 0;
static bool setYflag = 0;
forever {
n += QT_READ(m_fd, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n);
if (n == 0) {
qWarning("Got EOF from the input device.");
return;
} else if (n < 0 && (errno != EINTR && errno != EAGAIN)) {
qWarning("Could not read from input device: %s", strerror(errno));
return;
} else if (n % sizeof(buffer[0]) == 0) {
break;
}
}
n /= sizeof(buffer[0]);
for (int i = 0; i < n; ++i) {
struct ::input_event *data = &buffer[i];
bool unknown = false;
if (data->type == EV_ABS) {
if (data->code == ABS_X && !setXflag) {
m_x = data->value;
setXflag = 1;
} else if (data->code == ABS_Y && !setYflag) {
m_y = data->value;
setYflag = 1;
} else {
unknown = true;
}
} else if (data->type == EV_SYN && data->code == SYN_REPORT && setXflag && setYflag) {
adjuest(&m_x, &m_y);
printf("########### X=%d Y=%d\n", m_x, m_y);
QPoint pos(m_x, m_y);
//pos = m_handler->transform(pos);
//m_handler->limitToScreen(pos);
setButton(3);
m_handler->mouseChanged(pos, m_buttons);
setXflag = setYflag = 0;
setButton(0);
usleep(1000);
m_handler->mouseChanged(pos, m_buttons);
return;
} else if (data->type == EV_MSC && data->code == MSC_SCAN) {
// kernel encountered an unmapped key - just ignore it
continue;
} else {
unknown = true;
}
if (unknown) {
qWarning("unknown mouse event type=%x, code=%x, value=%x", data->type, data->code, data->value);
}
}
}
QT_END_NAMESPACE
#include "qmouselinuxinput_qws.moc"