10#include "QtCore/qmetaobject.h"
11#include "QtCore/qmath.h"
12#include <QtGui/qpointingdevice.h>
13#include <QtGui/private/qpointingdevice_p.h>
14#include <qpa/qwindowsysteminterface_p.h>
17#include <xcb/xinput.h>
19#if QT_CONFIG(gestures)
20#define QT_XCB_HAS_TOUCHPAD_GESTURES (XCB_INPUT_MINOR_VERSION >= 4
)
23using namespace Qt::StringLiterals;
26#if QT_XCB_HAS_TOUCHPAD_GESTURES
27using qt_xcb_input_pinch_event_t = xcb_input_gesture_pinch_begin_event_t;
28using qt_xcb_input_swipe_event_t = xcb_input_gesture_swipe_begin_event_t;
33struct qt_xcb_input_event_mask_t {
34 xcb_input_event_mask_t header;
35 alignas(4) uint8_t mask[8] = {};
43 mask[bit >> 3] |= 1 << (bit & 7);
46void QXcbConnection::xi2SelectStateEvents()
50 qt_xcb_input_event_mask_t xiEventMask;
51 xiEventMask.header.deviceid = XCB_INPUT_DEVICE_ALL;
52 xiEventMask.header.mask_len = 1;
53 setXcbMask(xiEventMask.mask, XCB_INPUT_HIERARCHY);
54 setXcbMask(xiEventMask.mask, XCB_INPUT_DEVICE_CHANGED);
55 setXcbMask(xiEventMask.mask, XCB_INPUT_PROPERTY);
56 xcb_input_xi_select_events(xcb_connection(), rootWindow(), 1, &xiEventMask.header);
59void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
61 if (window == rootWindow())
64 qt_xcb_input_event_mask_t mask;
66 setXcbMask(mask.mask, XCB_INPUT_BUTTON_PRESS);
67 setXcbMask(mask.mask, XCB_INPUT_BUTTON_RELEASE);
68 setXcbMask(mask.mask, XCB_INPUT_MOTION);
71 setXcbMask(mask.mask, XCB_INPUT_ENTER);
72 setXcbMask(mask.mask, XCB_INPUT_LEAVE);
73 if (isAtLeastXI22()) {
74 setXcbMask(mask.mask, XCB_INPUT_TOUCH_BEGIN);
75 setXcbMask(mask.mask, XCB_INPUT_TOUCH_UPDATE);
76 setXcbMask(mask.mask, XCB_INPUT_TOUCH_END);
78#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
79 if (isAtLeastXI24()) {
80 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
81 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
82 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_END);
83 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
84 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
85 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_END);
89 mask.header.deviceid = XCB_INPUT_DEVICE_ALL;
90 mask.header.mask_len = 2;
91 xcb_void_cookie_t cookie =
92 xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &mask.header);
93 xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
95 qCDebug(lcQpaXInput,
"failed to select events, window %x, error code %d", window, error->error_code);
98 QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(
false);
104 return qreal(val.integral) + qreal(val.frac) / (1ULL << 32);
107#if QT_CONFIG(tabletevent)
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126static const QPointingDevice *tabletToolInstance(QPointingDevice *master,
const QString &tabletName,
127 qint64 id, quint32 usbId, quint32 toolId, qint64 uniqueId,
128 QPointingDevice::PointerType pointerTypeOverride = QPointingDevice::PointerType::Unknown,
129 QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None)
131 QInputDevice::DeviceType devType = QInputDevice::DeviceType::Stylus;
132 QPointingDevice::PointerType pointerType = QPointingDevice::PointerType::Pen;
133 QPointingDevice::Capabilities caps = QInputDevice::Capability::Position |
134 QInputDevice::Capability::Pressure |
135 QInputDevice::Capability::MouseEmulation |
136 QInputDevice::Capability::Hover |
148 devType = QInputDevice::DeviceType::Airbrush;
149 caps.setFlag(QInputDevice::Capability::XTilt);
150 caps.setFlag(QInputDevice::Capability::YTilt);
151 caps.setFlag(QInputDevice::Capability::TangentialPressure);
157 devType = QInputDevice::DeviceType::Airbrush;
158 pointerType = QPointingDevice::PointerType::Eraser;
159 caps.setFlag(QInputDevice::Capability::XTilt);
160 caps.setFlag(QInputDevice::Capability::YTilt);
161 caps.setFlag(QInputDevice::Capability::TangentialPressure);
169 devType = QInputDevice::DeviceType::Mouse;
174 devType = QInputDevice::DeviceType::Mouse;
179 devType = QInputDevice::DeviceType::Puck;
183 caps.setFlag(QInputDevice::Capability::XTilt);
184 caps.setFlag(QInputDevice::Capability::YTilt);
185 caps.setFlag(QInputDevice::Capability::Rotation);
189 pointerType = QPointingDevice::PointerType::Eraser;
190 caps.setFlag(QInputDevice::Capability::XTilt);
191 caps.setFlag(QInputDevice::Capability::YTilt);
192 caps.setFlag(QInputDevice::Capability::Rotation);
196 pointerType = QPointingDevice::PointerType::Unknown;
199 if (pointerTypeOverride != QPointingDevice::PointerType::Unknown)
200 pointerType = pointerTypeOverride;
201 const QPointingDevice *ret = QPointingDevicePrivate::queryTabletDevice(devType, pointerType,
202 QPointingDeviceUniqueId::fromNumericId(uniqueId),
205 ret =
new QPointingDevice(tabletName, id, devType, pointerType, caps, 1, buttonCount,
206 master ? master->seatName() : QString(),
207 QPointingDeviceUniqueId::fromNumericId(uniqueId), master);
208 QWindowSystemInterface::registerInputDevice(ret);
210 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(ret));
211 devPriv->busId = QString::number(usbId, 16);
212 devPriv->toolId = toolId;
214 devPriv->seatName = master->seatName();
218static const char *toolName(QInputDevice::DeviceType tool) {
219 static const QMetaObject *metaObject = qt_getEnumMetaObject(tool);
220 static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool)));
221 return me.valueToKey(
int(tool));
224static const char *pointerTypeName(QPointingDevice::PointerType ptype) {
225 static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype);
226 static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype)));
227 return me.valueToKey(
int(ptype));
231void QXcbConnection::xi2SetupSlavePointerDevice(
void *info, QPointingDevice *master)
233 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
234#if QT_CONFIG(tabletevent)
235 for (
int i = 0; i < m_tabletData.size(); ++i) {
236 if (m_tabletData.at(i).deviceId == deviceInfo->deviceid) {
237 m_tabletData.remove(i);
242 m_touchDevices.remove(deviceInfo->deviceid);
244 const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
245 xcb_input_xi_device_info_name_length(deviceInfo));
246 const QString name = QString::fromUtf8(nameRaw);
247 m_xiSlavePointerIds.append(deviceInfo->deviceid);
248 qCDebug(lcQpaInputDevices) <<
"input device " << name <<
"ID" << deviceInfo->deviceid;
249#if QT_CONFIG(tabletevent)
250 TabletData tabletData;
252 QXcbScrollingDevicePrivate *scrollingDeviceP =
nullptr;
254 auto scrollingDevice = [&]() {
255 if (!scrollingDeviceP)
256 scrollingDeviceP =
new QXcbScrollingDevicePrivate(name, deviceInfo->deviceid,
257 QInputDevice::Capability::Scroll);
258 return scrollingDeviceP;
261 int buttonCount = 32;
262 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
263 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
264 xcb_input_device_class_t *classinfo = classes_it.data;
265 switch (classinfo->type) {
266 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
267 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
268 const int valuatorAtom = qatom(vci->label);
269 qCDebug(lcQpaInputDevices) <<
" has valuator" << atomName(vci->label) <<
"recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
270#if QT_CONFIG(tabletevent)
271 if (valuatorAtom < QXcbAtom::NAtoms) {
272 TabletData::ValuatorClassInfo info;
273 info.minVal = fixed3232ToReal(vci->min);
274 info.maxVal = fixed3232ToReal(vci->max);
275 info.number = vci->number;
276 tabletData.valuatorInfo[valuatorAtom] = info;
279 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
280 scrollingDevice()->lastScrollPosition.setX(fixed3232ToReal(vci->value));
281 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
282 scrollingDevice()->lastScrollPosition.setY(fixed3232ToReal(vci->value));
285 case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
286 auto *sci =
reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
287 if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
288 auto dev = scrollingDevice();
289 dev->orientations.setFlag(Qt::Vertical);
290 dev->verticalIndex = sci->number;
291 dev->verticalIncrement = fixed3232ToReal(sci->increment);
292 }
else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
293 auto dev = scrollingDevice();
294 dev->orientations.setFlag(Qt::Horizontal);
295 dev->horizontalIndex = sci->number;
296 dev->horizontalIncrement = fixed3232ToReal(sci->increment);
300 case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: {
301 auto *bci =
reinterpret_cast<xcb_input_button_class_t *>(classinfo);
302 xcb_atom_t *labels =
nullptr;
303 if (bci->num_buttons >= 5) {
304 labels = xcb_input_button_class_labels(bci);
305 xcb_atom_t label4 = labels[3];
306 xcb_atom_t label5 = labels[4];
309 if ((!label4 || qatom(label4) == QXcbAtom::AtomButtonWheelUp || qatom(label4) == QXcbAtom::AtomButtonWheelDown) &&
310 (!label5 || qatom(label5) == QXcbAtom::AtomButtonWheelUp || qatom(label5) == QXcbAtom::AtomButtonWheelDown))
311 scrollingDevice()->legacyOrientations |= Qt::Vertical;
313 if (bci->num_buttons >= 7) {
314 xcb_atom_t label6 = labels[5];
315 xcb_atom_t label7 = labels[6];
316 if ((!label6 || qatom(label6) == QXcbAtom::AtomButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::AtomButtonHorizWheelRight))
317 scrollingDevice()->legacyOrientations |= Qt::Horizontal;
319 buttonCount = bci->num_buttons;
320 qCDebug(lcQpaInputDevices,
" has %d buttons", bci->num_buttons);
323 case XCB_INPUT_DEVICE_CLASS_TYPE_KEY:
324 qCDebug(lcQpaInputDevices) <<
" it's a keyboard";
326 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
327#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
328 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE:
333 qCDebug(lcQpaInputDevices) <<
" has class" << classinfo->type;
337 bool isTablet =
false;
338#if QT_CONFIG(tabletevent)
340 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsX) &&
341 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsY) &&
342 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsPressure))
346 QByteArray nameLower = nameRaw.toLower();
347 QString dbgType =
"UNKNOWN"_L1;
348 if (nameLower.contains(
"eraser")) {
350 tabletData.pointerType = QPointingDevice::PointerType::Eraser;
351 dbgType =
"eraser"_L1;
352 }
else if (nameLower.contains(
"cursor") && !(nameLower.contains(
"cursor controls") && nameLower.contains(
"trackball"))) {
354 tabletData.pointerType = QPointingDevice::PointerType::Cursor;
355 dbgType =
"cursor"_L1;
356 }
else if (nameLower.contains(
"wacom") && nameLower.contains(
"finger touch")) {
358 }
else if ((nameLower.contains(
"pen") || nameLower.contains(
"stylus")) && isTablet) {
359 tabletData.pointerType = QPointingDevice::PointerType::Pen;
361 }
else if (nameLower.contains(
"wacom") && isTablet && !nameLower.contains(
"touch")) {
363 tabletData.pointerType = QPointingDevice::PointerType::Pen;
365 }
else if (nameLower.contains(
"aiptek") ) {
368 tabletData.pointerType = QPointingDevice::PointerType::Pen;
370 }
else if (nameLower.contains(
"waltop") && nameLower.contains(
"tablet")) {
374 tabletData.pointerType = QPointingDevice::PointerType::Pen;
376 }
else if (nameLower.contains(
"uc-logic") && isTablet) {
377 tabletData.pointerType = QPointingDevice::PointerType::Pen;
379 }
else if (nameLower.contains(
"ugee")) {
381 tabletData.pointerType = QPointingDevice::PointerType::Pen;
388 tabletData.deviceId = deviceInfo->deviceid;
389 tabletData.name = name;
390 m_tabletData.append(tabletData);
391 qCDebug(lcQpaInputDevices) <<
" it's a tablet with pointer type" << dbgType;
392 QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None;
393 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltX))
394 capsOverride.setFlag(QInputDevice::Capability::XTilt);
395 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltY))
396 capsOverride.setFlag(QInputDevice::Capability::YTilt);
398 Q_ASSERT(deviceInfo->deviceid == tabletData.deviceId);
399 const QPointingDevice *dev = tabletToolInstance(master,
400 tabletData.name, deviceInfo->deviceid, 0, 0, tabletData.serialId,
401 tabletData.pointerType, capsOverride);
406 if (scrollingDeviceP) {
408 scrollingDeviceP->legacyOrientations &= ~scrollingDeviceP->orientations;
409 qCDebug(lcQpaInputDevices) <<
" it's a scrolling device";
413 TouchDeviceData *dev = populateTouchDevices(deviceInfo, scrollingDeviceP, &used);
414 if (dev && lcQpaInputDevices().isDebugEnabled()) {
415 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen)
416 qCDebug(lcQpaInputDevices,
" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
417 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
418 dev->qtTouchDevice->maximumPoints());
419 else if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
420 qCDebug(lcQpaInputDevices,
" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
421 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
422 dev->qtTouchDevice->maximumPoints(),
423 dev->size.width(), dev->size.height());
427 if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) {
428 qCDebug(lcQpaInputDevices) <<
" it's a mouse";
429 QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover;
430 if (scrollingDeviceP) {
431 scrollingDeviceP->capabilities |= caps;
432 scrollingDeviceP->buttonCount = buttonCount;
434 scrollingDeviceP->seatName = master->seatName();
435 QWindowSystemInterface::registerInputDevice(
new QXcbScrollingDevice(*scrollingDeviceP, master));
438 QWindowSystemInterface::registerInputDevice(
new QPointingDevice(
439 name, deviceInfo->deviceid,
440 QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
441 caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master));
445 if (!used && scrollingDeviceP) {
446 QXcbScrollingDevice *holder =
new QXcbScrollingDevice(*scrollingDeviceP, master);
447 holder->deleteLater();
452
453
454
455
456
457
458void QXcbConnection::xi2SetupDevices()
460 m_xiMasterPointerIds.clear();
462 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL);
464 qCDebug(lcQpaInputDevices) <<
"failed to query devices";
470 QList<
const QInputDevice *> previousDevices = QInputDevice::devices();
473 auto newOrKeep = [&previousDevices](qint64 systemId) {
475 return !previousDevices.removeIf([systemId](
const QInputDevice *dev) {
476 return dev->systemId() == systemId;
483 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
484 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
485 xcb_input_xi_device_info_t *deviceInfo = it.data;
486 switch (deviceInfo->type) {
487 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD: {
488 if (newOrKeep(deviceInfo->deviceid)) {
489 auto dev =
new QInputDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)),
490 deviceInfo->deviceid, QInputDevice::DeviceType::Keyboard,
491 QString::number(deviceInfo->deviceid << 16 | deviceInfo->attachment, 16),
this);
492 QWindowSystemInterface::registerInputDevice(dev);
495 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER: {
496 m_xiMasterPointerIds.append(deviceInfo->deviceid);
497 if (newOrKeep(deviceInfo->deviceid)) {
498 auto dev =
new QXcbScrollingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
499 QInputDevice::Capability::Position | QInputDevice::Capability::Scroll | QInputDevice::Capability::Hover,
500 32, QString::number(deviceInfo->attachment << 16 | deviceInfo->deviceid, 16),
this);
501 QWindowSystemInterface::registerInputDevice(dev);
510 it = xcb_input_xi_query_device_infos_iterator(reply.get());
511 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
512 xcb_input_xi_device_info_t *deviceInfo = it.data;
513 switch (deviceInfo->type) {
514 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD:
515 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
518 case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
519 if (newOrKeep(deviceInfo->deviceid)) {
520 m_xiSlavePointerIds.append(deviceInfo->deviceid);
521 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
523 xi2SetupSlavePointerDevice(deviceInfo, qobject_cast<QPointingDevice *>(master));
526 case XCB_INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: {
527 if (newOrKeep(deviceInfo->deviceid)) {
528 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
530 QWindowSystemInterface::registerInputDevice(
new QInputDevice(
531 QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
532 QInputDevice::DeviceType::Keyboard, master->seatName(), master));
535 case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
541 qCDebug(lcQpaInputDevices) <<
"removed" << previousDevices;
542 for (
auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
543 const auto id = (*it)->systemId();
544 m_xiSlavePointerIds.removeAll(id);
545 m_touchDevices.remove(id);
547 qDeleteAll(previousDevices);
549 if (m_xiMasterPointerIds.size() > 1)
550 qCDebug(lcQpaInputDevices) <<
"multi-pointer X detected";
553QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(
int id)
555 TouchDeviceData *dev =
nullptr;
556 if (m_touchDevices.contains(id))
557 dev = &m_touchDevices[id];
561QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(
void *info, QXcbScrollingDevicePrivate *scrollingDeviceP,
bool *used)
563 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
564 QPointingDevice::Capabilities caps;
565 QInputDevice::DeviceType type = QInputDevice::DeviceType::Unknown;
566 int maxTouchPoints = 1;
567 bool isTouchDevice =
false;
568 bool hasRelativeCoords =
false;
570 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
571 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
572 xcb_input_device_class_t *classinfo = classes_it.data;
573 switch (classinfo->type) {
574 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: {
575 auto *tci =
reinterpret_cast<xcb_input_touch_class_t *>(classinfo);
576 maxTouchPoints = tci->num_touches;
577 qCDebug(lcQpaInputDevices,
" has touch class with mode %d", tci->mode);
579 case XCB_INPUT_TOUCH_MODE_DEPENDENT:
580 type = QInputDevice::DeviceType::TouchPad;
582 case XCB_INPUT_TOUCH_MODE_DIRECT:
583 type = QInputDevice::DeviceType::TouchScreen;
588#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
589 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE: {
593 auto *gci =
reinterpret_cast<xcb_input_gesture_class_t *>(classinfo);
594 maxTouchPoints = gci->num_touches;
595 qCDebug(lcQpaInputDevices,
" has gesture class");
596 type = QInputDevice::DeviceType::TouchPad;
600 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
601 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
602 const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
603 if (valuatorAtom < QXcbAtom::NAtoms) {
604 TouchDeviceData::ValuatorClassInfo info;
605 info.min = fixed3232ToReal(vci->min);
606 info.max = fixed3232ToReal(vci->max);
607 info.number = vci->number;
608 info.label = valuatorAtom;
609 dev.valuatorInfo.append(info);
613 const int vciResolution = vci->resolution ? vci->resolution : 1;
614 if (valuatorAtom == QXcbAtom::AtomAbsMTPositionX)
615 caps |= QInputDevice::Capability::Position | QInputDevice::Capability::NormalizedPosition;
616 else if (valuatorAtom == QXcbAtom::AtomAbsMTTouchMajor)
617 caps |= QInputDevice::Capability::Area;
618 else if (valuatorAtom == QXcbAtom::AtomAbsMTOrientation)
619 dev.providesTouchOrientation =
true;
620 else if (valuatorAtom == QXcbAtom::AtomAbsMTPressure || valuatorAtom == QXcbAtom::AtomAbsPressure)
621 caps |= QInputDevice::Capability::Pressure;
622 else if (valuatorAtom == QXcbAtom::AtomRelX) {
623 hasRelativeCoords =
true;
624 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
625 }
else if (valuatorAtom == QXcbAtom::AtomRelY) {
626 hasRelativeCoords =
true;
627 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
628 }
else if (valuatorAtom == QXcbAtom::AtomAbsX) {
629 caps |= QInputDevice::Capability::Position;
630 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
631 }
else if (valuatorAtom == QXcbAtom::AtomAbsY) {
632 caps |= QInputDevice::Capability::Position;
633 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
634 }
else if (valuatorAtom == QXcbAtom::AtomRelVertWheel || valuatorAtom == QXcbAtom::AtomRelHorizWheel) {
635 caps |= QInputDevice::Capability::Scroll;
643 if (type == QInputDevice::DeviceType::Unknown && caps && hasRelativeCoords) {
644 type = QInputDevice::DeviceType::TouchPad;
645 if (dev.size.width() < 10 || dev.size.height() < 10 ||
646 dev.size.width() > 10000 || dev.size.height() > 10000)
647 dev.size = QSizeF(130, 110);
649 if (!isAtLeastXI22() || type == QInputDevice::DeviceType::TouchPad)
650 caps |= QInputDevice::Capability::MouseEmulation;
652 if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) {
653 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
655 if (scrollingDeviceP) {
657 scrollingDeviceP->deviceType = type;
658 scrollingDeviceP->pointerType = QPointingDevice::PointerType::Finger;
659 scrollingDeviceP->capabilities |= caps;
660 scrollingDeviceP->maximumTouchPoints = maxTouchPoints;
661 scrollingDeviceP->buttonCount = 3;
662 scrollingDeviceP->seatName = master->seatName();
663 dev.qtTouchDevice =
new QXcbScrollingDevice(*scrollingDeviceP, master);
664 if (Q_UNLIKELY(!caps.testFlag(QInputDevice::Capability::Scroll)))
665 qCDebug(lcQpaInputDevices) <<
"unexpectedly missing RelVert/HorizWheel atoms for touchpad with scroll capability" << dev.qtTouchDevice;
668 dev.qtTouchDevice =
new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo),
669 xcb_input_xi_device_info_name_length(deviceInfo)),
670 deviceInfo->deviceid,
671 type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0,
672 master->seatName(), QPointingDeviceUniqueId(), master);
675 QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice);
676 m_touchDevices[deviceInfo->deviceid] = dev;
677 isTouchDevice =
true;
680 return isTouchDevice ? &m_touchDevices[deviceInfo->deviceid] :
nullptr;
685 return qreal(val) / 0x10000;
688void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
690 auto *xiEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
691 setTime(xiEvent->time);
692 if (m_xiSlavePointerIds.contains(xiEvent->deviceid) && xiEvent->event_type != XCB_INPUT_PROPERTY) {
693 if (!m_duringSystemMoveResize)
695 if (xiEvent->event == XCB_NONE)
698 if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
699 && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
700 abortSystemMoveResize(xiEvent->event);
701 }
else if (xiEvent->event_type == XCB_INPUT_TOUCH_END) {
702 abortSystemMoveResize(xiEvent->event);
708 int sourceDeviceId = xiEvent->deviceid;
709 qt_xcb_input_device_event_t *xiDeviceEvent =
nullptr;
710 xcb_input_enter_event_t *xiEnterEvent =
nullptr;
711 QXcbWindowEventListener *eventListener =
nullptr;
713 switch (xiEvent->event_type) {
714 case XCB_INPUT_BUTTON_PRESS:
715 case XCB_INPUT_BUTTON_RELEASE:
716 case XCB_INPUT_MOTION:
717 case XCB_INPUT_TOUCH_BEGIN:
718 case XCB_INPUT_TOUCH_UPDATE:
719 case XCB_INPUT_TOUCH_END:
721 xiDeviceEvent = xiEvent;
722 eventListener = windowEventListenerFromId(xiDeviceEvent->event);
723 sourceDeviceId = xiDeviceEvent->sourceid;
726#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
727 case XCB_INPUT_GESTURE_PINCH_BEGIN:
728 case XCB_INPUT_GESTURE_PINCH_UPDATE:
729 case XCB_INPUT_GESTURE_PINCH_END:
730 xi2HandleGesturePinchEvent(event);
732 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
733 case XCB_INPUT_GESTURE_SWIPE_UPDATE:
734 case XCB_INPUT_GESTURE_SWIPE_END:
735 xi2HandleGestureSwipeEvent(event);
738 case XCB_INPUT_ENTER:
739 case XCB_INPUT_LEAVE: {
740 xiEnterEvent =
reinterpret_cast<xcb_input_enter_event_t *>(event);
741 eventListener = windowEventListenerFromId(xiEnterEvent->event);
742 sourceDeviceId = xiEnterEvent->sourceid;
745 case XCB_INPUT_HIERARCHY:
746 xi2HandleHierarchyEvent(event);
748 case XCB_INPUT_DEVICE_CHANGED:
749 xi2HandleDeviceChangedEvent(event);
756 if (eventListener->handleNativeEvent(
reinterpret_cast<xcb_generic_event_t *>(event)))
760#if QT_CONFIG(tabletevent)
763 QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
764 if (tablet && xi2HandleTabletEvent(event, tablet))
769 if (
auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
770 xi2HandleScrollEvent(event, device);
772 qCDebug(lcQpaXInputEvents) <<
"scroll event from unregistered device" << sourceDeviceId;
775 switch (xiDeviceEvent->event_type) {
776 case XCB_INPUT_BUTTON_PRESS:
777 case XCB_INPUT_BUTTON_RELEASE:
778 case XCB_INPUT_MOTION:
779 if (eventListener && !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
780 eventListener->handleXIMouseEvent(event);
783 case XCB_INPUT_TOUCH_BEGIN:
784 case XCB_INPUT_TOUCH_UPDATE:
785 case XCB_INPUT_TOUCH_END:
786 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
787 qCDebug(lcQpaXInputEvents,
"XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x",
788 event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
789 fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
790 fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
791 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
792 xi2ProcessTouch(xiDeviceEvent, platformWindow);
794 if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
795 dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
799 }
else if (xiEnterEvent && eventListener) {
800 switch (xiEnterEvent->event_type) {
801 case XCB_INPUT_ENTER:
802 case XCB_INPUT_LEAVE:
803 eventListener->handleXIEnterLeave(event);
809bool QXcbConnection::isTouchScreen(
int id)
811 auto device = touchDeviceForId(id);
812 return device && device->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen;
815void QXcbConnection::xi2ProcessTouch(
void *xiDevEvent, QXcbWindow *platformWindow)
817 auto *xiDeviceEvent =
reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
818 TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
820 qCDebug(lcQpaXInputEvents) <<
"didn't find the dev for given sourceid - " << xiDeviceEvent->sourceid
821 <<
", try to repopulate xi2 devices";
823 dev = touchDeviceForId(xiDeviceEvent->sourceid);
825 qCDebug(lcQpaXInputEvents) <<
"still can't find the dev for it, give up.";
829 const bool firstTouch = dev->touchPoints.isEmpty();
830 if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
831 QWindowSystemInterface::TouchPoint tp;
832 tp.id = xiDeviceEvent->detail % INT_MAX;
833 tp.state = QEventPoint::State::Pressed;
835 dev->touchPoints[tp.id] = tp;
837 QWindowSystemInterface::TouchPoint &touchPoint = dev->touchPoints[xiDeviceEvent->detail];
838 QXcbScreen* screen = platformWindow->xcbScreen();
839 qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
840 qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
841 qreal nx = -1.0, ny = -1.0;
842 qreal w = 0.0, h = 0.0;
843 bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width();
844 for (
const TouchDeviceData::ValuatorClassInfo &vci : std::as_const(dev->valuatorInfo)) {
846 if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value))
848 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
849 qCDebug(lcQpaXInputEvents,
" valuator %20s value %lf from range %lf -> %lf",
850 atomName(atom(vci.label)).constData(), value, vci.min, vci.max);
855 qreal valuatorNormalized = (value - vci.min) / (vci.max - vci.min);
856 if (vci.label == QXcbAtom::AtomRelX) {
857 nx = valuatorNormalized;
858 }
else if (vci.label == QXcbAtom::AtomRelY) {
859 ny = valuatorNormalized;
860 }
else if (vci.label == QXcbAtom::AtomAbsX) {
861 nx = valuatorNormalized;
862 }
else if (vci.label == QXcbAtom::AtomAbsY) {
863 ny = valuatorNormalized;
864 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionX) {
865 nx = valuatorNormalized;
866 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionY) {
867 ny = valuatorNormalized;
868 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMajor) {
869 const qreal sw = screen->geometry().width();
870 const qreal sh = screen->geometry().height();
871 w = valuatorNormalized * qHypot(sw, sh);
872 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMinor) {
873 const qreal sw = screen->geometry().width();
874 const qreal sh = screen->geometry().height();
875 h = valuatorNormalized * qHypot(sw, sh);
876 }
else if (vci.label == QXcbAtom::AtomAbsMTOrientation) {
883 while (value > vci.max)
884 value -= 2 * vci.max;
886 majorAxisIsY = value < vci.max - value;
887 }
else if (vci.label == QXcbAtom::AtomAbsMTPressure || vci.label == QXcbAtom::AtomAbsPressure) {
888 touchPoint.pressure = valuatorNormalized;
894 x = touchPoint.area.center().x();
895 nx = x / screen->geometry().width();
898 y = touchPoint.area.center().y();
899 ny = y / screen->geometry().height();
901 if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) {
902 if (!dev->providesTouchOrientation) {
904 w = touchPoint.area.width();
908 w = qMax(touchPoint.area.width(), touchPoint.area.height());
910 h = qMin(touchPoint.area.width(), touchPoint.area.height());
916 switch (xiDeviceEvent->event_type) {
917 case XCB_INPUT_TOUCH_BEGIN:
919 dev->firstPressedPosition = QPointF(x, y);
920 dev->firstPressedNormalPosition = QPointF(nx, ny);
922 dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y));
927 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
928 XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH,
929 xiDeviceEvent->detail, xiDeviceEvent->event);
932 case XCB_INPUT_TOUCH_UPDATE:
933 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
934 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
935 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
936 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
937 dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
938 x = dev->firstPressedPosition.x() + dx;
939 y = dev->firstPressedPosition.y() + dy;
940 touchPoint.state = QEventPoint::State::Updated;
941 }
else if (touchPoint.area.center() != QPoint(x, y)) {
942 touchPoint.state = QEventPoint::State::Updated;
943 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
944 dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
947 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen &&
948 xiDeviceEvent->event == m_startSystemMoveResizeInfo.window &&
949 xiDeviceEvent->sourceid == m_startSystemMoveResizeInfo.deviceid &&
950 xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
951 QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window);
953 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
954 XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
955 xiDeviceEvent->detail, xiDeviceEvent->event);
956 window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.edges);
957 m_startSystemMoveResizeInfo.window = XCB_NONE;
961 case XCB_INPUT_TOUCH_END:
962 touchPoint.state = QEventPoint::State::Released;
963 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
964 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
965 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
966 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
967 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
968 x = dev->firstPressedPosition.x() + dx;
969 y = dev->firstPressedPosition.y() + dy;
971 dev->pointPressedPosition.remove(touchPoint.id);
973 touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
974 touchPoint.normalPosition = QPointF(nx, ny);
976 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
977 qCDebug(lcQpaXInputEvents) <<
" touchpoint " << touchPoint.id <<
" state " << touchPoint.state <<
" pos norm " << touchPoint.normalPosition <<
978 " area " << touchPoint.area <<
" pressure " << touchPoint.pressure;
979 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
980 QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers);
981 if (touchPoint.state == QEventPoint::State::Released)
983 dev->touchPoints.remove(touchPoint.id);
987 touchPoint.state = QEventPoint::State::Stationary;
990bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window,
int edges)
992 QHash<
int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin();
993 for (; devIt != m_touchDevices.constEnd(); ++devIt) {
994 TouchDeviceData deviceData = devIt.value();
995 if (deviceData.qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen) {
996 auto pointIt = deviceData.touchPoints.constBegin();
997 for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
998 QEventPoint::State state = pointIt.value().state;
999 if (state == QEventPoint::State::Updated || state == QEventPoint::State::Pressed || state == QEventPoint::State::Stationary) {
1000 m_startSystemMoveResizeInfo.window = window;
1001 m_startSystemMoveResizeInfo.deviceid = devIt.key();
1002 m_startSystemMoveResizeInfo.pointid = pointIt.key();
1003 m_startSystemMoveResizeInfo.edges = edges;
1004 setDuringSystemMoveResize(
true);
1005 qCDebug(lcQpaInputDevices) <<
"triggered system move or resize from touch";
1014void QXcbConnection::abortSystemMoveResize(xcb_window_t window)
1016 qCDebug(lcQpaInputDevices) <<
"sending client message NET_WM_MOVERESIZE_CANCEL to window: " << window;
1017 m_startSystemMoveResizeInfo.window = XCB_NONE;
1019 const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
1020 xcb_client_message_event_t xev;
1021 xev.response_type = XCB_CLIENT_MESSAGE;
1022 xev.type = moveResize;
1024 xev.window = window;
1026 xev.data.data32[0] = 0;
1027 xev.data.data32[1] = 0;
1028 xev.data.data32[2] = 11;
1029 xev.data.data32[3] = 0;
1030 xev.data.data32[4] = 0;
1031 xcb_send_event(xcb_connection(),
false, primaryScreen()->root(),
1032 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
1033 (
const char *)&xev);
1035 m_duringSystemMoveResize =
false;
1038bool QXcbConnection::isDuringSystemMoveResize()
const
1040 return m_duringSystemMoveResize;
1043void QXcbConnection::setDuringSystemMoveResize(
bool during)
1045 m_duringSystemMoveResize = during;
1048bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w,
bool grab)
1053 uint8_t mask[8] = {};
1054 setXcbMask(mask, XCB_INPUT_BUTTON_PRESS);
1055 setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE);
1056 setXcbMask(mask, XCB_INPUT_MOTION);
1057 setXcbMask(mask, XCB_INPUT_ENTER);
1058 setXcbMask(mask, XCB_INPUT_LEAVE);
1059 if (isAtLeastXI22()) {
1060 setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN);
1061 setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE);
1062 setXcbMask(mask, XCB_INPUT_TOUCH_END);
1064#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
1065 if (isAtLeastXI24()) {
1066 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
1067 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
1068 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_END);
1069 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
1070 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
1071 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_END);
1075 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1076 xcb_generic_error_t *error =
nullptr;
1077 auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
1078 XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
1079 false, 2,
reinterpret_cast<uint32_t *>(mask));
1080 auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error);
1082 qCDebug(lcQpaXInput,
"failed to grab events for device %d on window %x"
1083 "(error code %d)", id, w, error->error_code);
1093 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1094 auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id);
1095 xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
1097 qCDebug(lcQpaXInput,
"XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code);
1114void QXcbConnection::xi2HandleHierarchyEvent(
void *event)
1116 auto *xiEvent =
reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
1121 if (xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED |
1122 XCB_INPUT_HIERARCHY_MASK_MASTER_REMOVED |
1123 XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED |
1124 XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED))
1128#if QT_XCB_HAS_TOUCHPAD_GESTURES
1129void QXcbConnection::xi2HandleGesturePinchEvent(
void *event)
1131 auto *xiEvent =
reinterpret_cast<qt_xcb_input_pinch_event_t *>(event);
1133 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1134 qCDebug(lcQpaXInputEvents,
"XI2 gesture event type %d seq %d fingers %d pos %6.1f, "
1135 "%6.1f root pos %6.1f, %6.1f delta_angle %6.1f scale %6.1f on window %x",
1136 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1137 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1138 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1139 fixed1616ToReal(xiEvent->delta_angle), fixed1616ToReal(xiEvent->scale),
1142 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1143 if (!platformWindow)
1146 setTime(xiEvent->time);
1148 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1151 uint32_t fingerCount = xiEvent->detail;
1153 switch (xiEvent->event_type) {
1154 case XCB_INPUT_GESTURE_PINCH_BEGIN:
1158 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1159 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1161 m_lastPinchScale = 1.0;
1162 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1164 Qt::BeginNativeGesture,
1165 platformWindow->lastPointerPosition(),
1166 platformWindow->lastPointerGlobalPosition(),
1170 case XCB_INPUT_GESTURE_PINCH_UPDATE: {
1171 qreal rotationDelta = fixed1616ToReal(xiEvent->delta_angle);
1172 qreal scale = fixed1616ToReal(xiEvent->scale);
1173 qreal scaleDelta = scale - m_lastPinchScale;
1174 m_lastPinchScale = scale;
1176 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1177 fixed1616ToReal(xiEvent->delta_y));
1179 if (!delta.isNull()) {
1180 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1181 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1182 Qt::PanNativeGesture, 0, delta,
1183 platformWindow->lastPointerPosition(),
1184 platformWindow->lastPointerGlobalPosition(),
1187 if (rotationDelta != 0) {
1188 QWindowSystemInterface::handleGestureEventWithRealValue(
1189 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1190 Qt::RotateNativeGesture,
1192 platformWindow->lastPointerPosition(),
1193 platformWindow->lastPointerGlobalPosition(),
1196 if (scaleDelta != 0) {
1197 QWindowSystemInterface::handleGestureEventWithRealValue(
1198 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1199 Qt::ZoomNativeGesture,
1201 platformWindow->lastPointerPosition(),
1202 platformWindow->lastPointerGlobalPosition(),
1207 case XCB_INPUT_GESTURE_PINCH_END:
1208 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1210 Qt::EndNativeGesture,
1211 platformWindow->lastPointerPosition(),
1212 platformWindow->lastPointerGlobalPosition(),
1218void QXcbConnection::xi2HandleGestureSwipeEvent(
void *event)
1220 auto *xiEvent =
reinterpret_cast<qt_xcb_input_swipe_event_t *>(event);
1222 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1223 qCDebug(lcQpaXInputEvents,
"XI2 gesture event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x",
1224 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1225 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1226 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1229 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1230 if (!platformWindow)
1233 setTime(xiEvent->time);
1235 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1238 uint32_t fingerCount = xiEvent->detail;
1240 switch (xiEvent->event_type) {
1241 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
1245 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1246 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1248 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1250 Qt::BeginNativeGesture,
1251 platformWindow->lastPointerPosition(),
1252 platformWindow->lastPointerGlobalPosition(),
1255 case XCB_INPUT_GESTURE_SWIPE_UPDATE: {
1256 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1257 fixed1616ToReal(xiEvent->delta_y));
1259 if (xiEvent->delta_x != 0 || xiEvent->delta_y != 0) {
1260 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1261 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1262 Qt::PanNativeGesture, 0, delta,
1263 platformWindow->lastPointerPosition(),
1264 platformWindow->lastPointerGlobalPosition(),
1269 case XCB_INPUT_GESTURE_SWIPE_END:
1270 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1272 Qt::EndNativeGesture,
1273 platformWindow->lastPointerPosition(),
1274 platformWindow->lastPointerGlobalPosition(),
1281void QXcbConnection::xi2HandleGesturePinchEvent(
void*) {}
1282void QXcbConnection::xi2HandleGestureSwipeEvent(
void*) {}
1285void QXcbConnection::xi2HandleDeviceChangedEvent(
void *event)
1287 auto *xiEvent =
reinterpret_cast<xcb_input_device_changed_event_t *>(event);
1288 switch (xiEvent->reason) {
1289 case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
1291 if (m_xiMasterPointerIds.contains(xiEvent->deviceid) || m_xiSlavePointerIds.contains(xiEvent->deviceid))
1293 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid);
1294 if (!reply || reply->num_infos <= 0)
1296 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
1297 xi2SetupSlavePointerDevice(it.data);
1300 case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
1301 if (
auto *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
1302 xi2UpdateScrollingDevice(scrollingDevice);
1306 qCDebug(lcQpaXInputEvents,
"unknown device-changed-event (device %d)", xiEvent->sourceid);
1311void QXcbConnection::xi2UpdateScrollingDevice(QInputDevice *dev)
1313 QXcbScrollingDevice *scrollDev = qobject_cast<QXcbScrollingDevice *>(dev);
1314 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1316 QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1318 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice->systemId);
1319 if (!reply || reply->num_infos <= 0) {
1320 qCDebug(lcQpaInputDevices,
"scrolling device %lld no longer present", scrollingDevice->systemId);
1323 QPointF lastScrollPosition;
1324 if (lcQpaXInputEvents().isDebugEnabled())
1325 lastScrollPosition = scrollingDevice->lastScrollPosition;
1327 xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data;
1328 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
1329 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
1330 xcb_input_device_class_t *classInfo = classes_it.data;
1331 if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) {
1332 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
1333 const int valuatorAtom = qatom(vci->label);
1334 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
1335 scrollingDevice->lastScrollPosition.setX(fixed3232ToReal(vci->value));
1336 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
1337 scrollingDevice->lastScrollPosition.setY(fixed3232ToReal(vci->value));
1340 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice->lastScrollPosition))
1341 qCDebug(lcQpaXInputEvents,
"scrolling device %lld moved from (%f, %f) to (%f, %f)", scrollingDevice->systemId,
1342 lastScrollPosition.x(), lastScrollPosition.y(),
1343 scrollingDevice->lastScrollPosition.x(),
1344 scrollingDevice->lastScrollPosition.y());
1347void QXcbConnection::xi2UpdateScrollingDevices()
1349 const auto &devices = QInputDevice::devices();
1350 for (
const QInputDevice *dev : devices) {
1351 if (dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1352 xi2UpdateScrollingDevice(
const_cast<QInputDevice *>(dev));
1356QXcbScrollingDevice *QXcbConnection::scrollingDeviceForId(
int id)
1358 const QPointingDevice *dev = QPointingDevicePrivate::pointingDeviceById(id);
1359 if (!dev|| !dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1361 return qobject_cast<QXcbScrollingDevice *>(
const_cast<QPointingDevice *>(dev));
1364void QXcbConnection::xi2HandleScrollEvent(
void *event,
const QPointingDevice *dev)
1366 auto *xiDeviceEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
1368 const QXcbScrollingDevice *scrollDev = qobject_cast<
const QXcbScrollingDevice *>(dev);
1369 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1371 const QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1373 if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice->orientations) {
1374 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1378 if (scrollingDevice->orientations & Qt::Vertical) {
1379 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->verticalIndex, &value)) {
1380 double delta = scrollingDevice->lastScrollPosition.y() - value;
1381 scrollingDevice->lastScrollPosition.setY(value);
1382 angleDelta.setY((delta / scrollingDevice->verticalIncrement) * 120);
1386 if (scrollingDevice->verticalIncrement > 15)
1387 rawDelta.setY(delta);
1388 else if (scrollingDevice->verticalIncrement < -15)
1389 rawDelta.setY(-delta);
1392 if (scrollingDevice->orientations & Qt::Horizontal) {
1393 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->horizontalIndex, &value)) {
1394 double delta = scrollingDevice->lastScrollPosition.x() - value;
1395 scrollingDevice->lastScrollPosition.setX(value);
1396 angleDelta.setX((delta / scrollingDevice->horizontalIncrement) * 120);
1398 if (scrollingDevice->horizontalIncrement > 15)
1399 rawDelta.setX(delta);
1400 else if (scrollingDevice->horizontalIncrement < -15)
1401 rawDelta.setX(-delta);
1404 if (!angleDelta.isNull()) {
1405 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1406 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1407 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1408 if (modifiers & Qt::AltModifier) {
1409 angleDelta = angleDelta.transposed();
1410 rawDelta = rawDelta.transposed();
1412 qCDebug(lcQpaXInputEvents) <<
"scroll wheel from device" << scrollingDevice->systemId
1413 <<
"@ window pos" << local <<
"delta px" << rawDelta <<
"angle" << angleDelta;
1414 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1415 local, global, rawDelta, angleDelta, modifiers);
1418 }
else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice->legacyOrientations) {
1419 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1421 if (scrollingDevice->legacyOrientations & Qt::Vertical) {
1422 if (xiDeviceEvent->detail == 4)
1423 angleDelta.setY(120);
1424 else if (xiDeviceEvent->detail == 5)
1425 angleDelta.setY(-120);
1427 if (scrollingDevice->legacyOrientations & Qt::Horizontal) {
1428 if (xiDeviceEvent->detail == 6)
1429 angleDelta.setX(120);
1430 else if (xiDeviceEvent->detail == 7)
1431 angleDelta.setX(-120);
1433 if (!angleDelta.isNull()) {
1434 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1435 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1436 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1437 if (modifiers & Qt::AltModifier)
1438 angleDelta = angleDelta.transposed();
1439 qCDebug(lcQpaXInputEvents) <<
"scroll wheel (button" << xiDeviceEvent->detail <<
") @ window pos" << local <<
"delta angle" << angleDelta;
1440 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1441 local, global, QPoint(), angleDelta, modifiers);
1450 for (
int i = 0; i < maskLen; i++) {
1452 if ((maskPtr[i] & (1 << number)) == 0)
1455 for (
int j = 0; j < 8; j++) {
1458 if (maskPtr[i] & (1 << j))
1466bool QXcbConnection::xi2GetValuatorValueIfSet(
const void *event,
int valuatorNum,
double *value)
1468 auto *xideviceevent =
static_cast<
const qt_xcb_input_device_event_t *>(event);
1469 auto *buttonsMaskAddr =
reinterpret_cast<
const unsigned char *>(&xideviceevent[1]);
1470 auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
1471 auto *valuatorsValuesAddr =
reinterpret_cast<
const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
1473 int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
1474 if (valuatorOffset < 0)
1477 *value = valuatorsValuesAddr[valuatorOffset].integral;
1478 *value += ((
double)valuatorsValuesAddr[valuatorOffset].frac / (1 << 16) / (1 << 16));
1482Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
1485 case 1:
return Qt::LeftButton;
1486 case 2:
return Qt::MiddleButton;
1487 case 3:
return Qt::RightButton;
1491 if (b >= 8 && b <= Qt::MaxMouseButton)
1492 return static_cast<Qt::MouseButton>(Qt::BackButton << (b - 8));
1493 return Qt::NoButton;
1496#if QT_CONFIG(tabletevent)
1497bool QXcbConnection::xi2HandleTabletEvent(
const void *event, TabletData *tabletData)
1499 bool handled =
true;
1500 const auto *xiDeviceEvent =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1502 switch (xiDeviceEvent->event_type) {
1503 case XCB_INPUT_BUTTON_PRESS: {
1504 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1505 tabletData->buttons |= b;
1506 xi2ReportTabletEvent(event, tabletData);
1509 case XCB_INPUT_BUTTON_RELEASE: {
1510 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1511 tabletData->buttons ^= b;
1512 xi2ReportTabletEvent(event, tabletData);
1515 case XCB_INPUT_MOTION:
1516 xi2ReportTabletEvent(event, tabletData);
1518 case XCB_INPUT_PROPERTY: {
1521 const auto *ev =
reinterpret_cast<
const xcb_input_property_event_t *>(event);
1522 if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) {
1523 if (ev->property == atom(QXcbAtom::AtomWacomSerialIDs)) {
1524 enum WacomSerialIndex {
1526 _WACSER_LAST_TOOL_SERIAL,
1527 _WACSER_LAST_TOOL_ID,
1528 _WACSER_TOOL_SERIAL,
1533 auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, xcb_connection(), tabletData->deviceId, 0,
1534 ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
1536 if (reply->type == atom(QXcbAtom::AtomINTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
1537 quint32 *ptr =
reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get()));
1538 quint32 tool = ptr[_WACSER_TOOL_ID];
1541 if (!tool && ptr[_WACSER_TOOL_SERIAL])
1542 tool = ptr[_WACSER_TOOL_SERIAL];
1544 QWindow *win =
nullptr;
1547 const QPointingDevice *dev = tabletToolInstance(
nullptr, tabletData->name,
1548 tabletData->deviceId, ptr[_WACSER_USB_ID], tool,
1549 qint64(ptr[_WACSER_TOOL_SERIAL]));
1550 tabletData->inProximity =
true;
1551 tabletData->tool = dev->type();
1552 tabletData->serialId = qint64(ptr[_WACSER_TOOL_SERIAL]);
1553 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
true);
1555 tool = ptr[_WACSER_LAST_TOOL_ID];
1559 tool = ptr[_WACSER_LAST_TOOL_SERIAL];
1560 auto *dev = qobject_cast<
const QPointingDevice *>(QInputDevicePrivate::fromId(tabletData->deviceId));
1562 tabletData->tool = dev->type();
1563 tabletData->inProximity =
false;
1564 tabletData->serialId = qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
1565 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
false);
1569 qCDebug(lcQpaInputDevices,
"XI2 proximity change on tablet %d %s (USB %x): last tool: %x id %x current tool: %x id %x %s",
1570 tabletData->deviceId, qPrintable(tabletData->name), ptr[_WACSER_USB_ID],
1571 ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
1572 ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
1587static inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize)
1589 return screenMin + normValue * screenSize;
1593void QXcbConnection::xi2ReportTabletEvent(
const void *event, TabletData *tabletData)
1595 auto *ev =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1596 QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
1599 QWindow *window = xcbWindow->window();
1600 const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective);
1601 QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y));
1602 QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y));
1603 double pressure = 0, rotation = 0, tangentialPressure = 0;
1604 qreal xTilt = 0, yTilt = 0;
1605 static const bool useValuators = !qEnvironmentVariableIsSet(
"QT_XCB_TABLET_LEGACY_COORDINATES");
1606 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(tabletData->tool),
1607 QPointingDevice::PointerType(tabletData->pointerType),
1608 QPointingDeviceUniqueId::fromNumericId(tabletData->serialId));
1613 QRect physicalScreenArea;
1614 if (Q_LIKELY(useValuators)) {
1615 const QList<QPlatformScreen *> siblings = window->screen()->handle()->virtualSiblings();
1616 for (
const QPlatformScreen *screen : siblings)
1617 physicalScreenArea |= screen->geometry();
1620 for (QHash<
int, TabletData::ValuatorClassInfo>::iterator it = tabletData->valuatorInfo.begin(),
1621 ite = tabletData->valuatorInfo.end(); it != ite; ++it) {
1622 int valuator = it.key();
1623 TabletData::ValuatorClassInfo &classInfo(it.value());
1624 xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
1625 double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal);
1627 case QXcbAtom::AtomAbsX:
1628 if (Q_LIKELY(useValuators)) {
1629 const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width());
1631 local.setX(xcbWindow->mapFromGlobalF(global).x());
1634 case QXcbAtom::AtomAbsY:
1635 if (Q_LIKELY(useValuators)) {
1636 qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height());
1638 local.setY(xcbWindow->mapFromGlobalF(global).y());
1641 case QXcbAtom::AtomAbsPressure:
1642 pressure = normalizedValue;
1644 case QXcbAtom::AtomAbsTiltX:
1645 xTilt = classInfo.curVal;
1647 case QXcbAtom::AtomAbsTiltY:
1648 yTilt = classInfo.curVal;
1650 case QXcbAtom::AtomAbsWheel:
1651 switch (tabletData->tool) {
1652 case QInputDevice::DeviceType::Airbrush:
1653 tangentialPressure = normalizedValue * 2.0 - 1.0;
1655 case QInputDevice::DeviceType::Stylus:
1656 if (dev->capabilities().testFlag(QInputDevice::Capability::Rotation))
1657 rotation = normalizedValue * 360.0 - 180.0;
1668 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
1669 qCDebug(lcQpaXInputEvents,
"XI2 event on tablet %d with tool %s %llx type %s seq %d detail %d time %d "
1670 "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %4.2lf, %4.2lf rotation %6.2lf modifiers 0x%x",
1671 tabletData->deviceId, toolName(tabletData->tool), tabletData->serialId, pointerTypeName(tabletData->pointerType),
1672 ev->sequence, ev->detail, ev->time,
1673 local.x(), local.y(), global.x(), global.y(),
1674 (
int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (
int)modifiers);
1676 QWindowSystemInterface::handleTabletEvent(window, ev->time, dev, local, global,
1677 tabletData->buttons, pressure,
1678 xTilt, yTilt, tangentialPressure,
1679 rotation, 0, modifiers);
1682QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(
int id)
1684 for (
int i = 0; i < m_tabletData.size(); ++i) {
1685 if (m_tabletData.at(i).deviceId == id)
1686 return &m_tabletData[i];
#define Q_XCB_REPLY(call,...)
static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number)
static void setXcbMask(uint8_t *mask, int bit)
static qreal fixed1616ToReal(xcb_input_fp1616_t val)
xcb_input_button_press_event_t qt_xcb_input_device_event_t
static qreal fixed3232ToReal(xcb_input_fp3232_t val)