Pointer Handling Layer
The mouse driver (represented by an instance of the QWSMouseHandlerclass) is loaded by the server application when it startsrunning(当鼠标驱动需要运行时), using Qt's pluginsystem.
A mouse driver(即图中的Mouse Handler, 由QWSMouseHandler类或其派生类的实例描述)receives mouse events from the device and
Qt forEmbedded Linux provides ready-made(现成的) drivers for severalmouse protocols, see the pointerhandling documentation for details. Custom mouse drivers can beimplemented by subclassing the QWSMouseHandlerclass and creating a mouse driver plugin. The defaultimplementation of the QMouseDriverFactoryclass will automatically detect the plugin, loading the driver intothe server application at runtime.
In addition to the generic mouse handler, Qt forEmbedded Linux provides a calibrated mouse handler. Use theQWSCalibratedMouseHandle
See also: Qt forEmbedded Linux Pointer Handling and How to CreateQt Plugins.
2. 在Qt源代码中search : tslib对上层的接口函数ts_read() /ts_read_raw()=> 仅有src/gui/embedded/qmousetslib_qws.cpp中调用, 可见,类QWSTslibMouseHandlerPriv
其代码注释:
Pointer Handling
To make
3. 阅读tslib源代码中的README,了解ts.conf的配置
结合以上内容可以得到以下信息:
1.要能正确使用触摸屏鼠标必须要做到:
2.结合源代码Tslib鼠标的结构图:
Mouse Driver Factory : QMouseDriverFactory
Mouse DriverPlugin :
Mouse Handler
现象:点击触摸屏有反映,但是触点与鼠标图标之间总是有距离,而且距离随着触控操作变化:如,点击屏角,使触控点和鼠标位置很接近,
问题分析:触摸屏有反映说明tslib有触控事件送往QWSTslibMouseHandler,怀疑只是送往QWSTslibMouseHandler的坐标信息未矫正
=> 直接运行tslib的配套工具
=> google类似问题,多为校验问题,有些文章提到QWS_MOUSE_PROTO显示指定鼠标事件来源,结合以上总结,怀疑是否使Qt默认没有使用正确的鼠标事件.
=> QWS_MOUSE_PROTO
Specifies the driverfor pointer handling. For example, if the current shell is bash,ksh, zsh or sh: exportQWS_MOUSE_PROTO=<driver>[:<driverspecific options>]<driver> <driver specificoptions> are typically a device,e.g.,/dev/mouse for mouse devicesand/dev/tsfor touch panels.确认设备的方法: 如,测试/dev/input/mice 是否是输入设备: cat /dev/input/mice |hexdump, 测试移动鼠标应该有数据输出 Multiple mousedrivers can be specified in one go: exportQWS_MOUSE_PROTO="<driver>[:<driverspecific options>]<driver>[:<driverspecific options>]<driver>[:<driverspecific options>]" |
=> 使用cat发现目标设备的触摸屏设备文件为/etc/input/event1,所以设置exportQWS_MOUSE_PROTO=tslib:/etc/input/event1, 累计偏移故障消失
=>为同时使用USB鼠标,用cat发现/etc/input/mice为USB鼠标输入,所以设置:exportQWS_MOUSE_PROTO="tslib:/etc/input/event1interlliMouse:/etc/input/mice". 此时USB鼠标可用,但是触摸屏鼠标又出现累计偏差,怀疑和mice(mouse的复数)有关,是否mice是一个叠加输入?
应该有单独输入的设备文件.
=>用cat测试/dev/input下的设备文件,发现USB鼠标的输入文件还有/dev/input/mouse1,反过来触控触摸屏/dev/input/mice也有输出,但是比较event1与mice的数据发现不同
=>QWS_MOUSE_PROTO中针对USB鼠标和触摸屏分别使用各自独立的设备文件exportQWS_MOUSE_PROTO="tslib:/etc/input/event1interlliMouse:/etc/input/mouse1", 问题解决.
=> 结论:mice是所有鼠标设备的设备文件(USB/PS2鼠标 或
Mouse Calibration Example
Files:
- qws/mousecalibration/calibration.cpp
- qws/mousecalibration/calibration.h
- qws/mousecalibration/scribblewidget.cpp
- qws/mousecalibration/scribblewidget.h
- qws/mousecalibration/main.cpp
- qws/mousecalibration/mousecalibration.pro
-
The Mouse Calibration example demonstrates how to write a simple program using the mechanisms provided by the QWSMouseHandler class to calibrate the mouse handler in Qt for Embedded Linux.
Calibration is the process of mapping between physical (i.e. device) coordinates and logical coordinates.
The example consists of two classes in addition to the main program:
- Calibration is a dialog widget that retrieves the device coordinates.
- ScribbleWidget is a minimal drawing program used to let the user test the new mouse settings.
First we will review the main program, then we will take a look at the Calibration class. The ScribbleWidget class is only a help tool in this context, and will not be covered here.
The Main Program
The program starts by presenting a message box informing the user of what is going to happen:
int main(int argc, char **argv) { QApplication app(argc, argv, QApplication::GuiServer); if (!QWSServer::mouseHandler()) qFatal("No mouse handler installed"); { 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(); }
The QMessageBox class provides a modal dialog with a range of different messages, roughly arranged along two axes: severity and complexity. The message box has a different icon for each of the severity levels, but the icon must be specified explicitly. In our case we use the defaultQMessageBox::NoIcon value. In addition we use the default complexity, i.e. a message box showing the given text and an OK button.
At this stage in the program, the mouse could be completely uncalibrated, making the user unable to press the OK button. For that reason we use the static QTimer::singleShot() function to make the message box disappear after 10 seconds. The QTimer class provides repetitive and single-shot timers: The single shot function calls the given slot after the specified interval.
Calibration cal; cal.exec();
Next, we create an instance of the Calibration class which is a dialog widget retrieving the required sample coordinates: The dialog sequentially presents five marks for the user to press, storing the device coordinates for the mouse press events.
{ QMessageBox message; message.setText("<p>The next screen will let you test the calibration " "by drawing into a widget.</p><p>This program will " "automatically close after 20 seconds.<p>"); QTimer::singleShot(10 * 1000, &message, SLOT(accept())); message.exec(); } ScribbleWidget scribble; scribble.showMaximized(); scribble.show(); app.setActiveWindow(&scribble); QTimer::singleShot(20 * 1000, &app, SLOT(quit())); return app.exec(); }
When the calibration dialog returns, we let the user test the new mouse settings by drawing onto a ScribbleWidget object. Since the mouse still can be uncalibrated, we continue to use the QMessageBox and QTimer classes to inform the user about the program's progress.
An improved calibration tool would let the user choose between accepting the new calibration, reverting to the old one, and restarting the calibration.
Calibration Class Definition
The Calibration class inherits from QDialog and is responsible for retrieving the device coordinates from the user.
class Calibration : public QDialog { public: Calibration(); ~Calibration(); int exec(); protected: void paintEvent(QPaintEvent*); void mouseReleaseEvent(QMouseEvent*); void accept(); private: QWSPointerCalibrationData data; int pressCount; };
We reimplement QDialog's exec() and accept() slots, and QWidget's paintEvent() and mouseReleaseEvent() functions.
In addition, we declare a couple of private variables, data and pressCount, holding the Calibration object's number of mouse press events and current calibration data. The pressCount variable is a convenience variable, while the data is a QWSPointerCalibrationData object (storing the physical and logical coordinates) that is passed to the mouse handler. The QWSPointerCalibrationData class is simply a container for calibration data.
Calibration Class Implementation
In the constructor we first ensure that the Calibration dialog fills up the entire screen, has focus and will receive mouse events (the latter by making the dialog modal):
Calibration::Calibration() { QRect desktop = QApplication::desktop()->geometry(); desktop.moveTo(QPoint(0, 0)); setGeometry(desktop); setFocusPolicy(Qt::StrongFocus); setFocus(); setModal(true);
Then we initialize the screenPoints array:
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);
In order to specify the calibration, the screenPoints array must contain the screen coordinates for the logical positions represented by theQWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft). Since non-linearity is expected to increase on the edge of the screen, all points are kept 10 percent within the screen. The qt_screen pointer is a reference to the screen device. There can only be one screen device per application.
pressCount = 0; }
Finally, we initialize the variable which keeps track of the number of mouse press events we have received.
Calibration::~Calibration() { }
The destructor is trivial.
int Calibration::exec() { QWSServer::mouseHandler()->clearCalibration(); grabMouse(); activateWindow(); int ret = QDialog::exec(); releaseMouse(); return ret; }
The reimplementation of the QDialog::exec() slot is called from the main program.
First we clear the current calibration making the following mouse event delivered in raw device coordinates. Then we call the QWidget::grabMouse() function to make sure no mouse events are lost, and the QWidget::activateWindow() function to make the top-level widget containing this dialog, the active window. When the call to the QDialog::exec() base function returns, we call QWidget::releaseMouse() to release the mouse grab before the function returns.
void Calibration::paintEvent(QPaintEvent*) { QPainter p(this); p.fillRect(rect(), Qt::white); QPoint point = data.screenPoints[pressCount]; <span class="comment" style="color:#8b00;font-style:italic">// Map to logical coordinates in case the screen is transformed</span> 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); }
The QWidget::paintEvent() function is reimplemented to receive the widget's paint events. A paint event is a request to repaint all or parts of the widget. It can happen as a result of QWidget::repaint() or QWidget::update(), or because the widget was obscured and has now been uncovered, or for many other reasons. In our reimplementation of the function we simply draw a cross at the next point the user should press.
void Calibration::mouseReleaseEvent(QMouseEvent *event) { <span class="comment" style="color:#8b00;font-style:italic">// Map from device coordinates in case the screen is transformed</span> 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(); }
We then reimplement the QWidget::mouseReleaseEvent() function to receive the widget's move events, using the QMouseEvent object passed as parameter to find the coordinates the user pressed, and update the QWSPointerCalibrationData::devPoints array.
In order to complete the mapping between logical and physical coordinates, the devPoints array must contain the raw device coordinates for the logical positions represented by the QWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft)
We continue by drawing the next cross, or close the dialog by calling the QDialog::accept() slot if we have collected all the required coordinate samples.
void Calibration::accept() { Q_ASSERT(pressCount == 5); QWSServer::mouseHandler()->calibrate(&data); QDialog::accept(); }