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,
bool removeExisting, QPointingDevice *master)
229 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
230 if (removeExisting) {
231#if QT_CONFIG(tabletevent)
232 for (
int i = 0; i < m_tabletData.size(); ++i) {
233 if (m_tabletData.at(i).deviceId == deviceInfo->deviceid) {
234 m_tabletData.remove(i);
239 m_touchDevices.remove(deviceInfo->deviceid);
242 const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
243 xcb_input_xi_device_info_name_length(deviceInfo));
244 const QString name = QString::fromUtf8(nameRaw);
245 m_xiSlavePointerIds.append(deviceInfo->deviceid);
246 qCDebug(lcQpaInputDevices) <<
"input device " << name <<
"ID" << deviceInfo->deviceid;
247#if QT_CONFIG(tabletevent)
248 TabletData tabletData;
250 QXcbScrollingDevicePrivate *scrollingDeviceP =
nullptr;
252 auto scrollingDevice = [&]() {
253 if (!scrollingDeviceP)
254 scrollingDeviceP =
new QXcbScrollingDevicePrivate(name, deviceInfo->deviceid,
255 QInputDevice::Capability::Scroll);
256 return scrollingDeviceP;
259 int buttonCount = 32;
260 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
261 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
262 xcb_input_device_class_t *classinfo = classes_it.data;
263 switch (classinfo->type) {
264 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
265 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
266 const int valuatorAtom = qatom(vci->label);
267 qCDebug(lcQpaInputDevices) <<
" has valuator" << atomName(vci->label) <<
"recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
268#if QT_CONFIG(tabletevent)
269 if (valuatorAtom < QXcbAtom::NAtoms) {
270 TabletData::ValuatorClassInfo info;
271 info.minVal = fixed3232ToReal(vci->min);
272 info.maxVal = fixed3232ToReal(vci->max);
273 info.number = vci->number;
274 tabletData.valuatorInfo[valuatorAtom] = info;
277 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
278 scrollingDevice()->lastScrollPosition.setX(fixed3232ToReal(vci->value));
279 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
280 scrollingDevice()->lastScrollPosition.setY(fixed3232ToReal(vci->value));
283 case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
284 auto *sci =
reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
285 if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
286 auto dev = scrollingDevice();
287 dev->orientations.setFlag(Qt::Vertical);
288 dev->verticalIndex = sci->number;
289 dev->verticalIncrement = fixed3232ToReal(sci->increment);
290 }
else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
291 auto dev = scrollingDevice();
292 dev->orientations.setFlag(Qt::Horizontal);
293 dev->horizontalIndex = sci->number;
294 dev->horizontalIncrement = fixed3232ToReal(sci->increment);
298 case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: {
299 auto *bci =
reinterpret_cast<xcb_input_button_class_t *>(classinfo);
300 xcb_atom_t *labels =
nullptr;
301 if (bci->num_buttons >= 5) {
302 labels = xcb_input_button_class_labels(bci);
303 xcb_atom_t label4 = labels[3];
304 xcb_atom_t label5 = labels[4];
307 if ((!label4 || qatom(label4) == QXcbAtom::AtomButtonWheelUp || qatom(label4) == QXcbAtom::AtomButtonWheelDown) &&
308 (!label5 || qatom(label5) == QXcbAtom::AtomButtonWheelUp || qatom(label5) == QXcbAtom::AtomButtonWheelDown))
309 scrollingDevice()->legacyOrientations |= Qt::Vertical;
311 if (bci->num_buttons >= 7) {
312 xcb_atom_t label6 = labels[5];
313 xcb_atom_t label7 = labels[6];
314 if ((!label6 || qatom(label6) == QXcbAtom::AtomButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::AtomButtonHorizWheelRight))
315 scrollingDevice()->legacyOrientations |= Qt::Horizontal;
317 buttonCount = bci->num_buttons;
318 qCDebug(lcQpaInputDevices,
" has %d buttons", bci->num_buttons);
321 case XCB_INPUT_DEVICE_CLASS_TYPE_KEY:
322 qCDebug(lcQpaInputDevices) <<
" it's a keyboard";
324 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
325#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
326 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE:
331 qCDebug(lcQpaInputDevices) <<
" has class" << classinfo->type;
335 bool isTablet =
false;
336#if QT_CONFIG(tabletevent)
338 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsX) &&
339 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsY) &&
340 tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsPressure))
344 QByteArray nameLower = nameRaw.toLower();
345 QString dbgType =
"UNKNOWN"_L1;
346 if (nameLower.contains(
"eraser")) {
348 tabletData.pointerType = QPointingDevice::PointerType::Eraser;
349 dbgType =
"eraser"_L1;
350 }
else if (nameLower.contains(
"cursor") && !(nameLower.contains(
"cursor controls") && nameLower.contains(
"trackball"))) {
352 tabletData.pointerType = QPointingDevice::PointerType::Cursor;
353 dbgType =
"cursor"_L1;
354 }
else if (nameLower.contains(
"wacom") && nameLower.contains(
"finger touch")) {
356 }
else if ((nameLower.contains(
"pen") || nameLower.contains(
"stylus")) && isTablet) {
357 tabletData.pointerType = QPointingDevice::PointerType::Pen;
359 }
else if (nameLower.contains(
"wacom") && isTablet && !nameLower.contains(
"touch")) {
361 tabletData.pointerType = QPointingDevice::PointerType::Pen;
363 }
else if (nameLower.contains(
"aiptek") ) {
366 tabletData.pointerType = QPointingDevice::PointerType::Pen;
368 }
else if (nameLower.contains(
"waltop") && nameLower.contains(
"tablet")) {
372 tabletData.pointerType = QPointingDevice::PointerType::Pen;
374 }
else if (nameLower.contains(
"uc-logic") && isTablet) {
375 tabletData.pointerType = QPointingDevice::PointerType::Pen;
377 }
else if (nameLower.contains(
"ugee")) {
379 tabletData.pointerType = QPointingDevice::PointerType::Pen;
386 tabletData.deviceId = deviceInfo->deviceid;
387 tabletData.name = name;
388 m_tabletData.append(tabletData);
389 qCDebug(lcQpaInputDevices) <<
" it's a tablet with pointer type" << dbgType;
390 QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None;
391 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltX))
392 capsOverride.setFlag(QInputDevice::Capability::XTilt);
393 if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltY))
394 capsOverride.setFlag(QInputDevice::Capability::YTilt);
396 Q_ASSERT(deviceInfo->deviceid == tabletData.deviceId);
397 const QPointingDevice *dev = tabletToolInstance(master,
398 tabletData.name, deviceInfo->deviceid, 0, 0, tabletData.serialId,
399 tabletData.pointerType, capsOverride);
404 if (scrollingDeviceP) {
406 scrollingDeviceP->legacyOrientations &= ~scrollingDeviceP->orientations;
407 qCDebug(lcQpaInputDevices) <<
" it's a scrolling device";
411 TouchDeviceData *dev = populateTouchDevices(deviceInfo, scrollingDeviceP, &used);
412 if (dev && lcQpaInputDevices().isDebugEnabled()) {
413 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen)
414 qCDebug(lcQpaInputDevices,
" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
415 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
416 dev->qtTouchDevice->maximumPoints());
417 else if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
418 qCDebug(lcQpaInputDevices,
" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
419 int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
420 dev->qtTouchDevice->maximumPoints(),
421 dev->size.width(), dev->size.height());
425 if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) {
426 qCDebug(lcQpaInputDevices) <<
" it's a mouse";
427 QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover;
428 if (scrollingDeviceP) {
429 scrollingDeviceP->capabilities |= caps;
430 scrollingDeviceP->buttonCount = buttonCount;
432 scrollingDeviceP->seatName = master->seatName();
433 QWindowSystemInterface::registerInputDevice(
new QXcbScrollingDevice(*scrollingDeviceP, master));
436 QWindowSystemInterface::registerInputDevice(
new QPointingDevice(
437 name, deviceInfo->deviceid,
438 QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
439 caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master));
443 if (!used && scrollingDeviceP) {
444 QXcbScrollingDevice *holder =
new QXcbScrollingDevice(*scrollingDeviceP, master);
445 holder->deleteLater();
450
451
452
453
454
455
456void QXcbConnection::xi2SetupDevices()
458 m_xiMasterPointerIds.clear();
460 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL);
462 qCDebug(lcQpaInputDevices) <<
"failed to query devices";
468 QList<
const QInputDevice *> previousDevices = QInputDevice::devices();
471 auto newOrKeep = [&previousDevices](qint64 systemId) {
473 return !previousDevices.removeIf([systemId](
const QInputDevice *dev) {
474 return dev->systemId() == systemId;
481 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
482 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
483 xcb_input_xi_device_info_t *deviceInfo = it.data;
484 switch (deviceInfo->type) {
485 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD: {
486 if (newOrKeep(deviceInfo->deviceid)) {
487 auto dev =
new QInputDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)),
488 deviceInfo->deviceid, QInputDevice::DeviceType::Keyboard,
489 QString::number(deviceInfo->deviceid << 16 | deviceInfo->attachment, 16),
this);
490 QWindowSystemInterface::registerInputDevice(dev);
493 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER: {
494 m_xiMasterPointerIds.append(deviceInfo->deviceid);
495 if (newOrKeep(deviceInfo->deviceid)) {
496 auto dev =
new QXcbScrollingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
497 QInputDevice::Capability::Position | QInputDevice::Capability::Scroll | QInputDevice::Capability::Hover,
498 32, QString::number(deviceInfo->attachment << 16 | deviceInfo->deviceid, 16),
this);
499 QWindowSystemInterface::registerInputDevice(dev);
508 it = xcb_input_xi_query_device_infos_iterator(reply.get());
509 for (; it.rem; xcb_input_xi_device_info_next(&it)) {
510 xcb_input_xi_device_info_t *deviceInfo = it.data;
511 switch (deviceInfo->type) {
512 case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD:
513 case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
516 case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
517 if (newOrKeep(deviceInfo->deviceid)) {
518 m_xiSlavePointerIds.append(deviceInfo->deviceid);
519 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
521 xi2SetupSlavePointerDevice(deviceInfo,
false, qobject_cast<QPointingDevice *>(master));
524 case XCB_INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: {
525 if (newOrKeep(deviceInfo->deviceid)) {
526 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
528 QWindowSystemInterface::registerInputDevice(
new QInputDevice(
529 QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
530 QInputDevice::DeviceType::Keyboard, master->seatName(), master));
533 case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
539 qCDebug(lcQpaInputDevices) <<
"removed" << previousDevices;
540 for (
auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
541 const auto id = (*it)->systemId();
542 m_xiSlavePointerIds.removeAll(id);
543 m_touchDevices.remove(id);
545 qDeleteAll(previousDevices);
547 if (m_xiMasterPointerIds.size() > 1)
548 qCDebug(lcQpaInputDevices) <<
"multi-pointer X detected";
551QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(
int id)
553 TouchDeviceData *dev =
nullptr;
554 if (m_touchDevices.contains(id))
555 dev = &m_touchDevices[id];
559QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(
void *info, QXcbScrollingDevicePrivate *scrollingDeviceP,
bool *used)
561 auto *deviceInfo =
reinterpret_cast<xcb_input_xi_device_info_t *>(info);
562 QPointingDevice::Capabilities caps;
563 QInputDevice::DeviceType type = QInputDevice::DeviceType::Unknown;
564 int maxTouchPoints = 1;
565 bool isTouchDevice =
false;
566 bool hasRelativeCoords =
false;
568 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
569 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
570 xcb_input_device_class_t *classinfo = classes_it.data;
571 switch (classinfo->type) {
572 case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: {
573 auto *tci =
reinterpret_cast<xcb_input_touch_class_t *>(classinfo);
574 maxTouchPoints = tci->num_touches;
575 qCDebug(lcQpaInputDevices,
" has touch class with mode %d", tci->mode);
577 case XCB_INPUT_TOUCH_MODE_DEPENDENT:
578 type = QInputDevice::DeviceType::TouchPad;
580 case XCB_INPUT_TOUCH_MODE_DIRECT:
581 type = QInputDevice::DeviceType::TouchScreen;
586#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
587 case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE: {
591 auto *gci =
reinterpret_cast<xcb_input_gesture_class_t *>(classinfo);
592 maxTouchPoints = gci->num_touches;
593 qCDebug(lcQpaInputDevices,
" has gesture class");
594 type = QInputDevice::DeviceType::TouchPad;
598 case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
599 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
600 const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
601 if (valuatorAtom < QXcbAtom::NAtoms) {
602 TouchDeviceData::ValuatorClassInfo info;
603 info.min = fixed3232ToReal(vci->min);
604 info.max = fixed3232ToReal(vci->max);
605 info.number = vci->number;
606 info.label = valuatorAtom;
607 dev.valuatorInfo.append(info);
611 const int vciResolution = vci->resolution ? vci->resolution : 1;
612 if (valuatorAtom == QXcbAtom::AtomAbsMTPositionX)
613 caps |= QInputDevice::Capability::Position | QInputDevice::Capability::NormalizedPosition;
614 else if (valuatorAtom == QXcbAtom::AtomAbsMTTouchMajor)
615 caps |= QInputDevice::Capability::Area;
616 else if (valuatorAtom == QXcbAtom::AtomAbsMTOrientation)
617 dev.providesTouchOrientation =
true;
618 else if (valuatorAtom == QXcbAtom::AtomAbsMTPressure || valuatorAtom == QXcbAtom::AtomAbsPressure)
619 caps |= QInputDevice::Capability::Pressure;
620 else if (valuatorAtom == QXcbAtom::AtomRelX) {
621 hasRelativeCoords =
true;
622 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
623 }
else if (valuatorAtom == QXcbAtom::AtomRelY) {
624 hasRelativeCoords =
true;
625 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
626 }
else if (valuatorAtom == QXcbAtom::AtomAbsX) {
627 caps |= QInputDevice::Capability::Position;
628 dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
629 }
else if (valuatorAtom == QXcbAtom::AtomAbsY) {
630 caps |= QInputDevice::Capability::Position;
631 dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
632 }
else if (valuatorAtom == QXcbAtom::AtomRelVertWheel || valuatorAtom == QXcbAtom::AtomRelHorizWheel) {
633 caps |= QInputDevice::Capability::Scroll;
641 if (type == QInputDevice::DeviceType::Unknown && caps && hasRelativeCoords) {
642 type = QInputDevice::DeviceType::TouchPad;
643 if (dev.size.width() < 10 || dev.size.height() < 10 ||
644 dev.size.width() > 10000 || dev.size.height() > 10000)
645 dev.size = QSizeF(130, 110);
647 if (!isAtLeastXI22() || type == QInputDevice::DeviceType::TouchPad)
648 caps |= QInputDevice::Capability::MouseEmulation;
650 if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) {
651 QInputDevice *master =
const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
653 if (scrollingDeviceP) {
655 scrollingDeviceP->deviceType = type;
656 scrollingDeviceP->pointerType = QPointingDevice::PointerType::Finger;
657 scrollingDeviceP->capabilities |= caps;
658 scrollingDeviceP->maximumTouchPoints = maxTouchPoints;
659 scrollingDeviceP->buttonCount = 3;
660 scrollingDeviceP->seatName = master->seatName();
661 dev.qtTouchDevice =
new QXcbScrollingDevice(*scrollingDeviceP, master);
662 if (Q_UNLIKELY(!caps.testFlag(QInputDevice::Capability::Scroll)))
663 qCDebug(lcQpaInputDevices) <<
"unexpectedly missing RelVert/HorizWheel atoms for touchpad with scroll capability" << dev.qtTouchDevice;
666 dev.qtTouchDevice =
new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo),
667 xcb_input_xi_device_info_name_length(deviceInfo)),
668 deviceInfo->deviceid,
669 type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0,
670 master->seatName(), QPointingDeviceUniqueId(), master);
673 QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice);
674 m_touchDevices[deviceInfo->deviceid] = dev;
675 isTouchDevice =
true;
678 return isTouchDevice ? &m_touchDevices[deviceInfo->deviceid] :
nullptr;
683 return qreal(val) / 0x10000;
686void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
688 auto *xiEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
689 setTime(xiEvent->time);
690 if (m_xiSlavePointerIds.contains(xiEvent->deviceid) && xiEvent->event_type != XCB_INPUT_PROPERTY) {
691 if (!m_duringSystemMoveResize)
693 if (xiEvent->event == XCB_NONE)
696 if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
697 && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
698 abortSystemMoveResize(xiEvent->event);
699 }
else if (xiEvent->event_type == XCB_INPUT_TOUCH_END) {
700 abortSystemMoveResize(xiEvent->event);
706 int sourceDeviceId = xiEvent->deviceid;
707 qt_xcb_input_device_event_t *xiDeviceEvent =
nullptr;
708 xcb_input_enter_event_t *xiEnterEvent =
nullptr;
709 QXcbWindowEventListener *eventListener =
nullptr;
711 switch (xiEvent->event_type) {
712 case XCB_INPUT_BUTTON_PRESS:
713 case XCB_INPUT_BUTTON_RELEASE:
714 case XCB_INPUT_MOTION:
715 case XCB_INPUT_TOUCH_BEGIN:
716 case XCB_INPUT_TOUCH_UPDATE:
717 case XCB_INPUT_TOUCH_END:
719 xiDeviceEvent = xiEvent;
720 eventListener = windowEventListenerFromId(xiDeviceEvent->event);
721 sourceDeviceId = xiDeviceEvent->sourceid;
724#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
725 case XCB_INPUT_GESTURE_PINCH_BEGIN:
726 case XCB_INPUT_GESTURE_PINCH_UPDATE:
727 case XCB_INPUT_GESTURE_PINCH_END:
728 xi2HandleGesturePinchEvent(event);
730 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
731 case XCB_INPUT_GESTURE_SWIPE_UPDATE:
732 case XCB_INPUT_GESTURE_SWIPE_END:
733 xi2HandleGestureSwipeEvent(event);
736 case XCB_INPUT_ENTER:
737 case XCB_INPUT_LEAVE: {
738 xiEnterEvent =
reinterpret_cast<xcb_input_enter_event_t *>(event);
739 eventListener = windowEventListenerFromId(xiEnterEvent->event);
740 sourceDeviceId = xiEnterEvent->sourceid;
743 case XCB_INPUT_HIERARCHY:
744 xi2HandleHierarchyEvent(event);
746 case XCB_INPUT_DEVICE_CHANGED:
747 xi2HandleDeviceChangedEvent(event);
754 if (eventListener->handleNativeEvent(
reinterpret_cast<xcb_generic_event_t *>(event)))
758#if QT_CONFIG(tabletevent)
761 QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
762 if (tablet && xi2HandleTabletEvent(event, tablet))
767 if (
auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
768 xi2HandleScrollEvent(event, device);
770 qCDebug(lcQpaXInputEvents) <<
"scroll event from unregistered device" << sourceDeviceId;
773 switch (xiDeviceEvent->event_type) {
774 case XCB_INPUT_BUTTON_PRESS:
775 case XCB_INPUT_BUTTON_RELEASE:
776 case XCB_INPUT_MOTION:
777 if (eventListener && !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
778 eventListener->handleXIMouseEvent(event);
781 case XCB_INPUT_TOUCH_BEGIN:
782 case XCB_INPUT_TOUCH_UPDATE:
783 case XCB_INPUT_TOUCH_END:
784 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
785 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",
786 event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
787 fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
788 fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
789 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
790 xi2ProcessTouch(xiDeviceEvent, platformWindow);
792 if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
793 dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
797 }
else if (xiEnterEvent && eventListener) {
798 switch (xiEnterEvent->event_type) {
799 case XCB_INPUT_ENTER:
800 case XCB_INPUT_LEAVE:
801 eventListener->handleXIEnterLeave(event);
807bool QXcbConnection::isTouchScreen(
int id)
809 auto device = touchDeviceForId(id);
810 return device && device->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen;
813void QXcbConnection::xi2ProcessTouch(
void *xiDevEvent, QXcbWindow *platformWindow)
815 auto *xiDeviceEvent =
reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
816 TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
818 qCDebug(lcQpaXInputEvents) <<
"didn't find the dev for given sourceid - " << xiDeviceEvent->sourceid
819 <<
", try to repopulate xi2 devices";
821 dev = touchDeviceForId(xiDeviceEvent->sourceid);
823 qCDebug(lcQpaXInputEvents) <<
"still can't find the dev for it, give up.";
827 const bool firstTouch = dev->touchPoints.isEmpty();
828 if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
829 QWindowSystemInterface::TouchPoint tp;
830 tp.id = xiDeviceEvent->detail % INT_MAX;
831 tp.state = QEventPoint::State::Pressed;
833 dev->touchPoints[tp.id] = tp;
835 QWindowSystemInterface::TouchPoint &touchPoint = dev->touchPoints[xiDeviceEvent->detail];
836 QXcbScreen* screen = platformWindow->xcbScreen();
837 qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
838 qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
839 qreal nx = -1.0, ny = -1.0;
840 qreal w = 0.0, h = 0.0;
841 bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width();
842 for (
const TouchDeviceData::ValuatorClassInfo &vci : std::as_const(dev->valuatorInfo)) {
844 if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value))
846 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
847 qCDebug(lcQpaXInputEvents,
" valuator %20s value %lf from range %lf -> %lf",
848 atomName(atom(vci.label)).constData(), value, vci.min, vci.max);
853 qreal valuatorNormalized = (value - vci.min) / (vci.max - vci.min);
854 if (vci.label == QXcbAtom::AtomRelX) {
855 nx = valuatorNormalized;
856 }
else if (vci.label == QXcbAtom::AtomRelY) {
857 ny = valuatorNormalized;
858 }
else if (vci.label == QXcbAtom::AtomAbsX) {
859 nx = valuatorNormalized;
860 }
else if (vci.label == QXcbAtom::AtomAbsY) {
861 ny = valuatorNormalized;
862 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionX) {
863 nx = valuatorNormalized;
864 }
else if (vci.label == QXcbAtom::AtomAbsMTPositionY) {
865 ny = valuatorNormalized;
866 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMajor) {
867 const qreal sw = screen->geometry().width();
868 const qreal sh = screen->geometry().height();
869 w = valuatorNormalized * qHypot(sw, sh);
870 }
else if (vci.label == QXcbAtom::AtomAbsMTTouchMinor) {
871 const qreal sw = screen->geometry().width();
872 const qreal sh = screen->geometry().height();
873 h = valuatorNormalized * qHypot(sw, sh);
874 }
else if (vci.label == QXcbAtom::AtomAbsMTOrientation) {
881 while (value > vci.max)
882 value -= 2 * vci.max;
884 majorAxisIsY = value < vci.max - value;
885 }
else if (vci.label == QXcbAtom::AtomAbsMTPressure || vci.label == QXcbAtom::AtomAbsPressure) {
886 touchPoint.pressure = valuatorNormalized;
892 x = touchPoint.area.center().x();
893 nx = x / screen->geometry().width();
896 y = touchPoint.area.center().y();
897 ny = y / screen->geometry().height();
899 if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) {
900 if (!dev->providesTouchOrientation) {
902 w = touchPoint.area.width();
906 w = qMax(touchPoint.area.width(), touchPoint.area.height());
908 h = qMin(touchPoint.area.width(), touchPoint.area.height());
914 switch (xiDeviceEvent->event_type) {
915 case XCB_INPUT_TOUCH_BEGIN:
917 dev->firstPressedPosition = QPointF(x, y);
918 dev->firstPressedNormalPosition = QPointF(nx, ny);
920 dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y));
925 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
926 XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH,
927 xiDeviceEvent->detail, xiDeviceEvent->event);
930 case XCB_INPUT_TOUCH_UPDATE:
931 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
932 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
933 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
934 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
935 dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
936 x = dev->firstPressedPosition.x() + dx;
937 y = dev->firstPressedPosition.y() + dy;
938 touchPoint.state = QEventPoint::State::Updated;
939 }
else if (touchPoint.area.center() != QPoint(x, y)) {
940 touchPoint.state = QEventPoint::State::Updated;
941 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
942 dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
945 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen &&
946 xiDeviceEvent->event == m_startSystemMoveResizeInfo.window &&
947 xiDeviceEvent->sourceid == m_startSystemMoveResizeInfo.deviceid &&
948 xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
949 QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window);
951 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
952 XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
953 xiDeviceEvent->detail, xiDeviceEvent->event);
954 window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.edges);
955 m_startSystemMoveResizeInfo.window = XCB_NONE;
959 case XCB_INPUT_TOUCH_END:
960 touchPoint.state = QEventPoint::State::Released;
961 if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
962 qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
963 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
964 qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
965 dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
966 x = dev->firstPressedPosition.x() + dx;
967 y = dev->firstPressedPosition.y() + dy;
969 dev->pointPressedPosition.remove(touchPoint.id);
971 touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
972 touchPoint.normalPosition = QPointF(nx, ny);
974 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
975 qCDebug(lcQpaXInputEvents) <<
" touchpoint " << touchPoint.id <<
" state " << touchPoint.state <<
" pos norm " << touchPoint.normalPosition <<
976 " area " << touchPoint.area <<
" pressure " << touchPoint.pressure;
977 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
978 QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers);
979 if (touchPoint.state == QEventPoint::State::Released)
981 dev->touchPoints.remove(touchPoint.id);
985 touchPoint.state = QEventPoint::State::Stationary;
988bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window,
int edges)
990 QHash<
int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin();
991 for (; devIt != m_touchDevices.constEnd(); ++devIt) {
992 TouchDeviceData deviceData = devIt.value();
993 if (deviceData.qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen) {
994 auto pointIt = deviceData.touchPoints.constBegin();
995 for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
996 QEventPoint::State state = pointIt.value().state;
997 if (state == QEventPoint::State::Updated || state == QEventPoint::State::Pressed || state == QEventPoint::State::Stationary) {
998 m_startSystemMoveResizeInfo.window = window;
999 m_startSystemMoveResizeInfo.deviceid = devIt.key();
1000 m_startSystemMoveResizeInfo.pointid = pointIt.key();
1001 m_startSystemMoveResizeInfo.edges = edges;
1002 setDuringSystemMoveResize(
true);
1003 qCDebug(lcQpaInputDevices) <<
"triggered system move or resize from touch";
1012void QXcbConnection::abortSystemMoveResize(xcb_window_t window)
1014 qCDebug(lcQpaInputDevices) <<
"sending client message NET_WM_MOVERESIZE_CANCEL to window: " << window;
1015 m_startSystemMoveResizeInfo.window = XCB_NONE;
1017 const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
1018 xcb_client_message_event_t xev;
1019 xev.response_type = XCB_CLIENT_MESSAGE;
1020 xev.type = moveResize;
1022 xev.window = window;
1024 xev.data.data32[0] = 0;
1025 xev.data.data32[1] = 0;
1026 xev.data.data32[2] = 11;
1027 xev.data.data32[3] = 0;
1028 xev.data.data32[4] = 0;
1029 xcb_send_event(xcb_connection(),
false, primaryScreen()->root(),
1030 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
1031 (
const char *)&xev);
1033 m_duringSystemMoveResize =
false;
1036bool QXcbConnection::isDuringSystemMoveResize()
const
1038 return m_duringSystemMoveResize;
1041void QXcbConnection::setDuringSystemMoveResize(
bool during)
1043 m_duringSystemMoveResize = during;
1046bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w,
bool grab)
1051 uint8_t mask[8] = {};
1052 setXcbMask(mask, XCB_INPUT_BUTTON_PRESS);
1053 setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE);
1054 setXcbMask(mask, XCB_INPUT_MOTION);
1055 setXcbMask(mask, XCB_INPUT_ENTER);
1056 setXcbMask(mask, XCB_INPUT_LEAVE);
1057 if (isAtLeastXI22()) {
1058 setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN);
1059 setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE);
1060 setXcbMask(mask, XCB_INPUT_TOUCH_END);
1062#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
1063 if (isAtLeastXI24()) {
1064 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
1065 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
1066 setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_END);
1067 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
1068 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
1069 setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_END);
1073 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1074 xcb_generic_error_t *error =
nullptr;
1075 auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
1076 XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
1077 false, 2,
reinterpret_cast<uint32_t *>(mask));
1078 auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error);
1080 qCDebug(lcQpaXInput,
"failed to grab events for device %d on window %x"
1081 "(error code %d)", id, w, error->error_code);
1091 for (
int id : std::as_const(m_xiMasterPointerIds)) {
1092 auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id);
1093 xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
1095 qCDebug(lcQpaXInput,
"XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code);
1112void QXcbConnection::xi2HandleHierarchyEvent(
void *event)
1114 auto *xiEvent =
reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
1119 if (xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED |
1120 XCB_INPUT_HIERARCHY_MASK_MASTER_REMOVED |
1121 XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED |
1122 XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED))
1126#if QT_XCB_HAS_TOUCHPAD_GESTURES
1127void QXcbConnection::xi2HandleGesturePinchEvent(
void *event)
1129 auto *xiEvent =
reinterpret_cast<qt_xcb_input_pinch_event_t *>(event);
1131 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1132 qCDebug(lcQpaXInputEvents,
"XI2 gesture event type %d seq %d fingers %d pos %6.1f, "
1133 "%6.1f root pos %6.1f, %6.1f delta_angle %6.1f scale %6.1f on window %x",
1134 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1135 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1136 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1137 fixed1616ToReal(xiEvent->delta_angle), fixed1616ToReal(xiEvent->scale),
1140 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1141 if (!platformWindow)
1144 setTime(xiEvent->time);
1146 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1149 uint32_t fingerCount = xiEvent->detail;
1151 switch (xiEvent->event_type) {
1152 case XCB_INPUT_GESTURE_PINCH_BEGIN:
1156 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1157 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1159 m_lastPinchScale = 1.0;
1160 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1162 Qt::BeginNativeGesture,
1163 platformWindow->lastPointerPosition(),
1164 platformWindow->lastPointerGlobalPosition(),
1168 case XCB_INPUT_GESTURE_PINCH_UPDATE: {
1169 qreal rotationDelta = fixed1616ToReal(xiEvent->delta_angle);
1170 qreal scale = fixed1616ToReal(xiEvent->scale);
1171 qreal scaleDelta = scale - m_lastPinchScale;
1172 m_lastPinchScale = scale;
1174 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1175 fixed1616ToReal(xiEvent->delta_y));
1177 if (!delta.isNull()) {
1178 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1179 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1180 Qt::PanNativeGesture, 0, delta,
1181 platformWindow->lastPointerPosition(),
1182 platformWindow->lastPointerGlobalPosition(),
1185 if (rotationDelta != 0) {
1186 QWindowSystemInterface::handleGestureEventWithRealValue(
1187 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1188 Qt::RotateNativeGesture,
1190 platformWindow->lastPointerPosition(),
1191 platformWindow->lastPointerGlobalPosition(),
1194 if (scaleDelta != 0) {
1195 QWindowSystemInterface::handleGestureEventWithRealValue(
1196 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1197 Qt::ZoomNativeGesture,
1199 platformWindow->lastPointerPosition(),
1200 platformWindow->lastPointerGlobalPosition(),
1205 case XCB_INPUT_GESTURE_PINCH_END:
1206 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1208 Qt::EndNativeGesture,
1209 platformWindow->lastPointerPosition(),
1210 platformWindow->lastPointerGlobalPosition(),
1216void QXcbConnection::xi2HandleGestureSwipeEvent(
void *event)
1218 auto *xiEvent =
reinterpret_cast<qt_xcb_input_swipe_event_t *>(event);
1220 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
1221 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",
1222 xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
1223 fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
1224 fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
1227 QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
1228 if (!platformWindow)
1231 setTime(xiEvent->time);
1233 TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
1236 uint32_t fingerCount = xiEvent->detail;
1238 switch (xiEvent->event_type) {
1239 case XCB_INPUT_GESTURE_SWIPE_BEGIN:
1243 xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
1244 XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
1246 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1248 Qt::BeginNativeGesture,
1249 platformWindow->lastPointerPosition(),
1250 platformWindow->lastPointerGlobalPosition(),
1253 case XCB_INPUT_GESTURE_SWIPE_UPDATE: {
1254 QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
1255 fixed1616ToReal(xiEvent->delta_y));
1257 if (xiEvent->delta_x != 0 || xiEvent->delta_y != 0) {
1258 QWindowSystemInterface::handleGestureEventWithValueAndDelta(
1259 platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
1260 Qt::PanNativeGesture, 0, delta,
1261 platformWindow->lastPointerPosition(),
1262 platformWindow->lastPointerGlobalPosition(),
1267 case XCB_INPUT_GESTURE_SWIPE_END:
1268 QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
1270 Qt::EndNativeGesture,
1271 platformWindow->lastPointerPosition(),
1272 platformWindow->lastPointerGlobalPosition(),
1279void QXcbConnection::xi2HandleGesturePinchEvent(
void*) {}
1280void QXcbConnection::xi2HandleGestureSwipeEvent(
void*) {}
1283void QXcbConnection::xi2HandleDeviceChangedEvent(
void *event)
1285 auto *xiEvent =
reinterpret_cast<xcb_input_device_changed_event_t *>(event);
1286 switch (xiEvent->reason) {
1287 case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
1289 if (m_xiMasterPointerIds.contains(xiEvent->deviceid) || m_xiSlavePointerIds.contains(xiEvent->deviceid))
1291 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid);
1292 if (!reply || reply->num_infos <= 0)
1294 auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
1295 xi2SetupSlavePointerDevice(it.data);
1298 case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
1299 if (
auto *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
1300 xi2UpdateScrollingDevice(scrollingDevice);
1304 qCDebug(lcQpaXInputEvents,
"unknown device-changed-event (device %d)", xiEvent->sourceid);
1309void QXcbConnection::xi2UpdateScrollingDevice(QInputDevice *dev)
1311 QXcbScrollingDevice *scrollDev = qobject_cast<QXcbScrollingDevice *>(dev);
1312 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1314 QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1316 auto reply =
Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice->systemId);
1317 if (!reply || reply->num_infos <= 0) {
1318 qCDebug(lcQpaInputDevices,
"scrolling device %lld no longer present", scrollingDevice->systemId);
1321 QPointF lastScrollPosition;
1322 if (lcQpaXInputEvents().isDebugEnabled())
1323 lastScrollPosition = scrollingDevice->lastScrollPosition;
1325 xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data;
1326 auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
1327 for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
1328 xcb_input_device_class_t *classInfo = classes_it.data;
1329 if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) {
1330 auto *vci =
reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
1331 const int valuatorAtom = qatom(vci->label);
1332 if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
1333 scrollingDevice->lastScrollPosition.setX(fixed3232ToReal(vci->value));
1334 else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
1335 scrollingDevice->lastScrollPosition.setY(fixed3232ToReal(vci->value));
1338 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice->lastScrollPosition))
1339 qCDebug(lcQpaXInputEvents,
"scrolling device %lld moved from (%f, %f) to (%f, %f)", scrollingDevice->systemId,
1340 lastScrollPosition.x(), lastScrollPosition.y(),
1341 scrollingDevice->lastScrollPosition.x(),
1342 scrollingDevice->lastScrollPosition.y());
1345void QXcbConnection::xi2UpdateScrollingDevices()
1347 const auto &devices = QInputDevice::devices();
1348 for (
const QInputDevice *dev : devices) {
1349 if (dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1350 xi2UpdateScrollingDevice(
const_cast<QInputDevice *>(dev));
1354QXcbScrollingDevice *QXcbConnection::scrollingDeviceForId(
int id)
1356 const QPointingDevice *dev = QPointingDevicePrivate::pointingDeviceById(id);
1357 if (!dev|| !dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1359 return qobject_cast<QXcbScrollingDevice *>(
const_cast<QPointingDevice *>(dev));
1362void QXcbConnection::xi2HandleScrollEvent(
void *event,
const QPointingDevice *dev)
1364 auto *xiDeviceEvent =
reinterpret_cast<qt_xcb_input_device_event_t *>(event);
1366 const QXcbScrollingDevice *scrollDev = qobject_cast<
const QXcbScrollingDevice *>(dev);
1367 if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
1369 const QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
1371 if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice->orientations) {
1372 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1376 if (scrollingDevice->orientations & Qt::Vertical) {
1377 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->verticalIndex, &value)) {
1378 double delta = scrollingDevice->lastScrollPosition.y() - value;
1379 scrollingDevice->lastScrollPosition.setY(value);
1380 angleDelta.setY((delta / scrollingDevice->verticalIncrement) * 120);
1384 if (scrollingDevice->verticalIncrement > 15)
1385 rawDelta.setY(delta);
1386 else if (scrollingDevice->verticalIncrement < -15)
1387 rawDelta.setY(-delta);
1390 if (scrollingDevice->orientations & Qt::Horizontal) {
1391 if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->horizontalIndex, &value)) {
1392 double delta = scrollingDevice->lastScrollPosition.x() - value;
1393 scrollingDevice->lastScrollPosition.setX(value);
1394 angleDelta.setX((delta / scrollingDevice->horizontalIncrement) * 120);
1396 if (scrollingDevice->horizontalIncrement > 15)
1397 rawDelta.setX(delta);
1398 else if (scrollingDevice->horizontalIncrement < -15)
1399 rawDelta.setX(-delta);
1402 if (!angleDelta.isNull()) {
1403 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1404 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1405 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1406 if (modifiers & Qt::AltModifier) {
1407 angleDelta = angleDelta.transposed();
1408 rawDelta = rawDelta.transposed();
1410 qCDebug(lcQpaXInputEvents) <<
"scroll wheel from device" << scrollingDevice->systemId
1411 <<
"@ window pos" << local <<
"delta px" << rawDelta <<
"angle" << angleDelta;
1412 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1413 local, global, rawDelta, angleDelta, modifiers);
1416 }
else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice->legacyOrientations) {
1417 if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
1419 if (scrollingDevice->legacyOrientations & Qt::Vertical) {
1420 if (xiDeviceEvent->detail == 4)
1421 angleDelta.setY(120);
1422 else if (xiDeviceEvent->detail == 5)
1423 angleDelta.setY(-120);
1425 if (scrollingDevice->legacyOrientations & Qt::Horizontal) {
1426 if (xiDeviceEvent->detail == 6)
1427 angleDelta.setX(120);
1428 else if (xiDeviceEvent->detail == 7)
1429 angleDelta.setX(-120);
1431 if (!angleDelta.isNull()) {
1432 QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
1433 QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
1434 Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
1435 if (modifiers & Qt::AltModifier)
1436 angleDelta = angleDelta.transposed();
1437 qCDebug(lcQpaXInputEvents) <<
"scroll wheel (button" << xiDeviceEvent->detail <<
") @ window pos" << local <<
"delta angle" << angleDelta;
1438 QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
1439 local, global, QPoint(), angleDelta, modifiers);
1448 for (
int i = 0; i < maskLen; i++) {
1450 if ((maskPtr[i] & (1 << number)) == 0)
1453 for (
int j = 0; j < 8; j++) {
1456 if (maskPtr[i] & (1 << j))
1464bool QXcbConnection::xi2GetValuatorValueIfSet(
const void *event,
int valuatorNum,
double *value)
1466 auto *xideviceevent =
static_cast<
const qt_xcb_input_device_event_t *>(event);
1467 auto *buttonsMaskAddr =
reinterpret_cast<
const unsigned char *>(&xideviceevent[1]);
1468 auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
1469 auto *valuatorsValuesAddr =
reinterpret_cast<
const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
1471 int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
1472 if (valuatorOffset < 0)
1475 *value = valuatorsValuesAddr[valuatorOffset].integral;
1476 *value += ((
double)valuatorsValuesAddr[valuatorOffset].frac / (1 << 16) / (1 << 16));
1480Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
1483 case 1:
return Qt::LeftButton;
1484 case 2:
return Qt::MiddleButton;
1485 case 3:
return Qt::RightButton;
1489 if (b >= 8 && b <= Qt::MaxMouseButton)
1490 return static_cast<Qt::MouseButton>(Qt::BackButton << (b - 8));
1491 return Qt::NoButton;
1494#if QT_CONFIG(tabletevent)
1495bool QXcbConnection::xi2HandleTabletEvent(
const void *event, TabletData *tabletData)
1497 bool handled =
true;
1498 const auto *xiDeviceEvent =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1500 switch (xiDeviceEvent->event_type) {
1501 case XCB_INPUT_BUTTON_PRESS: {
1502 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1503 tabletData->buttons |= b;
1504 xi2ReportTabletEvent(event, tabletData);
1507 case XCB_INPUT_BUTTON_RELEASE: {
1508 Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
1509 tabletData->buttons ^= b;
1510 xi2ReportTabletEvent(event, tabletData);
1513 case XCB_INPUT_MOTION:
1514 xi2ReportTabletEvent(event, tabletData);
1516 case XCB_INPUT_PROPERTY: {
1519 const auto *ev =
reinterpret_cast<
const xcb_input_property_event_t *>(event);
1520 if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) {
1521 if (ev->property == atom(QXcbAtom::AtomWacomSerialIDs)) {
1522 enum WacomSerialIndex {
1524 _WACSER_LAST_TOOL_SERIAL,
1525 _WACSER_LAST_TOOL_ID,
1526 _WACSER_TOOL_SERIAL,
1531 auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, xcb_connection(), tabletData->deviceId, 0,
1532 ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
1534 if (reply->type == atom(QXcbAtom::AtomINTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
1535 quint32 *ptr =
reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get()));
1536 quint32 tool = ptr[_WACSER_TOOL_ID];
1539 if (!tool && ptr[_WACSER_TOOL_SERIAL])
1540 tool = ptr[_WACSER_TOOL_SERIAL];
1542 QWindow *win =
nullptr;
1545 const QPointingDevice *dev = tabletToolInstance(
nullptr, tabletData->name,
1546 tabletData->deviceId, ptr[_WACSER_USB_ID], tool,
1547 qint64(ptr[_WACSER_TOOL_SERIAL]));
1548 tabletData->inProximity =
true;
1549 tabletData->tool = dev->type();
1550 tabletData->serialId = qint64(ptr[_WACSER_TOOL_SERIAL]);
1551 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
true);
1553 tool = ptr[_WACSER_LAST_TOOL_ID];
1557 tool = ptr[_WACSER_LAST_TOOL_SERIAL];
1558 auto *dev = qobject_cast<
const QPointingDevice *>(QInputDevicePrivate::fromId(tabletData->deviceId));
1560 tabletData->tool = dev->type();
1561 tabletData->inProximity =
false;
1562 tabletData->serialId = qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
1563 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev,
false);
1567 qCDebug(lcQpaInputDevices,
"XI2 proximity change on tablet %d %s (USB %x): last tool: %x id %x current tool: %x id %x %s",
1568 tabletData->deviceId, qPrintable(tabletData->name), ptr[_WACSER_USB_ID],
1569 ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
1570 ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
1585inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize)
1587 return screenMin + normValue * screenSize;
1591void QXcbConnection::xi2ReportTabletEvent(
const void *event, TabletData *tabletData)
1593 auto *ev =
reinterpret_cast<
const qt_xcb_input_device_event_t *>(event);
1594 QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
1597 QWindow *window = xcbWindow->window();
1598 const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective);
1599 QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y));
1600 QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y));
1601 double pressure = 0, rotation = 0, tangentialPressure = 0;
1602 qreal xTilt = 0, yTilt = 0;
1603 static const bool useValuators = !qEnvironmentVariableIsSet(
"QT_XCB_TABLET_LEGACY_COORDINATES");
1604 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(tabletData->tool),
1605 QPointingDevice::PointerType(tabletData->pointerType),
1606 QPointingDeviceUniqueId::fromNumericId(tabletData->serialId));
1611 QRect physicalScreenArea;
1612 if (Q_LIKELY(useValuators)) {
1613 const QList<QPlatformScreen *> siblings = window->screen()->handle()->virtualSiblings();
1614 for (
const QPlatformScreen *screen : siblings)
1615 physicalScreenArea |= screen->geometry();
1618 for (QHash<
int, TabletData::ValuatorClassInfo>::iterator it = tabletData->valuatorInfo.begin(),
1619 ite = tabletData->valuatorInfo.end(); it != ite; ++it) {
1620 int valuator = it.key();
1621 TabletData::ValuatorClassInfo &classInfo(it.value());
1622 xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
1623 double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal);
1625 case QXcbAtom::AtomAbsX:
1626 if (Q_LIKELY(useValuators)) {
1627 const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width());
1629 local.setX(xcbWindow->mapFromGlobalF(global).x());
1632 case QXcbAtom::AtomAbsY:
1633 if (Q_LIKELY(useValuators)) {
1634 qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height());
1636 local.setY(xcbWindow->mapFromGlobalF(global).y());
1639 case QXcbAtom::AtomAbsPressure:
1640 pressure = normalizedValue;
1642 case QXcbAtom::AtomAbsTiltX:
1643 xTilt = classInfo.curVal;
1645 case QXcbAtom::AtomAbsTiltY:
1646 yTilt = classInfo.curVal;
1648 case QXcbAtom::AtomAbsWheel:
1649 switch (tabletData->tool) {
1650 case QInputDevice::DeviceType::Airbrush:
1651 tangentialPressure = normalizedValue * 2.0 - 1.0;
1653 case QInputDevice::DeviceType::Stylus:
1654 if (dev->capabilities().testFlag(QInputDevice::Capability::Rotation))
1655 rotation = normalizedValue * 360.0 - 180.0;
1666 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
1667 qCDebug(lcQpaXInputEvents,
"XI2 event on tablet %d with tool %s %llx type %s seq %d detail %d time %d "
1668 "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",
1669 tabletData->deviceId, toolName(tabletData->tool), tabletData->serialId, pointerTypeName(tabletData->pointerType),
1670 ev->sequence, ev->detail, ev->time,
1671 local.x(), local.y(), global.x(), global.y(),
1672 (
int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (
int)modifiers);
1674 QWindowSystemInterface::handleTabletEvent(window, ev->time, dev, local, global,
1675 tabletData->buttons, pressure,
1676 xTilt, yTilt, tangentialPressure,
1677 rotation, 0, modifiers);
1680QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(
int id)
1682 for (
int i = 0; i < m_tabletData.size(); ++i) {
1683 if (m_tabletData.at(i).deviceId == id)
1684 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)