1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qmouseqnx_qws.h"
43 #ifndef QT_NO_QWS_TRANSFORMED
44 #include "qscreen_qws.h"
45 #endif
46
47 #include "qplatformdefs.h"
48 #include "qsocketnotifier.h"
49 #include "private/qcore_unix_p.h"
50
51 #include <sys/dcmd_input.h>
52 #include <errno.h>
53
54 QT_BEGIN_NAMESPACE
55
56 /*!
57 \class QQnxMouseHandler
58 \preliminary
59 \ingroup qws
60 \internal
61 \since 4.6
62
63 \brief The QQnxMouseHandler class implements a mouse driver
64 for the QNX \c{devi-hid} input manager.
65
66 To be able to compile this mouse handler, \l{Qt for Embedded Linux}
67 must be configured with the \c -qt-mouse-qnx option, see the
68 \l{Qt for Embedded Linux Pointer Handling}{Pointer Handling} documentation for details.
69
70 In order to use this mouse handler, the \c{devi-hid} input manager
71 must be set up and run with the resource manager interface (option \c{-r}).
72 Also, Photon must not be running.
73
74 Example invocation from command line: \c{/usr/photon/bin/devi-hid -Pr kbd mouse}
75 Note that after running \c{devi-hid}, you will not be able to use the local
76 shell anymore. It is suggested to run the command in a shell scrip, that launches
77 a Qt application after invocation of \c{devi-hid}.
78
79 To make \l{Qt for Embedded Linux} explicitly choose the qnx mouse
80 handler, set the QWS_MOUSE_PROTO environment variable to \c{qnx}. By default,
81 the first mouse device (\c{/dev/devi/mouse0}) is used. To override, pass a device
82 name as the first and only parameter, for example
83 \c{QWS_MOUSE_PROTO=qnx:/dev/devi/mouse1; export QWS_MOUSE_PROTO}.
84
85 \sa {Qt for Embedded Linux Pointer Handling}{Pointer Handling}, {Qt for Embedded Linux}
86 */
87
88 /*!
89 Constructs a mouse handler for the specified \a device, defaulting to \c{/dev/devi/mouse0}.
90 The \a driver parameter must be \c{"qnx"}.
91
92 Note that you should never instanciate this class, instead let QMouseDriverFactory
93 handle the mouse handlers.
94
95 \sa QMouseDriverFactory
96 */
QQnxMouseHandler(const QString & driver,const QString & device)97 QQnxMouseHandler::QQnxMouseHandler(const QString & driver, const QString &device)
98 : QObject(), QWSMouseHandler(driver, device), mouseButtons(Qt::NoButton)
99 {
100 // open the mouse device with O_NONBLOCK so reading won't block when there's no data
101 mouseFD = QT_OPEN(device.isEmpty() ? "/dev/devi/mouse0" : device.toLatin1().constData(),
102 QT_OPEN_RDONLY | O_NONBLOCK);
103 if (mouseFD == -1) {
104 qErrnoWarning(errno, "QQnxMouseHandler: Unable to open mouse device");
105 } else {
106 struct _pointer_info data;
107 if (devctl(mouseFD, _POINTERGETINFO, &data, sizeof(data), NULL) == EOK)
108 absolutePositioning = (data.flags & _POINTER_FLAG_ABSOLUTE);
109 else
110 absolutePositioning = !device.isEmpty() && device.contains(QLatin1String("touch"));
111
112 // register a socket notifier on the file descriptor so we'll wake up whenever
113 // there's a mouse move waiting for us.
114 mouseNotifier = new QSocketNotifier(mouseFD, QSocketNotifier::Read, this);
115 connect(mouseNotifier, SIGNAL(activated(int)), SLOT(socketActivated()));
116
117 qDebug("QQnxMouseHandler: connected.");
118 }
119 #ifndef QT_NO_QWS_TRANSFORMED
120 transformedMousePos = QPoint(qt_screen->deviceWidth() / 2, qt_screen->deviceHeight() / 2);
121 #endif
122 }
123
124 /*!
125 Destroys this mouse handler and closes the connection to the mouse device.
126 */
~QQnxMouseHandler()127 QQnxMouseHandler::~QQnxMouseHandler()
128 {
129 if (mouseFD != -1)
130 QT_CLOSE(mouseFD);
131 }
132
133 /*! \reimp */
resume()134 void QQnxMouseHandler::resume()
135 {
136 if (mouseNotifier)
137 mouseNotifier->setEnabled(true);
138 }
139
140 /*! \reimp */
suspend()141 void QQnxMouseHandler::suspend()
142 {
143 if (mouseNotifier)
144 mouseNotifier->setEnabled(false);
145 }
146
147 /*! \internal
148
149 This function is called whenever there is activity on the mouse device.
150 By default, it reads up to 10 mouse move packets and calls mouseChanged()
151 for each of them.
152 */
socketActivated()153 void QQnxMouseHandler::socketActivated()
154 {
155 #ifndef QT_NO_QWS_TRANSFORMED
156 QPoint queuedPos = transformedMousePos;
157 #else
158 QPoint queuedPos = mousePos;
159 #endif
160
161 // _mouse_packet is a QNX structure. devi-hid is nice enough to translate
162 // the raw byte data from mouse devices into generic format for us.
163 struct _mouse_packet buffer[32];
164 int n = 0;
165
166 forever {
167 int bytesRead = QT_READ(mouseFD, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n);
168 if (bytesRead == -1) {
169 // EAGAIN means that there are no more mouse events to read
170 if (errno != EAGAIN)
171 qErrnoWarning(errno, "QQnxMouseHandler: Could not read from input device");
172 break;
173 }
174
175 n += bytesRead;
176 if (n % sizeof(buffer[0]) == 0)
177 break;
178 }
179 n /= sizeof(buffer[0]);
180
181 for (int i = 0; i < n; ++i) {
182 const struct _mouse_packet &packet = buffer[i];
183
184 // translate the coordinates from the QNX data structure to the Qt coordinates
185 if (absolutePositioning) {
186 queuedPos = QPoint(packet.dx, packet.dy);
187 } else {
188 // note the swapped y axis
189 queuedPos += QPoint(packet.dx, -packet.dy);
190
191 // QNX only tells us relative mouse movements, not absolute ones, so
192 // limit the cursor position manually to the screen
193 limitToScreen(queuedPos);
194 }
195
196 // translate the QNX mouse button bitmask to Qt buttons
197 int buttons = Qt::NoButton;
198 if (packet.hdr.buttons & _POINTER_BUTTON_LEFT)
199 buttons |= Qt::LeftButton;
200 if (packet.hdr.buttons & _POINTER_BUTTON_MIDDLE)
201 buttons |= Qt::MidButton;
202 if (packet.hdr.buttons & _POINTER_BUTTON_RIGHT)
203 buttons |= Qt::RightButton;
204
205 if (buttons != mouseButtons) {
206 // send the MouseEvent to avoid missing any clicks
207 mouseChanged(queuedPos, buttons, 0);
208 // mousePos updated by the mouseChanged()
209 #ifndef QT_NO_QWS_TRANSFORMED
210 queuedPos = transformedMousePos;
211 #else
212 queuedPos = mousePos;
213 #endif
214 mouseButtons = buttons;
215 }
216 }
217
218 #ifndef QT_NO_QWS_TRANSFORMED
219 if (queuedPos != transformedMousePos) {
220 mouseChanged(queuedPos, mouseButtons, 0);
221 transformedMousePos = queuedPos;
222 }
223 #else
224 if (queuedPos != mousePos)
225 mouseChanged(queuedPos, mouseButtons, 0);
226 #endif
227 }
228
229 QT_END_NAMESPACE
230