Chinaunix首页 | 论坛 | 博客
  • 博客访问: 183980
  • 博文数量: 41
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 600
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-23 21:42
文章分类

全部博文(41)

文章存档

2008年(41)

我的朋友

分类: LINUX

2008-07-27 11:11:05

qwsmouse_qws.cpp在qt2.3.1/src/kernel目录下面
Qt的鼠标和触摸屏驱动

Qt的鼠标和触摸屏驱动主要集中在qwsmouse_qws.cpp当中.在qt中,触摸屏作为一种特别的鼠标,具有和鼠标同等的处理方法.
在qt初始化的时候,会输入一些环境变量,包括
QWS_KEYBORAD:设定键盘的类型
QWS_MOUSE_PROT设定鼠标的类型和设备.格式是:
:
protocol包括以下的几种:MouseMan,IntelliMouse,Microsoft等,
device就是鼠标(或者触摸屏)的设备文件,一般是/dev/mouse,还可能是/dev/ps2(ps类型的鼠标),ttyS*(串口鼠标),而对于触摸屏,则会是/dev/Tpanel(在2.4.*的qte版本中).
因为鼠标的驱动是qt的server的功能,而server关于鼠标的代码就集中在qwsmouse_qws.cpp中.由于qtembedded是由c + +语言写成,所以鼠标的驱动,实际上就是一些不同的鼠标类的实现,他们的基类就是QMouseHandle或者QAutoMouseHandle.
整个的流程是这样的:
根据环境变量QWS_MOUSE_PROTO的定义,选择一个特定的鼠标驱动程序来完成鼠标的驱动(选择一个特定的鼠标类来完成).在特定的鼠标驱动程序 中,首先打开设备文件,如果设备文件为空,就打开默认的设备文件,相应的默认设备文件在代码中都有详细的介绍.然后通过读取设备文件的数据,分析得到的数 据,变换成相应的鼠标消息,通过SendMouseEvent的方式,将其发送到应用程序.
触摸屏的不同之处在于,它需要进行调整.因为从设备得到的数据是物理屏的数据,比如s3c2410的触摸屏的ad转换是10位精度,也就是说物理数据从 0~1023,在实际的情况中一般是100~1000之间的数据,而我们的液晶屏是640*480(或者是其他的,这和触摸屏的数据没有任何的关系),所 以必须将物理数据转换为屏幕上点的数据.他们之间的转换公式,就必须通过定标的方式来确定.
所谓的定标,就是在屏幕上依次出现topleft,bottomleft,bottomright,topright和center一共5个点,用户必须 依次在这5个点上点击(在触摸屏上点击,触摸屏就放在液晶屏的上方),这样我们得到了物理的点,也得到了对应的实际的点,因此就可以计算出相应的参数,计 算公式是:
s=1<<16;
a=s*(screen_tl.x()-screen_br.x())/(dev_tl.x()-dev_br.x());
b=0;
c=s*screen_tl.x()-a*dev_tl.x();
d=0;
e=s*(screen_tl.y()-screen_br.y())/(dev_tl.y()-dev_br.y());
f=s*screen_tl.y()-e*dev_tl.y();
假设p是物理的数据,那么转换到屏幕上点的公式就是:
x=(a*p.x()+b*p.y()+c)/s);
y=(d*p.x()+e*p.y()+f)/s);
需要注意的是:如果物理的点特别的不合常理,比如左边和右边的y的差值相差太大,说明屏的线性度太差,不会通过测试.
S3c2410的触摸屏驱动是iPAQ兼容的驱动,编译的时候需要定义2个宏:
QWS_MOUSE_IPAQ,QWS_MOUSE_IPAQ_RAW.同时设定的是
QWS_MOUSE_PROTO=Tpanel:/dev/h3600_tsraw
上面列举的参数,会首先从文件/etc/pointercal中读取,这个文件格式就是:
abcdefs
如果屏的质量稳定,我们可以将测得的数据放在这个文件当中,并取消掉定标的过程,这样就可以每次使用默认的设置,而不需要重新计算了.
贴个源码,大家参考一下,在qwsmouse_qws.cpp中添加:
typedef struct
{
/* liftup: 0 / touchdown: 0x7f */
short pressure;
short xpos;
short ypos;
short timestamp;
} ts_sample; //检索触笔状态
typedef struct
{
int xscale;
int xtrans;
int yscale;
int ytrans;
int reverse;
} ts_cal_values; //触笔坐标校正
class QWSXscaleMouseHandlerPrivate : public QWSMouseHandler
{
Q_OBJECT
public:
QWSXscaleMouseHandlerPrivate(MouseProtocol protocol, QString mouseDev);
~QWSXscaleMouseHandlerPrivate();
private:
int mouseFD;
int prevstate;
private slots:
void readMouseData();
};
QWSXscaleMouseHandlerPrivate::QWSXscaleMouseHandlerPrivate( MouseProtocol protocol, QString mouseDev)
{
if ( mouseDev.isEmpty() )
mouseDev = "/dev/ts";
if ((mouseFD = open( mouseDev, O_RDONLY)) < 0) { //重要的是打开特定文件设备
qWarning( "Cannot open %s(%s)", mouseDev.latin1(),strerror(errno));
return;
} else {
sleep(1);
}
prevstate=0;
QSocketNotifier *mouseNotifier;
mouseNotifier = new QSocketNotifier( mouseFD, QSocketNotifier::Read,
this );
connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
}
QWSXscaleMouseHandlerPrivate::~QWSXscaleMouseHandlerPrivate()
{
if (mouseFD >= 0)
close(mouseFD);
}
void QWSXscaleMouseHandlerPrivate::readMouseData()
{
if(!qt_screen)
return;
//YopyTPdata data;
//unsigned int yopDat[4];
ts_sample data;//实际设备的数据结构
int ret;
//ret=read(mouseFD,&yopDat,sizeof(yopDat));
ret=read(mouseFD,&data,sizeof(ts_sample));//读取实际设备数据
if(ret) {
//data.status= ( YOPY_PRES(yopDat) ) ? 1 : 0;
data.pressure= data.pressure & 0xFF;//取得触笔状态
//data.xpos= yopDat.xpos;
//data.ypos= yopDat.ypos;
QPoint q;
q.setX(data.xpos);
q.setY(data.ypos);
//if (data.status && !prevstate) {
if (data.pressure == 0x01 && !prevstate) {//判断触笔状态
emit mouseChanged(q,Qt::LeftButton);//转换为鼠标左键压下事件
}
//else if( !data.status && prevstate ) {
else if( !data.pressure && prevstate ) {
emit mouseChanged(q,0);
}
prevstate = data.pressure;
}
else{
qDebug("Error %s",strerror(errno));
}
}
然后在QWSMouseHandler* QWSServer::newMouseHandler(const QString& spec)函数中添加:
handler = new QWSXscaleMouseHandlerPrivate( mouseProtocol, mouseDev );

阅读(2353) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~