Qt 5.4 Linux Touchscreen Input with Tslib on Raspberry Pi failing with LinuxFB QPA Platform Plugin
-
I bought a Tontec 2.4 Inch Touchscreen ( http://elinux.org/MZTX-PI-EXT ) for my Raspberry Pi. The touchscreen controller requires the "tsc2007.ko" and "tsp_raspi.ko" kernel modules as described in the elinux post. The tsc2007.ko module is in the Raspbian Kernel tree but the tsp_raspi.ko can be found here: https://github.com/osandov/raspi/tree/master/tsc2007.
I've cross compiled a new Kernel for the Pi with those modules and they load fine and create a /dev/input/event0 device in Raspbian. If I 'evtest' that device and touch the screen, I get output so I know the events are being delivered in Linux:
pi@raspberry /dev/input $ evtest Available devices: /dev/input/event0: TSC2007 Touchscreen Select the device event number [0-0]: 0 Input driver version is 1.0.1 Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0 Input device name: "TSC2007 Touchscreen" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 330 (BTN_TOUCH) Event type 3 (EV_ABS) Event code 0 (ABS_X) Value 1922 Min 0 Max 4095 Fuzz 64 Event code 1 (ABS_Y) Value 2221 Min 0 Max 4095 Fuzz 64 Event code 24 (ABS_PRESSURE) Value 0 Min 0 Max 4095 Fuzz 64 Properties: Testing ... (interrupt to exit) Event: time 1425521704.199489, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1 Event: time 1425521704.199489, type 3 (EV_ABS), code 1 (ABS_Y), value 2085 Event: time 1425521704.199489, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 538 Event: time 1425521704.199489, -------------- SYN_REPORT ------------ Event: time 1425521704.209174, type 3 (EV_ABS), code 0 (ABS_X), value 1455 ...
I installed tslib and ran a quick ts_calibrate. I also made sure that ts_test spit out data when I touched the screen.
I added the following environment variables to /etc/profile for tslib support in Qt5:
## For Qt5 Touchscreen Support export QT_DEBUG_PLUGINS=1 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/arm-linux-gnueabihf/ export QT_PLUGIN_PATH=/usr/lib/plugins export QT_QPA_FONTDIR=/usr/lib/fonts export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/lib/plugins/platforms export QT_QPA_PLATFORM=linuxfb export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event0 export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0 export TSLIB_TSEVENTTYPE='INPUT' export TSLIB_CALIBFILE='/etc/pointercal' export TSLIB_CONFFILE='/etc/ts.conf' export TSLIB_CONSOLEDEVICE='none' export TSLIB_FBDEVICE='/dev/fb0' export TSLIB_PLUGINDIR='/usr/lib/ts' export TSLIB_TSDEVICE='/dev/input/event0'
I read up on the Qt5 docs and how to get touch events in my app. I have a main Widget and set the appropriate flags in the constructor:
MainWidget::MainWidget(QLabel *parent) : QLabel(parent) { qDebug() << "Setting WA_AcceptTouchEvents on MainWidget..."; // Accept touch events setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_StaticContents); }
I setup an event filter to try to catch the touch events:
bool MainWidget::eventFilter( QObject* target, QEvent* e ) { qDebug() << "Event Type: " << e->type(); return false; return QLabel::eventFilter(target, e); }
I launch my app like this:
myapp -platform linuxfb:fb=/dev/fb0 -plugin tslib:/dev/input/event0
I also uncommented a single printf in Qt's source code for the qtslib.cpp:
void QTsLibMouseHandler::readMouseData() { ts_sample sample; while (get_sample(m_dev, &sample, m_rawMode)) { bool pressed = sample.pressure; int x = sample.x; int y = sample.y; // work around missing coordinates on mouse release if (sample.pressure == 0 && sample.x == 0 && sample.y == 0) { x = m_x; y = m_y; } if (!m_rawMode) { //filtering: ignore movements of 2 pixels or less int dx = x - m_x; int dy = y - m_y; if (dx*dx <= 4 && dy*dy <= 4 && pressed == m_pressed) continue; } QPoint pos(x, y); //printf("handleMouseEvent %d %d %d %ld\n", m_x, m_y, pressed, sample.tv.tv_usec); QWindowSystemInterface::handleMouseEvent(0, pos, pos, pressed ? Qt::LeftButton : Qt::NoButton); m_x = x; m_y = y; m_pressed = pressed; } }
When I launch my Qt app I see the plugins are loading OK ( even shows the correct event0 file ). I also see that the qt tslib plugin is receiving touch events when I touch the screen. The problem is that the event filter is NEVER called!
Here is the app being launched:
Got keys from plugin meta data ("tslib", "tslibraw") QFactoryLoader::QFactoryLoader() checking directory path "/home/pi/generic" ... loaded library "/usr/lib/qt/plugins/generic/libqtslibplugin.so" QTsLibMouseHandler "tslib" "" QTsLibMouseHandler "tslib" "/dev/input/event0" QFactoryLoader::QFactoryLoader() checking directory path "/usr/lib/qt/plugins/styles" ... QFactoryLoader::QFactoryLoader() checking directory path "/home/pi/styles" ... Setting WA_AcceptTouchEvents on MainWidget... ----------------------------------------- Waiting for data now... ----------------------------------------- handleMouseEvent 0 0 1 751196 handleMouseEvent 0 0 1 751196 handleMouseEvent 1696 1615 1 771075 handleMouseEvent 1696 1615 1 771075 handleMouseEvent 1679 1622 1 781368 handleMouseEvent 1671 1638 1 781368 handleMouseEvent 1679 1622 1 781368 handleMouseEvent 1671 1638 1 781368 ...
I found a few forum posts where people are having problems with touch input with the linuxfb platform plugin:
I've tried all their suggestions and still have the problem - no touch events are received by my app even though the Qt tslib plugin says it is receiving them.
It seems that the tslib plugin is having problems injecting the event it receives into my app's event loop with this:
QWindowSystemInterface::handleMouseEvent(0, pos, pos, pressed ? Qt::LeftButton : Qt::NoButton);
I also tried the Qt5.4 touch fingerpaint example and see the same behavior - no touch events are received.
I'm not sure where to go from here. I would greatly appreciate any help solving this issue. Thanks!
UPDATE:
I changed my event filter so it looks like this:
bool MainWidget::eventFilter(QObject *obj, QEvent *event) { qDebug() << "Event received" << obj->metaObject()->className() << event->type(); switch (event->type()) { case QEvent::TouchBegin: qDebug() << "TouchBegin"; case QEvent::TouchUpdate: qDebug() << "TouchUpdate"; case QEvent::TouchEnd: qDebug() << "TouchEnd"; { // QTouchEvent *touch = static_cast<QTouchEvent *>(event); // QList<QTouchEvent::TouchPoint> touchPoints = static_cast<QTouchEvent *>(event)->touchPoints(); // foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) { // switch (touchPoint.state()) { // case Qt::TouchPointStationary: // // don't do anything if this touch point hasn't moved // continue; // default: // { // } // break; // } // } // break; } //default: //return QLabel::event(event); } //return true; }
Now I can see 'socket notifier' events intermingled with Qt Tslib Plugin's prints whenever I touch the screen. Any ideas as to why Event Type 50 but no Touch Events?
Event received QSocketNotifier 50 handleMouseEvent 2702 2618 0 557715 Event received QSocketNotifier 50 handleMouseEvent 2698 2612 1 547758 Event received QSocketNotifier 50 handleMouseEvent 2706 2802 1 759928 Event received QSocketNotifier 50 Event received QSocketNotifier 50
UPDATE #2:
I installed the event filter only to try to catch any events. I'm not sure in Qt5 what translates an event type 50 ( QSocketNotifier ) to a QTouch* or QMouse* event.
Here is some more information:
- When I run evtest, I see that the screen resolution is huge ( ~2500 x
~2500 ) and the actual screen is 320x240. I tried changed the
/dev/fb0 framebuffer size in /boot/config.txt to 320x240 and
rebooted. But the evtest and ts_calibrate steps still show the huge
resolution. - Because of the large resolution, I tried making my main widget
10000x10000 to see if I would get a touch or mouse event - but I
still only get the QSocketNotifier - I then tried to force the tslib plugin to always inject events at
screen position X=50 Y=50, but I still only get the event type 50
QSocketNotifier.
-
Hi phil999,
Have you got any solution for your problem? Your problem is similar to the problem I am having. I posted it at
http://forum.qt.io/topic/51007/touch-screen-does-not-work-for-qt5-3-2-app/13
Please post your solution or progress, which could be big help to me.
Thanks. -
@phil999
I too have struggled with getting the Tslib touchscreen implementation to work. I've spent a lot of time sprinkling print statements around in the Qt code figuring out what is going on. What I've learned is this:-
Tslib and Evdev are separate implementations that are NOT equivalent. The Tslib implementation was developed for single touch (generally resistive) touchscreens while the Evdev implementation was developed for multi-touch (generally capacitive) touchscreens. For single touch screens, every action possible can be characterized as an equivalent mouse operation and that is what Tslib does. (Note that the Tslib plugin calls handleMouseEvent, not handleTouchEvent). Conversely the Evdev implementation does handle multi-touch which has no mouse equivalent so Evdev characterizes the touchscreen events as touch events.
-
You MUST get your touchscreen properly calibrated so that the coordinates are within the screen dimensions. Mouse events will only be reported to an object if they are within the object. Try recalibrating the touchscreen (ts_calibrate) and then run ts_test to be sure the touchscreen operation is correct. (We found that some versions of ts_calibrate don't work correctly and made some changes in the code ourselves.)
-
Event type 50 is a notifier event that I believe is triggering the QTsLibMouseHandler::readMouseData(). You can ignore these.
-
Your event filter should be looking for Mouse events. Probably these will be GraphicsSceneMousePress, GraphicsSceneMouseRelease, GraphicsSceneMouseMove, GrabMouse and UngrabMouse. (But this is object dependent.) I was using the qtbase/examples/touch/knobs application for test and debug and in the Knob::sceneEvent() function in knob.cpp, I changed the case statement to look for those 5 events. On a touch-drag-release I typically see the following sequence:
GrabMouse
GraphicsSceneMousePressA variable number of GraphicsSceneMouseMove
GraphicsSceneMouseRelease
UngrabMouse- Be sure to intercept these events and not call the default QGraphicsItem::sceneEvent() handler. It will inhibit seeing all of the above events except the initial GrabMouse and GraphicsSceneMousePress
Hope this helps!
-