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;
33 alignas(4) uint8_t
mask[8] = {};
39 mask[bit >> 3] |= 1 << (bit & 7);
42void QXcbConnection::xi2SelectStateEvents()
46 qt_xcb_input_event_mask_t xiEventMask;
47 xiEventMask.header.deviceid = XCB_INPUT_DEVICE_ALL;
48 xiEventMask.header.mask_len = 1;
49 setXcbMask(xiEventMask.mask, XCB_INPUT_HIERARCHY);
50 setXcbMask(xiEventMask.mask, XCB_INPUT_DEVICE_CHANGED);
51 setXcbMask(xiEventMask.mask, XCB_INPUT_PROPERTY);
52 xcb_input_xi_select_events(xcb_connection(), rootWindow(), 1, &xiEventMask.header);
55void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
57 if (window == rootWindow())
60 qt_xcb_input_event_mask_t mask;
62 setXcbMask(mask.mask, XCB_INPUT_BUTTON_PRESS);
63 setXcbMask(mask.mask, XCB_INPUT_BUTTON_RELEASE);
64 setXcbMask(mask.mask, XCB_INPUT_MOTION);
67 setXcbMask(mask.mask, XCB_INPUT_ENTER);
68 setXcbMask(mask.mask, XCB_INPUT_LEAVE);
69 if (isAtLeastXI22()) {
70 setXcbMask(mask.mask, XCB_INPUT_TOUCH_BEGIN);
71 setXcbMask(mask.mask, XCB_INPUT_TOUCH_UPDATE);
72 setXcbMask(mask.mask, XCB_INPUT_TOUCH_END);
74#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
75 if (isAtLeastXI24()) {
76 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
77 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
78 setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_END);
79 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
80 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
81 setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_END);
85 mask.header.deviceid = XCB_INPUT_DEVICE_ALL;
86 mask.header.mask_len = 2;
87 xcb_void_cookie_t cookie =
88 xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &mask.header);
89 xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
91 qCDebug(lcQpaXInput,
"failed to select events, window %x, error code %d", window, error->error_code);
94 QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(
false);
100 return qreal(val.integral) + qreal(val.frac) / (1ULL << 32);
103#if QT_CONFIG(tabletevent)
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122static const QPointingDevice *tabletToolInstance(QPointingDevice *master,
const QString &tabletName,
123 qint64 id, quint32 usbId, quint32 toolId, qint64 uniqueId,
124 QPointingDevice::PointerType pointerTypeOverride = QPointingDevice::PointerType::Unknown,
125 QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None)
127 QInputDevice::DeviceType devType = QInputDevice::DeviceType::Stylus;
128 QPointingDevice::PointerType pointerType = QPointingDevice::PointerType::Pen;
129 QPointingDevice::Capabilities caps = QInputDevice::Capability::Position |
130 QInputDevice::Capability::Pressure |
131 QInputDevice::Capability::MouseEmulation |
132 QInputDevice::Capability::Hover |
144 devType = QInputDevice::DeviceType::Airbrush;
145 caps.setFlag(QInputDevice::Capability::XTilt);
146 caps.setFlag(QInputDevice::Capability::YTilt);
147 caps.setFlag(QInputDevice::Capability::TangentialPressure);
153 devType = QInputDevice::DeviceType::Airbrush;
154 pointerType = QPointingDevice::PointerType::Eraser;
155 caps.setFlag(QInputDevice::Capability::XTilt);
156 caps.setFlag(QInputDevice::Capability::YTilt);
157 caps.setFlag(QInputDevice::Capability::TangentialPressure);
165 devType = QInputDevice::DeviceType::Mouse;
170 devType = QInputDevice::DeviceType::Mouse;
175 devType = QInputDevice::DeviceType::Puck;
179 caps.setFlag(QInputDevice::Capability::XTilt);
180 caps.setFlag(QInputDevice::Capability::YTilt);
181 caps.setFlag(QInputDevice::Capability::Rotation);
185 pointerType = QPointingDevice::PointerType::Eraser;
186 caps.setFlag(QInputDevice::Capability::XTilt);
187 caps.setFlag(QInputDevice::Capability::YTilt);
188 caps.setFlag(QInputDevice::Capability::Rotation);
192 pointerType = QPointingDevice::PointerType::Unknown;
195 if (pointerTypeOverride != QPointingDevice::PointerType::Unknown)
196 pointerType = pointerTypeOverride;
197 const QPointingDevice *ret = QPointingDevicePrivate::queryTabletDevice(devType, pointerType,
198 QPointingDeviceUniqueId::fromNumericId(uniqueId),
201 ret =
new QPointingDevice(tabletName, id, devType, pointerType, caps, 1, buttonCount,
202 master ? master->seatName() : QString(),
203 QPointingDeviceUniqueId::fromNumericId(uniqueId), master);
204 QWindowSystemInterface::registerInputDevice(ret);
206 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(ret));
207 devPriv->busId = QString::number(usbId, 16);
208 devPriv->toolId = toolId;
210 devPriv->seatName = master->seatName();
214static const char *toolName(QInputDevice::DeviceType tool) {
215 static const QMetaObject *metaObject = qt_getEnumMetaObject(tool);
216 static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool)));
217 return me.valueToKey(
int(tool));
220static const char *pointerTypeName(QPointingDevice::PointerType ptype) {
221 static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype);
222 static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype)));
223 return me.valueToKey(
int(ptype));
227void QXcbConnection::xi2SetupSlavePointerDevice(
void *info, QPointingDevice *master)
229 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
230#if QT_CONFIG(tabletevent)
231 for (
int i = 0; i < m_tabletData.size(); ++i) {
232 if (m_tabletData.at(i).deviceId == deviceInfo->deviceid) {
233 m_tabletData.remove(i);
238 m_touchDevices.remove(deviceInfo->deviceid);
240 const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
241 xcb_input_xi_device_info_name_length(deviceInfo));
242 const QString name = QString::fromUtf8(nameRaw);
243 m_xiSlavePointerIds.append(deviceInfo->deviceid);
244 qCDebug(lcQpaInputDevices) <<
"input device " << name <<
"ID" << deviceInfo->deviceid;
245#if QT_CONFIG(tabletevent)
246 TabletData tabletData;
248 QXcbScrollingDevicePrivate *scrollingDeviceP =
nullptr;
250 auto scrollingDevice = [&]() {
251 if (!scrollingDeviceP)
252 scrollingDeviceP =
new QXcbScrollingDevicePrivate(name, deviceInfo->deviceid,
253 QInputDevice::Capability::Scroll);
254 return scrollingDeviceP;
257 int buttonCount = 32;
258 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
259 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
260 xcb_input_device_class_t *classinfo = classes_it.data;
261 switch (classinfo->type) {
262 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
263 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
264 const int valuatorAtom = qatom(vci->label);
265 qCDebug(lcQpaInputDevices) <<
" has valuator" << atomName(vci->label) <<
"recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
266#if QT_CONFIG(tabletevent)
267 if (valuatorAtom < QXcbAtom::NAtoms) {
268 TabletData::ValuatorClassInfo info;
269 info.minVal = fixed3232ToReal(vci->min);
270 info.maxVal = fixed3232ToReal(vci->max);
271 info.number = vci->number;
272 tabletData.valuatorInfo[valuatorAtom] = info;
275 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
276 scrollingDevice()->lastScrollPosition.setX(fixed3232ToReal(vci->value));
277 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
278 scrollingDevice()->lastScrollPosition.setY(fixed3232ToReal(vci->value));
281 case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
282 auto *sci =
reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
283 if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
284 auto dev = scrollingDevice();
285 dev->orientations.setFlag(Qt::Vertical);
286 dev->verticalIndex = sci->number;
287 dev->verticalIncrement = fixed3232ToReal(sci->increment);
288 }
else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
289 auto dev = scrollingDevice();
290 dev->orientations.setFlag(Qt::Horizontal);
291 dev->horizontalIndex = sci->number;
292 dev->horizontalIncrement = fixed3232ToReal(sci->increment);
296 case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: {
297 auto *bci =
reinterpret_cast<xcb_input_button_class_t *>(classinfo);
298 xcb_atom_t *labels =
nullptr;
299 if (bci->num_buttons >= 5) {
300 labels = xcb_input_button_class_labels(bci);
301 xcb_atom_t label4 = labels[3];
302 xcb_atom_t label5 = labels[4];
305 if ((!label4 || qatom(label4) == QXcbAtom::AtomButtonWheelUp || qatom(label4) == QXcbAtom::AtomButtonWheelDown) &&
306 (!label5 || qatom(label5) == QXcbAtom::AtomButtonWheelUp || qatom(label5) == QXcbAtom::AtomButtonWheelDown))
307 scrollingDevice()->legacyOrientations |= Qt::Vertical;
309 if (bci->num_buttons >= 7) {
310 xcb_atom_t label6 = labels[5];
311 xcb_atom_t label7 = labels[6];
312 if ((!label6 || qatom(label6) == QXcbAtom::AtomButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::AtomButtonHorizWheelRight))
313 scrollingDevice()->legacyOrientations |= Qt::Horizontal;
315 buttonCount = bci->num_buttons;
316 qCDebug(lcQpaInputDevices,
" has %d buttons", bci->num_buttons);
319 case XCB_INPUT_DEVICE_CLASS_TYPE_KEY:
320 qCDebug(lcQpaInputDevices) <<
" it's a keyboard";
322 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
323#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
324 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE:
329 qCDebug(lcQpaInputDevices) <<
" has class" << classinfo->type;
333 bool isTablet =
false;
334#if QT_CONFIG(tabletevent)
336 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsX) &&
337 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsY) &&
338 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsPressure))
342 QByteArray nameLower = nameRaw.toLower();
343 QString dbgType =
"UNKNOWN"_L1;
344 if (nameLower.contains(
"eraser")) {
346 tabletData.pointerType = QPointingDevice::PointerType::Eraser;
347 dbgType =
"eraser"_L1;
348 }
else if (nameLower.contains(
"cursor") && !(nameLower.contains(
"cursor controls") && nameLower.contains(
"trackball"))) {
350 tabletData.pointerType = QPointingDevice::PointerType::Cursor;
351 dbgType =
"cursor"_L1;
352 }
else if (nameLower.contains(
"wacom") && nameLower.contains(
"finger touch")) {
354 }
else if ((nameLower.contains(
"pen") || nameLower.contains(
"stylus")) && isTablet) {
355 tabletData.pointerType = QPointingDevice::PointerType::Pen;
357 }
else if (nameLower.contains(
"wacom") && isTablet && !nameLower.contains(
"touch")) {
359 tabletData.pointerType = QPointingDevice::PointerType::Pen;
361 }
else if (nameLower.contains(
"aiptek") ) {
364 tabletData.pointerType = QPointingDevice::PointerType::Pen;
366 }
else if (nameLower.contains(
"waltop") && nameLower.contains(
"tablet")) {
370 tabletData.pointerType = QPointingDevice::PointerType::Pen;
372 }
else if (nameLower.contains(
"uc-logic") && isTablet) {
373 tabletData.pointerType = QPointingDevice::PointerType::Pen;
375 }
else if (nameLower.contains(
"ugee")) {
377 tabletData.pointerType = QPointingDevice::PointerType::Pen;
384 tabletData.deviceId = deviceInfo->deviceid;
385 tabletData.name = name;
386 m_tabletData.append(tabletData);
387 qCDebug(lcQpaInputDevices) <<
" it's a tablet with pointer type" << dbgType;
388 QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None;
389 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltX))
390 capsOverride.setFlag(QInputDevice::Capability::XTilt);
391 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltY))
392 capsOverride.setFlag(QInputDevice::Capability::YTilt);
394 Q_ASSERT(deviceInfo->deviceid == tabletData.deviceId);
395 const QPointingDevice *dev = tabletToolInstance(master,
396 tabletData.name, deviceInfo->deviceid, 0, 0, tabletData.serialId,
397 tabletData.pointerType, capsOverride);
402 if (scrollingDeviceP) {
404 scrollingDeviceP->legacyOrientations &= ~scrollingDeviceP->orientations;
405 qCDebug(lcQpaInputDevices) <<
" it's a scrolling device";
409 TouchDeviceData *dev = populateTouchDevices(deviceInfo, scrollingDeviceP, &used);
410 if (dev && lcQpaInputDevices().isDebugEnabled()) {
411 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen)
412 qCDebug(lcQpaInputDevices,
" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
413 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
414 dev->qtTouchDevice->maximumPoints());
415 else if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
416 qCDebug(lcQpaInputDevices,
" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
417 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
418 dev->qtTouchDevice->maximumPoints(),
419 dev->size.width(), dev->size.height());
423 if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) {
424 qCDebug(lcQpaInputDevices) <<
" it's a mouse";
425 QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover;
426 if (scrollingDeviceP) {
427 scrollingDeviceP->capabilities |= caps;
428 scrollingDeviceP->buttonCount = buttonCount;
430 scrollingDeviceP->seatName = master->seatName();
431 QWindowSystemInterface::registerInputDevice(
new QXcbScrollingDevice(*scrollingDeviceP, master));
434 QWindowSystemInterface::registerInputDevice(
new QPointingDevice(
435 name, deviceInfo->deviceid,
436 QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
437 caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master));
441 if (!used && scrollingDeviceP) {
442 QXcbScrollingDevice *holder =
new QXcbScrollingDevice(*scrollingDeviceP, master);
443 holder->deleteLater();
448
449
450
451
452
453
454void QXcbConnection::xi2SetupDevices()
456 m_xiMasterPointerIds.clear();
458 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL);
460 qCDebug(lcQpaInputDevices) <<
"failed to query devices";
466 QList<
const QInputDevice *> previousDevices = QInputDevice::devices();
469 auto newOrKeep = [&previousDevices](qint64 systemId) {
471 return !previousDevices.removeIf([systemId](
const QInputDevice *dev) {
472 return dev->systemId() == systemId;
479 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
480 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
481 xcb_input_xi_device_info_t *deviceInfo = it.data;
482 switch (deviceInfo->type) {
483 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD: {
484 if (newOrKeep(deviceInfo->deviceid)) {
485 auto dev =
new QInputDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)),
486 deviceInfo->deviceid, QInputDevice::DeviceType::Keyboard,
487 QString::number(deviceInfo->deviceid << 16 | deviceInfo->attachment, 16),
this);
488 QWindowSystemInterface::registerInputDevice(dev);
491 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER: {
492 m_xiMasterPointerIds.append(deviceInfo->deviceid);
493 if (newOrKeep(deviceInfo->deviceid)) {
494 auto dev =
new QXcbScrollingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
495 QInputDevice::Capability::Position | QInputDevice::Capability::Scroll | QInputDevice::Capability::Hover,
496 32, QString::number(deviceInfo->attachment << 16 | deviceInfo->deviceid, 16),
this);
497 QWindowSystemInterface::registerInputDevice(dev);
506 it = xcb_input_xi_query_device_infos_iterator(reply.get());
507 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
508 xcb_input_xi_device_info_t *deviceInfo = it.data;
509 switch (deviceInfo->type) {
510 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD:
511 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
514 case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
515 if (newOrKeep(deviceInfo->deviceid)) {
516 m_xiSlavePointerIds.append(deviceInfo->deviceid);
517 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
519 xi2SetupSlavePointerDevice(deviceInfo, qobject_cast<QPointingDevice *>(master));
522 case XCB_INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: {
523 if (newOrKeep(deviceInfo->deviceid)) {
524 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
526 QWindowSystemInterface::registerInputDevice(
new QInputDevice(
527 QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
528 QInputDevice::DeviceType::Keyboard, master->seatName(), master));
531 case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
537 qCDebug(lcQpaInputDevices) <<
"removed" << previousDevices;
538 for (
auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
539 const auto id = (*it)->systemId();
540 m_xiSlavePointerIds.removeAll(id);
541 m_touchDevices.remove(id);
543 qDeleteAll(previousDevices);
545 if (m_xiMasterPointerIds.size() > 1)
546 qCDebug(lcQpaInputDevices) <<
"multi-pointer X detected";
549QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(
int id)
551 TouchDeviceData *dev =
nullptr;
552 if (m_touchDevices.contains(id))
553 dev = &m_touchDevices[id];
557QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(
void *info, QXcbScrollingDevicePrivate *scrollingDeviceP,
bool *used)
559 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
560 QPointingDevice::Capabilities caps;
561 QInputDevice::DeviceType type = QInputDevice::DeviceType::Unknown;
562 int maxTouchPoints = 1;
563 bool isTouchDevice =
false;
564 bool hasRelativeCoords =
false;
566 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
567 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
568 xcb_input_device_class_t *classinfo = classes_it.data;
569 switch (classinfo->type) {
570 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: {
571 auto *tci =
reinterpret_cast<xcb_input_touch_class_t *>(classinfo);
572 maxTouchPoints = tci->num_touches;
573 qCDebug(lcQpaInputDevices,
" has touch class with mode %d", tci->mode);
575 case XCB_INPUT_TOUCH_MODE_DEPENDENT:
576 type = QInputDevice::DeviceType::TouchPad;
578 case XCB_INPUT_TOUCH_MODE_DIRECT:
579 type = QInputDevice::DeviceType::TouchScreen;
584#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
585 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE: {
589 auto *gci =
reinterpret_cast<xcb_input_gesture_class_t *>(classinfo);
590 maxTouchPoints = gci->num_touches;
591 qCDebug(lcQpaInputDevices,
" has gesture class");
592 type = QInputDevice::DeviceType::TouchPad;
596 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
597 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
598 const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
599 if (valuatorAtom < QXcbAtom::NAtoms) {
600 TouchDeviceData::ValuatorClassInfo info;
601 info.min = fixed3232ToReal(vci->min);
602 info.max = fixed3232ToReal(vci->max);
603 info.number = vci->number;
604 info.label = valuatorAtom;
605 dev.valuatorInfo.append(info);
609 const int vciResolution = vci->resolution ? vci->resolution : 1;
610 if (valuatorAtom == QXcbAtom::AtomAbsMTPositionX)
611 caps |= QInputDevice::Capability::Position | QInputDevice::Capability::NormalizedPosition;
612 else if (valuatorAtom == QXcbAtom::AtomAbsMTTouchMajor)
613 caps |= QInputDevice::Capability::Area;
614 else if (valuatorAtom == QXcbAtom::AtomAbsMTOrientation)
615 dev.providesTouchOrientation =
true;
616 else if (valuatorAtom == QXcbAtom::AtomAbsMTPressure || valuatorAtom == QXcbAtom::AtomAbsPressure)
617 caps |= QInputDevice::Capability::Pressure;
618 else if (valuatorAtom == QXcbAtom::AtomRelX) {
619 hasRelativeCoords =
true;
620 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
621 }
else if (valuatorAtom == QXcbAtom::AtomRelY) {
622 hasRelativeCoords =
true;
623 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
624 }
else if (valuatorAtom == QXcbAtom::AtomAbsX) {
625 caps |= QInputDevice::Capability::Position;
626 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
627 }
else if (valuatorAtom == QXcbAtom::AtomAbsY) {
628 caps |= QInputDevice::Capability::Position;
629 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
630 }
else if (valuatorAtom == QXcbAtom::AtomRelVertWheel || valuatorAtom == QXcbAtom::AtomRelHorizWheel) {
631 caps |= QInputDevice::Capability::Scroll;
639 if (type == QInputDevice::DeviceType::Unknown && caps && hasRelativeCoords) {
640 type = QInputDevice::DeviceType::TouchPad;
641 if (dev.size.width() < 10 || dev.size.height() < 10 ||
642 dev.size.width() > 10000 || dev.size.height() > 10000)
643 dev.size = QSizeF(130, 110);
645 if (!isAtLeastXI22() || type == QInputDevice::DeviceType::TouchPad)
646 caps |= QInputDevice::Capability::MouseEmulation;
648 if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) {
649 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
651 if (scrollingDeviceP) {
653 scrollingDeviceP->deviceType = type;
654 scrollingDeviceP->pointerType = QPointingDevice::PointerType::Finger;
655 scrollingDeviceP->capabilities |= caps;
656 scrollingDeviceP->maximumTouchPoints = maxTouchPoints;
657 scrollingDeviceP->buttonCount = 3;
658 scrollingDeviceP->seatName = master->seatName();
659 dev.qtTouchDevice =
new QXcbScrollingDevice(*scrollingDeviceP, master);
660 if (Q_UNLIKELY(!caps.testFlag(QInputDevice::Capability::Scroll)))
661 qCDebug(lcQpaInputDevices) <<
"unexpectedly missing RelVert/HorizWheel atoms for touchpad with scroll capability" << dev.qtTouchDevice;
664 dev.qtTouchDevice =
new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo),
665 xcb_input_xi_device_info_name_length(deviceInfo)),
666 deviceInfo->deviceid,
667 type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0,
668 master->seatName(), QPointingDeviceUniqueId(), master);
671 QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice);
672 m_touchDevices[deviceInfo->deviceid] = dev;
673 isTouchDevice =
true;
676 return isTouchDevice ? &m_touchDevices[deviceInfo->deviceid] :
nullptr;
681 return qreal(val) / 0x10000;
684void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
686 auto *xiEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
687 setTime(xiEvent->time);
688 if (m_xiSlavePointerIds.contains(xiEvent->deviceid) && xiEvent->event_type != XCB_INPUT_PROPERTY) {
689 if (!m_duringSystemMoveResize)
691 if (xiEvent->event == XCB_NONE)
694 if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
695 && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
696 abortSystemMoveResize(xiEvent->event);
697 }
else if (xiEvent->event_type == XCB_INPUT_TOUCH_END) {
698 abortSystemMoveResize(xiEvent->event);
704 int sourceDeviceId = xiEvent->deviceid;
705 qt_xcb_input_device_event_t *xiDeviceEvent =
nullptr;
706 xcb_input_enter_event_t *xiEnterEvent =
nullptr;
707 QXcbWindowEventListener *eventListener =
nullptr;
709 switch (xiEvent->event_type) {
710 case XCB_INPUT_BUTTON_PRESS:
711 case XCB_INPUT_BUTTON_RELEASE:
712 case XCB_INPUT_MOTION:
713 case XCB_INPUT_TOUCH_BEGIN:
714 case XCB_INPUT_TOUCH_UPDATE:
715 case XCB_INPUT_TOUCH_END:
717 xiDeviceEvent = xiEvent;
718 eventListener = windowEventListenerFromId(xiDeviceEvent->event);
719 sourceDeviceId = xiDeviceEvent->sourceid;
722#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
723 case XCB_INPUT_GESTURE_PINCH_BEGIN:
724 case XCB_INPUT_GESTURE_PINCH_UPDATE:
725 case XCB_INPUT_GESTURE_PINCH_END:
726 xi2HandleGesturePinchEvent(event);
728 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
729 case XCB_INPUT_GESTURE_SWIPE_UPDATE:
730 case XCB_INPUT_GESTURE_SWIPE_END:
731 xi2HandleGestureSwipeEvent(event);
734 case XCB_INPUT_ENTER:
735 case XCB_INPUT_LEAVE: {
736 xiEnterEvent =
reinterpret_cast<xcb_input_enter_event_t *>(event);
737 eventListener = windowEventListenerFromId(xiEnterEvent->event);
738 sourceDeviceId = xiEnterEvent->sourceid;
741 case XCB_INPUT_HIERARCHY:
742 xi2HandleHierarchyEvent(event);
744 case XCB_INPUT_DEVICE_CHANGED:
745 xi2HandleDeviceChangedEvent(event);
752 if (eventListener->handleNativeEvent(
reinterpret_cast<xcb_generic_event_t *>(event)))
756#if QT_CONFIG(tabletevent)
759 QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
760 if (tablet && xi2HandleTabletEvent(event, tablet))
765 if (
auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
766 xi2HandleScrollEvent(event, device);
768 qCDebug(lcQpaXInputEvents) <<
"scroll event from unregistered device" << sourceDeviceId;
771 switch (xiDeviceEvent->event_type) {
772 case XCB_INPUT_BUTTON_PRESS:
773 case XCB_INPUT_BUTTON_RELEASE:
774 case XCB_INPUT_MOTION:
775 if (eventListener && !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
776 eventListener->handleXIMouseEvent(event);
779 case XCB_INPUT_TOUCH_BEGIN:
780 case XCB_INPUT_TOUCH_UPDATE:
781 case XCB_INPUT_TOUCH_END:
782 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
783 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",
784 event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
785 fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
786 fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
787 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
788 xi2ProcessTouch(xiDeviceEvent, platformWindow);
790 if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
791 dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
795 }
else if (xiEnterEvent && eventListener) {
796 switch (xiEnterEvent->event_type) {
797 case XCB_INPUT_ENTER:
798 case XCB_INPUT_LEAVE:
799 eventListener->handleXIEnterLeave(event);
805bool QXcbConnection::isTouchScreen(
int id)
807 auto device = touchDeviceForId(id);
808 return device && device->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen;
811void QXcbConnection::xi2ProcessTouch(
void *xiDevEvent, QXcbWindow *platformWindow)
813 auto *xiDeviceEvent =
reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
814 TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
816 qCDebug(lcQpaXInputEvents) <<
"didn't find the dev for given sourceid - " << xiDeviceEvent->sourceid
817 <<
", try to repopulate xi2 devices";
819 dev = touchDeviceForId(xiDeviceEvent->sourceid);
821 qCDebug(lcQpaXInputEvents) <<
"still can't find the dev for it, give up.";
825 const bool firstTouch = dev->touchPoints.isEmpty();
826 if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
827 QWindowSystemInterface::TouchPoint tp;
828 tp.id = xiDeviceEvent->detail % INT_MAX;
829 tp.state = QEventPoint::State::Pressed;
831 dev->touchPoints[tp.id] = tp;
833 QWindowSystemInterface::TouchPoint &touchPoint = dev->touchPoints[xiDeviceEvent->detail];
834 QXcbScreen* screen = platformWindow->xcbScreen();
835 qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
836 qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
837 qreal nx = -1.0, ny = -1.0;
838 qreal w = 0.0, h = 0.0;
839 bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width();
840 for (
const TouchDeviceData::ValuatorClassInfo &vci : std::as_const(dev->valuatorInfo)) {
842 if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value))
844 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
845 qCDebug(lcQpaXInputEvents,
" valuator %20s value %lf from range %lf -> %lf",
846 atomName(atom(vci.label)).constData(), value, vci.min, vci.max);
851 qreal valuatorNormalized = (value - vci.min) / (vci.max - vci.min);
852 if (vci.label == QXcbAtom::AtomRelX) {
853 nx = valuatorNormalized;
854 }
else if (vci.label == QXcbAtom::AtomRelY) {
855 ny = valuatorNormalized;
856 }
else if (vci.label == QXcbAtom::AtomAbsX) {
857 nx = valuatorNormalized;
858 }
else if (vci.label == QXcbAtom::AtomAbsY) {
859 ny = valuatorNormalized;
860 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionX) {
861 nx = valuatorNormalized;
862 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionY) {
863 ny = valuatorNormalized;
864 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMajor) {
865 const qreal sw = screen->geometry().width();
866 const qreal sh = screen->geometry().height();
867 w = valuatorNormalized * qHypot(sw, sh);
868 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMinor) {
869 const qreal sw = screen->geometry().width();
870 const qreal sh = screen->geometry().height();
871 h = valuatorNormalized * qHypot(sw, sh);
872 }
else if (vci.label == QXcbAtom::AtomAbsMTOrientation) {
879 while (value > vci.max)
880 value -= 2 * vci.max;
882 majorAxisIsY = value < vci.max - value;
883 }
else if (vci.label == QXcbAtom::AtomAbsMTPressure || vci.label == QXcbAtom::AtomAbsPressure) {
884 touchPoint.pressure = valuatorNormalized;
890 x = touchPoint.area.center().x();
891 nx = x / screen->geometry().width();
894 y = touchPoint.area.center().y();
895 ny = y / screen->geometry().height();
897 if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) {
898 if (!dev->providesTouchOrientation) {
900 w = touchPoint.area.width();
904 w = qMax(touchPoint.area.width(), touchPoint.area.height());
906 h = qMin(touchPoint.area.width(), touchPoint.area.height());
912 switch (xiDeviceEvent->event_type) {
913 case XCB_INPUT_TOUCH_BEGIN:
915 dev->firstPressedPosition = QPointF(x, y);
916 dev->firstPressedNormalPosition = QPointF(nx, ny);
918 dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y));
923 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
924 XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH,
925 xiDeviceEvent->detail, xiDeviceEvent->event);
928 case XCB_INPUT_TOUCH_UPDATE:
929 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
930 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
931 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
932 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
933 dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
934 x = dev->firstPressedPosition.x() + dx;
935 y = dev->firstPressedPosition.y() + dy;
936 touchPoint.state = QEventPoint::State::Updated;
937 }
else if (touchPoint.area.center() != QPoint(x, y)) {
938 touchPoint.state = QEventPoint::State::Updated;
939 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
940 dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
943 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen &&
944 xiDeviceEvent->event == m_startSystemMoveResizeInfo.window &&
945 xiDeviceEvent->sourceid == m_startSystemMoveResizeInfo.deviceid &&
946 xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
947 QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window);
949 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
950 XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
951 xiDeviceEvent->detail, xiDeviceEvent->event);
952 window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.edges);
953 m_startSystemMoveResizeInfo.window = XCB_NONE;
957 case XCB_INPUT_TOUCH_END:
958 touchPoint.state = QEventPoint::State::Released;
959 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
960 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
961 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
962 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
963 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
964 x = dev->firstPressedPosition.x() + dx;
965 y = dev->firstPressedPosition.y() + dy;
967 dev->pointPressedPosition.remove(touchPoint.id);
969 touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
970 touchPoint.normalPosition = QPointF(nx, ny);
972 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
973 qCDebug(lcQpaXInputEvents) <<
" touchpoint " << touchPoint.id <<
" state " << touchPoint.state <<
" pos norm " << touchPoint.normalPosition <<
974 " area " << touchPoint.area <<
" pressure " << touchPoint.pressure;
975 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
976 QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers);
977 if (touchPoint.state == QEventPoint::State::Released)
979 dev->touchPoints.remove(touchPoint.id);
983 touchPoint.state = QEventPoint::State::Stationary;
986bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window,
int edges)
988 QHash<
int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin();
989 for (; devIt != m_touchDevices.constEnd(); ++devIt) {
990 TouchDeviceData deviceData = devIt.value();
991 if (deviceData.qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen) {
992 auto pointIt = deviceData.touchPoints.constBegin();
993 for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
994 QEventPoint::State state = pointIt.value().state;
995 if (state == QEventPoint::State::Updated || state == QEventPoint::State::Pressed || state == QEventPoint::State::Stationary) {
996 m_startSystemMoveResizeInfo.window = window;
997 m_startSystemMoveResizeInfo.deviceid = devIt.key();
998 m_startSystemMoveResizeInfo.pointid = pointIt.key();
999 m_startSystemMoveResizeInfo.edges = edges;
1000 setDuringSystemMoveResize(
true);
1001 qCDebug(lcQpaInputDevices) <<
"triggered system move or resize from touch";
1010void QXcbConnection::abortSystemMoveResize(xcb_window_t window)
1012 qCDebug(lcQpaInputDevices) <<
"sending client message NET_WM_MOVERESIZE_CANCEL to window: " << window;
1013 m_startSystemMoveResizeInfo.window = XCB_NONE;
1015 const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
1016 xcb_client_message_event_t xev;
1017 xev.response_type = XCB_CLIENT_MESSAGE;
1018 xev.type = moveResize;
1020 xev.window = window;
1022 xev.data.data32[0] = 0;
1023 xev.data.data32[1] = 0;
1024 xev.data.data32[2] = 11;
1025 xev.data.data32[3] = 0;
1026 xev.data.data32[4] = 0;
1027 xcb_send_event(xcb_connection(),
false, primaryScreen()->root(),
1028 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
1029 (
const char *)&xev);
1031 m_duringSystemMoveResize =
false;
1034bool QXcbConnection::isDuringSystemMoveResize()
const
1036 return m_duringSystemMoveResize;
1039void QXcbConnection::setDuringSystemMoveResize(
bool during)
1041 m_duringSystemMoveResize = during;
1044bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w,
bool grab)
1049 uint8_t mask[8] = {};
1050 setXcbMask(mask, XCB_INPUT_BUTTON_PRESS);
1051 setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE);
1052 setXcbMask(mask, XCB_INPUT_MOTION);
1053 setXcbMask(mask, XCB_INPUT_ENTER);
1054 setXcbMask(mask, XCB_INPUT_LEAVE);
1055 if (isAtLeastXI22()) {
1056 setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN);
1057 setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE);
1058 setXcbMask(mask, XCB_INPUT_TOUCH_END);
1060#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
1061 if (isAtLeastXI24()) {
1062 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
1063 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
1064 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_END);
1065 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
1066 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
1067 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_END);
1071 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1072 xcb_generic_error_t *error =
nullptr;
1073 auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
1074 XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
1075 false, 2,
reinterpret_cast<uint32_t *>(mask));
1076 auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error);
1078 qCDebug(lcQpaXInput,
"failed to grab events for device %d on window %x"
1079 "(error code %d)", id, w, error->error_code);
1089 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1090 auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id);
1091 xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
1093 qCDebug(lcQpaXInput,
"XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code);
1110void QXcbConnection::xi2HandleHierarchyEvent(
void *event)
1112 auto *xiEvent =
reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
1117 if (xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED |
1118 XCB_INPUT_HIERARCHY_MASK_MASTER_REMOVED |
1119 XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED |
1120 XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED))
1124#if QT_XCB_HAS_TOUCHPAD_GESTURES
1125void QXcbConnection::xi2HandleGesturePinchEvent(
void *event)
1127 auto *xiEvent =
reinterpret_cast<qt_xcb_input_pinch_event_t *>(event);
1129 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1130 qCDebug(lcQpaXInputEvents,
"XI2 gesture event type %d seq %d fingers %d pos %6.1f, "
1131 "%6.1f root pos %6.1f, %6.1f delta_angle %6.1f scale %6.1f on window %x",
1132 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1133 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1134 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1135 fixed1616ToReal(xiEvent->delta_angle), fixed1616ToReal(xiEvent->scale),
1138 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1139 if (!platformWindow)
1142 setTime(xiEvent->time);
1144 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1147 uint32_t fingerCount = xiEvent->detail;
1149 switch (xiEvent->event_type) {
1150 case XCB_INPUT_GESTURE_PINCH_BEGIN:
1154 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1155 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1157 m_lastPinchScale = 1.0;
1158 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1160 Qt::BeginNativeGesture,
1161 platformWindow->lastPointerPosition(),
1162 platformWindow->lastPointerGlobalPosition(),
1166 case XCB_INPUT_GESTURE_PINCH_UPDATE: {
1167 qreal rotationDelta = fixed1616ToReal(xiEvent->delta_angle);
1168 qreal scale = fixed1616ToReal(xiEvent->scale);
1169 qreal scaleDelta = scale - m_lastPinchScale;
1170 m_lastPinchScale = scale;
1172 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1173 fixed1616ToReal(xiEvent->delta_y));
1175 if (!delta.isNull()) {
1176 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1177 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1178 Qt::PanNativeGesture, 0, delta,
1179 platformWindow->lastPointerPosition(),
1180 platformWindow->lastPointerGlobalPosition(),
1183 if (rotationDelta != 0) {
1184 QWindowSystemInterface::handleGestureEventWithRealValue(
1185 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1186 Qt::RotateNativeGesture,
1188 platformWindow->lastPointerPosition(),
1189 platformWindow->lastPointerGlobalPosition(),
1192 if (scaleDelta != 0) {
1193 QWindowSystemInterface::handleGestureEventWithRealValue(
1194 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1195 Qt::ZoomNativeGesture,
1197 platformWindow->lastPointerPosition(),
1198 platformWindow->lastPointerGlobalPosition(),
1203 case XCB_INPUT_GESTURE_PINCH_END:
1204 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1206 Qt::EndNativeGesture,
1207 platformWindow->lastPointerPosition(),
1208 platformWindow->lastPointerGlobalPosition(),
1214void QXcbConnection::xi2HandleGestureSwipeEvent(
void *event)
1216 auto *xiEvent =
reinterpret_cast<qt_xcb_input_swipe_event_t *>(event);
1218 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1219 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",
1220 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1221 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1222 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1225 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1226 if (!platformWindow)
1229 setTime(xiEvent->time);
1231 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1234 uint32_t fingerCount = xiEvent->detail;
1236 switch (xiEvent->event_type) {
1237 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
1241 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1242 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1244 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1246 Qt::BeginNativeGesture,
1247 platformWindow->lastPointerPosition(),
1248 platformWindow->lastPointerGlobalPosition(),
1251 case XCB_INPUT_GESTURE_SWIPE_UPDATE: {
1252 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1253 fixed1616ToReal(xiEvent->delta_y));
1255 if (xiEvent->delta_x != 0 || xiEvent->delta_y != 0) {
1256 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1257 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1258 Qt::PanNativeGesture, 0, delta,
1259 platformWindow->lastPointerPosition(),
1260 platformWindow->lastPointerGlobalPosition(),
1265 case XCB_INPUT_GESTURE_SWIPE_END:
1266 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1268 Qt::EndNativeGesture,
1269 platformWindow->lastPointerPosition(),
1270 platformWindow->lastPointerGlobalPosition(),
1277void QXcbConnection::xi2HandleGesturePinchEvent(
void*) {}
1278void QXcbConnection::xi2HandleGestureSwipeEvent(
void*) {}
1281void QXcbConnection::xi2HandleDeviceChangedEvent(
void *event)
1283 auto *xiEvent =
reinterpret_cast<xcb_input_device_changed_event_t *>(event);
1284 switch (xiEvent->reason) {
1285 case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
1287 if (m_xiMasterPointerIds.contains(xiEvent->deviceid) || m_xiSlavePointerIds.contains(xiEvent->deviceid))
1289 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid);
1290 if (!reply || reply->num_infos <= 0)
1292 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
1293 xi2SetupSlavePointerDevice(it.data);
1296 case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
1297 if (
auto *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
1298 xi2UpdateScrollingDevice(scrollingDevice);
1302 qCDebug(lcQpaXInputEvents,
"unknown device-changed-event (device %d)", xiEvent->sourceid);
1307void QXcbConnection::xi2UpdateScrollingDevice(QInputDevice *dev)
1309 QXcbScrollingDevice *scrollDev = qobject_cast<QXcbScrollingDevice *>(dev);
1310 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1312 QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1314 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice->systemId);
1315 if (!reply || reply->num_infos <= 0) {
1316 qCDebug(lcQpaInputDevices,
"scrolling device %lld no longer present", scrollingDevice->systemId);
1319 QPointF lastScrollPosition;
1320 if (lcQpaXInputEvents().isDebugEnabled())
1321 lastScrollPosition = scrollingDevice->lastScrollPosition;
1323 xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data;
1324 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
1325 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
1326 xcb_input_device_class_t *classInfo = classes_it.data;
1327 if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) {
1328 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
1329 const int valuatorAtom = qatom(vci->label);
1330 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
1331 scrollingDevice->lastScrollPosition.setX(fixed3232ToReal(vci->value));
1332 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
1333 scrollingDevice->lastScrollPosition.setY(fixed3232ToReal(vci->value));
1336 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice->lastScrollPosition))
1337 qCDebug(lcQpaXInputEvents,
"scrolling device %lld moved from (%f, %f) to (%f, %f)", scrollingDevice->systemId,
1338 lastScrollPosition.x(), lastScrollPosition.y(),
1339 scrollingDevice->lastScrollPosition.x(),
1340 scrollingDevice->lastScrollPosition.y());
1343void QXcbConnection::xi2UpdateScrollingDevices()
1345 const auto &devices = QInputDevice::devices();
1346 for (
const QInputDevice *dev : devices) {
1347 if (dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1348 xi2UpdateScrollingDevice(
const_cast<QInputDevice *>(dev));
1352QXcbScrollingDevice *QXcbConnection::scrollingDeviceForId(
int id)
1354 const QPointingDevice *dev = QPointingDevicePrivate::pointingDeviceById(id);
1355 if (!dev|| !dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1357 return qobject_cast<QXcbScrollingDevice *>(
const_cast<QPointingDevice *>(dev));
1360void QXcbConnection::xi2HandleScrollEvent(
void *event,
const QPointingDevice *dev)
1362 auto *xiDeviceEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
1364 const QXcbScrollingDevice *scrollDev = qobject_cast<
const QXcbScrollingDevice *>(dev);
1365 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1367 const QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1369 if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice->orientations) {
1370 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1374 if (scrollingDevice->orientations & Qt::Vertical) {
1375 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->verticalIndex, &value)) {
1376 double delta = scrollingDevice->lastScrollPosition.y() - value;
1377 scrollingDevice->lastScrollPosition.setY(value);
1378 angleDelta.setY((delta / scrollingDevice->verticalIncrement) * 120);
1382 if (scrollingDevice->verticalIncrement > 15)
1383 rawDelta.setY(delta);
1384 else if (scrollingDevice->verticalIncrement < -15)
1385 rawDelta.setY(-delta);
1388 if (scrollingDevice->orientations & Qt::Horizontal) {
1389 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->horizontalIndex, &value)) {
1390 double delta = scrollingDevice->lastScrollPosition.x() - value;
1391 scrollingDevice->lastScrollPosition.setX(value);
1392 angleDelta.setX((delta / scrollingDevice->horizontalIncrement) * 120);
1394 if (scrollingDevice->horizontalIncrement > 15)
1395 rawDelta.setX(delta);
1396 else if (scrollingDevice->horizontalIncrement < -15)
1397 rawDelta.setX(-delta);
1400 if (!angleDelta.isNull()) {
1401 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1402 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1403 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1404 if (modifiers & Qt::AltModifier) {
1405 angleDelta = angleDelta.transposed();
1406 rawDelta = rawDelta.transposed();
1408 qCDebug(lcQpaXInputEvents) <<
"scroll wheel from device" << scrollingDevice->systemId
1409 <<
"@ window pos" << local <<
"delta px" << rawDelta <<
"angle" << angleDelta;
1410 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1411 local, global, rawDelta, angleDelta, modifiers);
1414 }
else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice->legacyOrientations) {
1415 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1417 if (scrollingDevice->legacyOrientations & Qt::Vertical) {
1418 if (xiDeviceEvent->detail == 4)
1419 angleDelta.setY(120);
1420 else if (xiDeviceEvent->detail == 5)
1421 angleDelta.setY(-120);
1423 if (scrollingDevice->legacyOrientations & Qt::Horizontal) {
1424 if (xiDeviceEvent->detail == 6)
1425 angleDelta.setX(120);
1426 else if (xiDeviceEvent->detail == 7)
1427 angleDelta.setX(-120);
1429 if (!angleDelta.isNull()) {
1430 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1431 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1432 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1433 if (modifiers & Qt::AltModifier)
1434 angleDelta = angleDelta.transposed();
1435 qCDebug(lcQpaXInputEvents) <<
"scroll wheel (button" << xiDeviceEvent->detail <<
") @ window pos" << local <<
"delta angle" << angleDelta;
1436 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1437 local, global, QPoint(), angleDelta, modifiers);
1446 for (
int i = 0; i < maskLen; i++) {
1448 if ((maskPtr[i] & (1 << number)) == 0)
1451 for (
int j = 0; j < 8; j++) {
1454 if (maskPtr[i] & (1 << j))
1462bool QXcbConnection::xi2GetValuatorValueIfSet(
const void *event,
int valuatorNum,
double *value)
1464 auto *xideviceevent =
static_cast<
const qt_xcb_input_device_event_t *>(event);
1465 auto *buttonsMaskAddr =
reinterpret_cast<
const unsigned char *>(&xideviceevent[1]);
1466 auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
1467 auto *valuatorsValuesAddr =
reinterpret_cast<
const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
1469 int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
1470 if (valuatorOffset < 0)
1473 *value = valuatorsValuesAddr[valuatorOffset].integral;
1474 *value += ((
double)valuatorsValuesAddr[valuatorOffset].frac / (1 << 16) / (1 << 16));
1478Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
1481 case 1:
return Qt::LeftButton;
1482 case 2:
return Qt::MiddleButton;
1483 case 3:
return Qt::RightButton;
1487 if (b >= 8 && b <= Qt::MaxMouseButton)
1488 return static_cast<Qt::MouseButton>(Qt::BackButton << (b - 8));
1489 return Qt::NoButton;
1492#if QT_CONFIG(tabletevent)
1493bool QXcbConnection::xi2HandleTabletEvent(
const void *event, TabletData *tabletData)
1495 bool handled =
true;
1496 const auto *xiDeviceEvent =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1498 switch (xiDeviceEvent->event_type) {
1499 case XCB_INPUT_BUTTON_PRESS: {
1500 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1501 tabletData->buttons |= b;
1502 xi2ReportTabletEvent(event, tabletData);
1505 case XCB_INPUT_BUTTON_RELEASE: {
1506 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1507 tabletData->buttons ^= b;
1508 xi2ReportTabletEvent(event, tabletData);
1511 case XCB_INPUT_MOTION:
1512 xi2ReportTabletEvent(event, tabletData);
1514 case XCB_INPUT_PROPERTY: {
1517 const auto *ev =
reinterpret_cast<
const xcb_input_property_event_t *>(event);
1518 if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) {
1519 if (ev->property == atom(QXcbAtom::AtomWacomSerialIDs)) {
1520 enum WacomSerialIndex {
1522 _WACSER_LAST_TOOL_SERIAL,
1523 _WACSER_LAST_TOOL_ID,
1524 _WACSER_TOOL_SERIAL,
1529 auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, xcb_connection(), tabletData->deviceId, 0,
1530 ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
1532 if (reply->type == atom(QXcbAtom::AtomINTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
1533 quint32 *ptr =
reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get()));
1534 quint32 tool = ptr[_WACSER_TOOL_ID];
1537 if (!tool && ptr[_WACSER_TOOL_SERIAL])
1538 tool = ptr[_WACSER_TOOL_SERIAL];
1540 QWindow *win =
nullptr;
1543 const QPointingDevice *dev = tabletToolInstance(
nullptr, tabletData->name,
1544 tabletData->deviceId, ptr[_WACSER_USB_ID], tool,
1545 qint64(ptr[_WACSER_TOOL_SERIAL]));
1546 tabletData->inProximity =
true;
1547 tabletData->tool = dev->type();
1548 tabletData->serialId = qint64(ptr[_WACSER_TOOL_SERIAL]);
1549 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
true);
1551 tool = ptr[_WACSER_LAST_TOOL_ID];
1555 tool = ptr[_WACSER_LAST_TOOL_SERIAL];
1556 auto *dev = qobject_cast<
const QPointingDevice *>(QInputDevicePrivate::fromId(tabletData->deviceId));
1558 tabletData->tool = dev->type();
1559 tabletData->inProximity =
false;
1560 tabletData->serialId = qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
1561 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
false);
1565 qCDebug(lcQpaInputDevices,
"XI2 proximity change on tablet %d %s (USB %x): last tool: %x id %x current tool: %x id %x %s",
1566 tabletData->deviceId, qPrintable(tabletData->name), ptr[_WACSER_USB_ID],
1567 ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
1568 ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
1583inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize)
1585 return screenMin + normValue * screenSize;
1589void QXcbConnection::xi2ReportTabletEvent(
const void *event, TabletData *tabletData)
1591 auto *ev =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1592 QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
1595 QWindow *window = xcbWindow->window();
1596 const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective);
1597 QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y));
1598 QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y));
1599 double pressure = 0, rotation = 0, tangentialPressure = 0;
1600 qreal xTilt = 0, yTilt = 0;
1601 static const bool useValuators = !qEnvironmentVariableIsSet(
"QT_XCB_TABLET_LEGACY_COORDINATES");
1602 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(tabletData->tool),
1603 QPointingDevice::PointerType(tabletData->pointerType),
1604 QPointingDeviceUniqueId::fromNumericId(tabletData->serialId));
1609 QRect physicalScreenArea;
1610 if (Q_LIKELY(useValuators)) {
1611 const QList<QPlatformScreen *> siblings = window->screen()->handle()->virtualSiblings();
1612 for (
const QPlatformScreen *screen : siblings)
1613 physicalScreenArea |= screen->geometry();
1616 for (QHash<
int, TabletData::ValuatorClassInfo>::iterator it = tabletData->valuatorInfo.begin(),
1617 ite = tabletData->valuatorInfo.end(); it != ite; ++it) {
1618 int valuator = it.key();
1619 TabletData::ValuatorClassInfo &classInfo(it.value());
1620 xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
1621 double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal);
1623 case QXcbAtom::AtomAbsX:
1624 if (Q_LIKELY(useValuators)) {
1625 const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width());
1627 local.setX(xcbWindow->mapFromGlobalF(global).x());
1630 case QXcbAtom::AtomAbsY:
1631 if (Q_LIKELY(useValuators)) {
1632 qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height());
1634 local.setY(xcbWindow->mapFromGlobalF(global).y());
1637 case QXcbAtom::AtomAbsPressure:
1638 pressure = normalizedValue;
1640 case QXcbAtom::AtomAbsTiltX:
1641 xTilt = classInfo.curVal;
1643 case QXcbAtom::AtomAbsTiltY:
1644 yTilt = classInfo.curVal;
1646 case QXcbAtom::AtomAbsWheel:
1647 switch (tabletData->tool) {
1648 case QInputDevice::DeviceType::Airbrush:
1649 tangentialPressure = normalizedValue * 2.0 - 1.0;
1651 case QInputDevice::DeviceType::Stylus:
1652 if (dev->capabilities().testFlag(QInputDevice::Capability::Rotation))
1653 rotation = normalizedValue * 360.0 - 180.0;
1664 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
1665 qCDebug(lcQpaXInputEvents,
"XI2 event on tablet %d with tool %s %llx type %s seq %d detail %d time %d "
1666 "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",
1667 tabletData->deviceId, toolName(tabletData->tool), tabletData->serialId, pointerTypeName(tabletData->pointerType),
1668 ev->sequence, ev->detail, ev->time,
1669 local.x(), local.y(), global.x(), global.y(),
1670 (
int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (
int)modifiers);
1672 QWindowSystemInterface::handleTabletEvent(window, ev->time, dev, local, global,
1673 tabletData->buttons, pressure,
1674 xTilt, yTilt, tangentialPressure,
1675 rotation, 0, modifiers);
1678QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(
int id)
1680 for (
int i = 0; i < m_tabletData.size(); ++i) {
1681 if (m_tabletData.at(i).deviceId == id)
1682 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)