一、Qt3/Embedded的输入设备的驱动接口实现原理分析
1、Qt3/Embedded把与底层硬件相关的源文件统一放在src/embedded目录下,所以我们最好也把自己的设备驱动接口文件放到此目录。
2、Qt/Embedded中的输入设备分为鼠标类与键盘类。在3.x版本系列中,鼠标设备的抽象基类为QWSMouseHandler,在src/embedded/qmouse_qws.h中定义,键盘设备的抽象基类为QWSKeyboardHandler,在src/embedded/qkbd_qws.h中定义。对于具体的输入设备我们则从这两个基类重新派生出它的实现类。
3、系统加载过程分析。Qt/Embedded在体系上为C/S结构,任何一个Qt/Embedded程序都可以作为系统中唯一的一个GUI Server存在。当应用程序首次以系统GUI Server的方式加载时,将建立QWSServer实体。在系统加载构造QWSServer时,将会调用QWSServer::openMouse与QWSServer::openKeyboard函数 (建立QWSServer实体的源文件是src/kernel/qwindowsystem_qws.cpp)。这两个函数分别调用QMouseDriverFactory::create()与QKbdDriverFactory::create()函数,它们分别是在src/embedded/qmousedriverfactory_qws.h和src/embedded/qkbddriverfactory_qws.h中定义。这时会根据嵌入式Linux系统的环境变量QWS_MOUSE_PROTO与QWS_KEYBOARD获得鼠标类设备和键盘类设备的设备类型和设备节点。打开相应设备并返回相应设备的基类句柄指针给系统,系统通过将该基类指令强制转换为对应的具体子类设备指针,获得对具体鼠标类设备和键盘类设备的调用操作。也就是说,我们只要把自己的设备类放在create()函数中即可。调用关系如下:
QWSServer::openMouse() à QMouseDriverFactory::create() à MyMouseHandler ← QWSMouseHandler
鼠标接口的加载过程
QWSServer::openKeyboard() à QKbdDriverFactory::create() à MyKeyboarddHandler ← QWSKeyboardHandler
键盘接口的加载过程
二、在QTE中实现自己的设备驱动接口
经过上面的分析可以发现,要在QTE中实现自己的设备接口其实是很容易的事情。下面以键盘接口的实现为例,简单介绍一下具体的实现过程,鼠标接口也是差不多的。
在QTE中实现自己的键盘接口只需要三步:
1、从抽象基类QWSKeyboardHandler派生出具体类,如MyKbdHandler。为此我们在QTE的子目录src/embedded中新建两个文件mykbd_qws.h和mykbd_qws.cpp,内容如下:
(1) mykbd_qws.h的内容:
#ifndef MYKBD_QWS_H
#define MYKBD_QWS_H
#include "qkbd_qws.h" //QT定义抽象基类QWSKeyboardHandler
#ifndef QT_NO_MYKBD //编译时可以通过定义这个变量从而不编译这个模块
class MyKbdPrivate; //我们的键盘设备私有类,实现具体的键盘设备操作,如打开键盘、读键盘数据,解析按键等等。
class MyKbdHandler : public QWSKeyboardHandler //供系统调用的键盘句柄
{
public:
MyKbdHandler(const QString&);
virtual ~MyKbdHandler();
private:
MyKbdPrivate *d;
};
#endif // QT_NO_MYKBD
#endif // MYKBD_QWS_H
(2)mykbd_qws.cpp的内容:
#include "mykbd_qws.h"
#ifndef QT_NO_MYKBD
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <qsocketnotifier.h>
class MyKbdPrivate : public QObject
{
Q_OBJECT
public:
MyKbdPrivate( MyKbdHandler *h, const QString& );
virtual ~MyKbdPrivate();
bool isOpen() { return buttonFD > 0; }
private slots:
void readKeyboardData();
private:
QString terminalName;
int buttonFD;
int kbdIdx;
int kbdBufferLen;
unsigned char *kbdBuffer;
QSocketNotifier *notifier;
MyKbdHandler *handler;
};
MyKbdPrivate::MyKbdPrivate(MyKbdHandler *h, const QString &device ) : handler(h)
{
terminalName = device.isEmpty()?"/dev/mykeyboard":device.latin1();
buttonFD = -1;
notifier = 0;
if ((buttonFD = open(terminalName, O_RDWR | O_NDELAY, 0)) < 0)
{
qWarning("Cannot open %s/n", terminalName.latin1());
}
if ( buttonFD >= 0 ) {
notifier = new QSocketNotifier( buttonFD, QSocketNotifier::Read, this );
connect( notifier, SIGNAL(activated(int)),this,
SLOT(readKeyboardData()) );
}
kbdBufferLen = 80;
kbdBuffer = new unsigned char [kbdBufferLen];
kbdIdx = 0;
}
MyKbdPrivate::~ MyKbdPrivate()
{
if ( buttonFD > 0 ) {
::close( buttonFD );
buttonFD = -1;
}
delete notifier;
notifier = 0;
delete [] kbdBuffer;
}
void MyKbdPrivate::readKeyboardData()
{
int n = 0;
int idx = 0;
n = read(buttonFD, kbdBuffer+kbdIdx, 4);
unsigned char *next = kbdBuffer + idx;
int *code = (int *)next;
int keycode = Qt::Key_unknown;
switch ( (*code) & 0xff ) {
case 11:
keycode = Qt::Key_Backtab;
break;
case 12:
keycode = Qt::Key_Return;
break;
case 13:
keycode = Qt::Key_Tab;
break;
case 14:
keycode = Qt::Key_Up;
break;
case 15:
keycode = Qt::Key_Down;
break;
default:
qDebug("Unrecognised key code %d", *code );
}
handler->processKeyEvent( 0, keycode, 0, TRUE, FALSE );
}
MyKbdHandler::MyKbdHandler(const QString &device)
{
d = new MyKbdPrivate( this, device );
}
MyKbdHandler::~MyKbdHandler()
{
delete d;
}
#include "mykbd_qws.moc"
#endif // QT_NO_MYKBD
2、把MyKbdHandler加入QkbdDriverFactory::create()函数中。在src/embedded/qkbddriverfactory_qws.cpp文件中加入头文件:
#include “mykbd_qws.h”
然后找到QkbdDriverFactory::create()这个函数,在”Qstring driver = key.lower();”这一行的后面加上以下几行:
#ifndef QT_NO_MYKBD
if ( driver == “mykbd” || driver.isEmpty() )
return new MyKbdHandler( device );
#endif
3、重新编译QT/Embedded并把生成的qt库文件下载到开发板上,然后在目标板上设置系统变量,输入命令:export QWS_KEYBOARD=’MYKBD:/dev/mykeyboard’。
至此 QT3/Embedded 的键盘设备接口已经完成。