Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qevdevtablethandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QStringList>
7#include <QSocketNotifier>
8#include <QGuiApplication>
9#include <QPointingDevice>
10#include <QLoggingCategory>
11#include <QtCore/private/qcore_unix_p.h>
12#include <qpa/qwindowsysteminterface.h>
13#ifdef Q_OS_FREEBSD
14#include <dev/evdev/input.h>
15#else
16#include <linux/input.h>
17#endif
18
20
21using namespace Qt::StringLiterals;
22
23Q_LOGGING_CATEGORY(qLcEvdevTablet, "qt.qpa.input")
24
26{
27public:
29
30 void processInputEvent(input_event *ev);
31 void report();
32
36 struct {
37 int x, y, p, d;
38 } minValues, maxValues;
39 struct {
40 int x, y, p, d;
41 bool down, lastReportDown;
42 int tool, lastReportTool;
45};
46
48 : q(q_ptr), lastEventType(0)
49{
50 memset(&minValues, 0, sizeof(minValues));
51 memset(&maxValues, 0, sizeof(maxValues));
52 memset(static_cast<void *>(&state), 0, sizeof(state));
53}
54
56{
57 if (ev->type == EV_ABS) {
58 switch (ev->code) {
59 case ABS_X:
60 state.x = ev->value;
61 break;
62 case ABS_Y:
63 state.y = ev->value;
64 break;
65 case ABS_PRESSURE:
66 state.p = ev->value;
67 break;
68 case ABS_DISTANCE:
69 state.d = ev->value;
70 break;
71 default:
72 break;
73 }
74 } else if (ev->type == EV_KEY) {
75 // code BTN_TOOL_* value 1 -> proximity enter
76 // code BTN_TOOL_* value 0 -> proximity leave
77 // code BTN_TOUCH value 1 -> contact with screen
78 // code BTN_TOUCH value 0 -> no contact
79 switch (ev->code) {
80 case BTN_TOUCH:
81 state.down = ev->value != 0;
82 break;
83 case BTN_TOOL_PEN:
84 state.tool = ev->value ? int(QPointingDevice::PointerType::Pen) : 0;
85 break;
86 case BTN_TOOL_RUBBER:
87 state.tool = ev->value ? int(QPointingDevice::PointerType::Eraser) : 0;
88 break;
89 default:
90 break;
91 }
92 } else if (ev->type == EV_SYN && ev->code == SYN_REPORT && lastEventType != ev->type) {
93 report();
94 }
95 lastEventType = ev->type;
96}
97
99{
100 if (!state.lastReportTool && state.tool)
102
103 qreal nx = (state.x - minValues.x) / qreal(maxValues.x - minValues.x);
104 qreal ny = (state.y - minValues.y) / qreal(maxValues.y - minValues.y);
105
107 QPointF globalPos(nx * winRect.width(), ny * winRect.height());
108 int pointer = state.tool;
109 // Prevent sending confusing values of 0 when moving the pen outside the active area.
110 if (!state.down && state.lastReportDown) {
111 globalPos = state.lastReportPos;
112 pointer = state.lastReportTool;
113 }
114
115 int pressureRange = maxValues.p - minValues.p;
116 qreal pressure = pressureRange ? (state.p - minValues.p) / qreal(pressureRange) : qreal(1);
117
118 if (state.down || state.lastReportDown) {
122 pressure, 0, 0, 0, 0, 0, q->deviceId(),
123 qGuiApp->keyboardModifiers());
124 }
125
126 if (state.lastReportTool && !state.tool)
128
129 state.lastReportDown = state.down;
130 state.lastReportTool = state.tool;
131 state.lastReportPos = globalPos;
132}
133
134
136 : QObject(parent), m_fd(-1), m_device(device), m_notifier(0), d(0)
137{
138 Q_UNUSED(spec);
139
140 setObjectName("Evdev Tablet Handler"_L1);
141
142 qCDebug(qLcEvdevTablet, "evdevtablet: using %ls", qUtf16Printable(device));
143
144 m_fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);
145 if (m_fd < 0) {
146 qErrnoWarning("evdevtablet: Cannot open input device %ls", qUtf16Printable(device));
147 return;
148 }
149
150 bool grabSuccess = !ioctl(m_fd, EVIOCGRAB, (void *) 1);
151 if (grabSuccess)
152 ioctl(m_fd, EVIOCGRAB, (void *) 0);
153 else
154 qWarning("evdevtablet: %ls: The device is grabbed by another process. No events will be read.", qUtf16Printable(device));
155
156 d = new QEvdevTabletData(this);
157 if (!queryLimits())
158 qWarning("evdevtablet: %ls: Unset or invalid ABS limits. Behavior will be unspecified.", qUtf16Printable(device));
159
160 m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
162}
163
165{
166 if (m_fd >= 0)
167 QT_CLOSE(m_fd);
168
169 delete d;
170}
171
173{
174 return m_fd;
175}
176
177bool QEvdevTabletHandler::queryLimits()
178{
179 bool ok = true;
180 input_absinfo absInfo;
181 memset(&absInfo, 0, sizeof(input_absinfo));
182 ok &= ioctl(m_fd, EVIOCGABS(ABS_X), &absInfo) >= 0;
183 if (ok) {
184 d->minValues.x = absInfo.minimum;
185 d->maxValues.x = absInfo.maximum;
186 qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min X: %d max X: %d", qUtf16Printable(m_device),
187 d->minValues.x, d->maxValues.x);
188 }
189 ok &= ioctl(m_fd, EVIOCGABS(ABS_Y), &absInfo) >= 0;
190 if (ok) {
191 d->minValues.y = absInfo.minimum;
192 d->maxValues.y = absInfo.maximum;
193 qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min Y: %d max Y: %d", qUtf16Printable(m_device),
194 d->minValues.y, d->maxValues.y);
195 }
196 if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) {
197 d->minValues.p = absInfo.minimum;
198 d->maxValues.p = absInfo.maximum;
199 qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min pressure: %d max pressure: %d", qUtf16Printable(m_device),
200 d->minValues.p, d->maxValues.p);
201 }
202 if (ioctl(m_fd, EVIOCGABS(ABS_DISTANCE), &absInfo) >= 0) {
203 d->minValues.d = absInfo.minimum;
204 d->maxValues.d = absInfo.maximum;
205 qCDebug(qLcEvdevTablet, "evdevtablet: %ls: min distance: %d max distance: %d", qUtf16Printable(m_device),
206 d->minValues.d, d->maxValues.d);
207 }
208 char name[128];
209 if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) {
211 qCDebug(qLcEvdevTablet, "evdevtablet: %ls: device name: %s", qUtf16Printable(m_device), name);
212 }
213 return ok;
214}
215
217{
218 input_event buffer[32];
219 int n = 0;
220 for (; ;) {
221 int result = QT_READ(m_fd, reinterpret_cast<char*>(buffer) + n, sizeof(buffer) - n);
222 if (!result) {
223 qWarning("evdevtablet: %ls: Got EOF from input device", qUtf16Printable(m_device));
224 return;
225 } else if (result < 0) {
226 if (errno != EINTR && errno != EAGAIN) {
227 qErrnoWarning("evdevtablet: %ls: Could not read from input device", qUtf16Printable(m_device));
228 if (errno == ENODEV) { // device got disconnected -> stop reading
229 delete m_notifier;
230 m_notifier = 0;
231 QT_CLOSE(m_fd);
232 m_fd = -1;
233 }
234 return;
235 }
236 } else {
237 n += result;
238 if (n % sizeof(input_event) == 0)
239 break;
240 }
241 }
242
243 n /= sizeof(input_event);
244
245 for (int i = 0; i < n; ++i)
247}
248
249
251 : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(0)
252{
253 start();
254}
255
261
263{
264 m_handler = new QEvdevTabletHandler(m_device, m_spec);
265 exec();
266 delete m_handler;
267 m_handler = 0;
268}
269
270
IOBluetoothDevice * device
struct QEvdevTabletData::@417 state
void processInputEvent(input_event *ev)
struct QEvdevTabletData::@416 minValues
struct QEvdevTabletData::@416 maxValues
QEvdevTabletHandler * q
QEvdevTabletData(QEvdevTabletHandler *q_ptr)
QEvdevTabletHandlerThread(const QString &device, const QString &spec, QObject *parent=nullptr)
QEvdevTabletHandler(const QString &device, const QString &spec=QString(), QObject *parent=nullptr)
QScreen * primaryScreen
the primary (or default) screen of the application.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qrect.h:30
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
\inmodule QtCore
void activated(QSocketDescriptor socket, QSocketNotifier::Type activationEvent, QPrivateSignal)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static bool handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, const QPointF &local, const QPointF &global, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
static bool handleTabletLeaveProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
static bool handleTabletEnterProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
else opt state
[0]
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
@ LeftButton
Definition qnamespace.h:58
@ NoButton
Definition qnamespace.h:57
#define QT_READ
#define QT_OPEN
#define QT_CLOSE
#define qGuiApp
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint buffer
GLuint start
GLuint name
GLfloat n
GLint y
GLbyte nx
GLfixed ny
GLsizei const void * pointer
Definition qopenglext.h:384
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define qUtf16Printable(string)
Definition qstring.h:1543
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
dialog exec()