diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2017-06-08 18:54:53 +0200 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2017-07-18 13:19:03 +0000 |
commit | 900abb116d6f47e71bc2bdfa57553dd91786edf7 (patch) | |
tree | 94d06aca51a1f2492a163c510d0ef14cd4abf23e /src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | |
parent | 46001e6f491640b340dd43c0da464aef9978f9d1 (diff) |
xcb: allow to change XInput device properties at runtime
xinput list-props <device-id>
xinput set-prop <device-id> <atom-id> n n n
Example:
xinput list-props 9
..
Evdev Scrolling Distance (274): 1, 1, 1
..
xinput set-prop 9 274 8 1 1
[ChangeLog][Platform Specific Changes][Linux] XInput device property
changes are now detected at runtime (no application restart required).
Change-Id: I4d2455eef70857bc2e35c27011a3808a78fa960f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbconnection_xi2.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 320 |
1 files changed, 174 insertions, 146 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 24b9dff6f7..a4be0371fd 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -93,175 +93,195 @@ void QXcbConnection::initializeXInput2() } } -void QXcbConnection::xi2SetupDevices() +void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) { + XIDeviceInfo *deviceInfo = reinterpret_cast<XIDeviceInfo *>(info); + if (removeExisting) { #if QT_CONFIG(tabletevent) - m_tabletData.clear(); + for (int i = 0; i < m_tabletData.count(); ++i) { + if (m_tabletData.at(i).deviceId == deviceInfo->deviceid) { + m_tabletData.remove(i); + break; + } + } #endif - m_scrollingDevices.clear(); - m_touchDevices.clear(); + m_scrollingDevices.remove(deviceInfo->deviceid); + m_touchDevices.remove(deviceInfo->deviceid); + } - Display *xDisplay = static_cast<Display *>(m_xlib_display); - int deviceCount = 0; - XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); - for (int i = 0; i < deviceCount; ++i) { - // Only non-master pointing devices are relevant here. - if (devices[i].use != XISlavePointer) - continue; - qCDebug(lcQpaXInputDevices) << "input device " << devices[i].name << "ID" << devices[i].deviceid; + qCDebug(lcQpaXInputDevices) << "input device " << deviceInfo->name << "ID" << deviceInfo->deviceid; #if QT_CONFIG(tabletevent) - TabletData tabletData; + TabletData tabletData; #endif - ScrollingDevice scrollingDevice; - for (int c = 0; c < devices[i].num_classes; ++c) { - XIAnyClassInfo *classinfo = devices[i].classes[c]; - switch (classinfo->type) { - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); - const int valuatorAtom = qatom(vci->label); - qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); + ScrollingDevice scrollingDevice; + for (int c = 0; c < deviceInfo->num_classes; ++c) { + XIAnyClassInfo *classinfo = deviceInfo->classes[c]; + switch (classinfo->type) { + case XIValuatorClass: { + XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); + const int valuatorAtom = qatom(vci->label); + qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); #if QT_CONFIG(tabletevent) - if (valuatorAtom < QXcbAtom::NAtoms) { - TabletData::ValuatorClassInfo info; - info.minVal = vci->min; - info.maxVal = vci->max; - info.number = vci->number; - tabletData.valuatorInfo[valuatorAtom] = info; - } -#endif // QT_CONFIG(tabletevent) - if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) - scrollingDevice.lastScrollPosition.setX(vci->value); - else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) - scrollingDevice.lastScrollPosition.setY(vci->value); - break; + if (valuatorAtom < QXcbAtom::NAtoms) { + TabletData::ValuatorClassInfo info; + info.minVal = vci->min; + info.maxVal = vci->max; + info.number = vci->number; + tabletData.valuatorInfo[valuatorAtom] = info; } +#endif // QT_CONFIG(tabletevent) + if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) + scrollingDevice.lastScrollPosition.setX(vci->value); + else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) + scrollingDevice.lastScrollPosition.setY(vci->value); + break; + } #ifdef XCB_USE_XINPUT21 - case XIScrollClass: { - XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(classinfo); - if (sci->scroll_type == XIScrollTypeVertical) { - scrollingDevice.orientations |= Qt::Vertical; - scrollingDevice.verticalIndex = sci->number; - scrollingDevice.verticalIncrement = sci->increment; - } - else if (sci->scroll_type == XIScrollTypeHorizontal) { - scrollingDevice.orientations |= Qt::Horizontal; - scrollingDevice.horizontalIndex = sci->number; - scrollingDevice.horizontalIncrement = sci->increment; - } - break; + case XIScrollClass: { + XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(classinfo); + if (sci->scroll_type == XIScrollTypeVertical) { + scrollingDevice.orientations |= Qt::Vertical; + scrollingDevice.verticalIndex = sci->number; + scrollingDevice.verticalIncrement = sci->increment; } - case XIButtonClass: { - XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(classinfo); - if (bci->num_buttons >= 5) { - Atom label4 = bci->labels[3]; - Atom label5 = bci->labels[4]; - // Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on - // button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons. - if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) && - (!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown)) - scrollingDevice.legacyOrientations |= Qt::Vertical; - } - if (bci->num_buttons >= 7) { - Atom label6 = bci->labels[5]; - Atom label7 = bci->labels[6]; - if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight)) - scrollingDevice.legacyOrientations |= Qt::Horizontal; - } - qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons); - break; + else if (sci->scroll_type == XIScrollTypeHorizontal) { + scrollingDevice.orientations |= Qt::Horizontal; + scrollingDevice.horizontalIndex = sci->number; + scrollingDevice.horizontalIncrement = sci->increment; + } + break; + } + case XIButtonClass: { + XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(classinfo); + if (bci->num_buttons >= 5) { + Atom label4 = bci->labels[3]; + Atom label5 = bci->labels[4]; + // Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on + // button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons. + if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) && + (!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown)) + scrollingDevice.legacyOrientations |= Qt::Vertical; } + if (bci->num_buttons >= 7) { + Atom label6 = bci->labels[5]; + Atom label7 = bci->labels[6]; + if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight)) + scrollingDevice.legacyOrientations |= Qt::Horizontal; + } + qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons); + break; + } #endif - case XIKeyClass: - qCDebug(lcQpaXInputDevices) << " it's a keyboard"; - break; + case XIKeyClass: + qCDebug(lcQpaXInputDevices) << " it's a keyboard"; + break; #ifdef XCB_USE_XINPUT22 - case XITouchClass: - // will be handled in populateTouchDevices() - break; + case XITouchClass: + // will be handled in populateTouchDevices() + break; #endif - default: - qCDebug(lcQpaXInputDevices) << " has class" << classinfo->type; - break; - } + default: + qCDebug(lcQpaXInputDevices) << " has class" << classinfo->type; + break; } - bool isTablet = false; + } + bool isTablet = false; #if QT_CONFIG(tabletevent) - // If we have found the valuators which we expect a tablet to have, it might be a tablet. - if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && - tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && - tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) - isTablet = true; - - // But we need to be careful not to take the touch and tablet-button devices as tablets. - QByteArray name = QByteArray(devices[i].name).toLower(); - QString dbgType = QLatin1String("UNKNOWN"); - if (name.contains("eraser")) { - isTablet = true; - tabletData.pointerType = QTabletEvent::Eraser; - dbgType = QLatin1String("eraser"); - } else if (name.contains("cursor")) { - isTablet = true; - tabletData.pointerType = QTabletEvent::Cursor; - dbgType = QLatin1String("cursor"); - } else if (name.contains("wacom") && name.contains("finger touch")) { - isTablet = false; - } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) { - tabletData.pointerType = QTabletEvent::Pen; - dbgType = QLatin1String("pen"); - } else if (name.contains("wacom") && isTablet && !name.contains("touch")) { - // combined device (evdev) rather than separate pen/eraser (wacom driver) - tabletData.pointerType = QTabletEvent::Pen; - dbgType = QLatin1String("pen"); - } else if (name.contains("aiptek") /* && device == QXcbAtom::KEYBOARD */) { - // some "Genius" tablets - isTablet = true; - tabletData.pointerType = QTabletEvent::Pen; - dbgType = QLatin1String("pen"); - } else if (name.contains("waltop") && name.contains("tablet")) { - // other "Genius" tablets - // WALTOP International Corp. Slim Tablet - isTablet = true; - tabletData.pointerType = QTabletEvent::Pen; - dbgType = QLatin1String("pen"); - } else if (name.contains("uc-logic") && isTablet) { - tabletData.pointerType = QTabletEvent::Pen; - dbgType = QLatin1String("pen"); - } else { - isTablet = false; - } + // If we have found the valuators which we expect a tablet to have, it might be a tablet. + if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) + isTablet = true; + + // But we need to be careful not to take the touch and tablet-button devices as tablets. + QByteArray name = QByteArray(deviceInfo->name).toLower(); + QString dbgType = QLatin1String("UNKNOWN"); + if (name.contains("eraser")) { + isTablet = true; + tabletData.pointerType = QTabletEvent::Eraser; + dbgType = QLatin1String("eraser"); + } else if (name.contains("cursor")) { + isTablet = true; + tabletData.pointerType = QTabletEvent::Cursor; + dbgType = QLatin1String("cursor"); + } else if (name.contains("wacom") && name.contains("finger touch")) { + isTablet = false; + } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) { + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else if (name.contains("wacom") && isTablet && !name.contains("touch")) { + // combined device (evdev) rather than separate pen/eraser (wacom driver) + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else if (name.contains("aiptek") /* && device == QXcbAtom::KEYBOARD */) { + // some "Genius" tablets + isTablet = true; + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else if (name.contains("waltop") && name.contains("tablet")) { + // other "Genius" tablets + // WALTOP International Corp. Slim Tablet + isTablet = true; + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else if (name.contains("uc-logic") && isTablet) { + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else { + isTablet = false; + } - if (isTablet) { - tabletData.deviceId = devices[i].deviceid; - m_tabletData.append(tabletData); - qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType; - } + if (isTablet) { + tabletData.deviceId = deviceInfo->deviceid; + m_tabletData.append(tabletData); + qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType; + } #endif // QT_CONFIG(tabletevent) #ifdef XCB_USE_XINPUT21 - if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { - scrollingDevice.deviceId = devices[i].deviceid; - // Only use legacy wheel button events when we don't have real scroll valuators. - scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; - m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); - qCDebug(lcQpaXInputDevices) << " it's a scrolling device"; - } + if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { + scrollingDevice.deviceId = deviceInfo->deviceid; + // Only use legacy wheel button events when we don't have real scroll valuators. + scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; + m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); + qCDebug(lcQpaXInputDevices) << " it's a scrolling device"; + } #endif - if (!isTablet) { - TouchDeviceData *dev = populateTouchDevices(&devices[i]); - if (dev && lcQpaXInputDevices().isDebugEnabled()) { - if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) - qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d", - dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), - dev->qtTouchDevice->maximumTouchPoints()); - else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad) - qCDebug(lcQpaXInputDevices, " it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", - dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), - dev->qtTouchDevice->maximumTouchPoints(), - dev->size.width(), dev->size.height()); - } + if (!isTablet) { + TouchDeviceData *dev = populateTouchDevices(deviceInfo); + if (dev && lcQpaXInputDevices().isDebugEnabled()) { + if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) + qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints()); + else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + qCDebug(lcQpaXInputDevices, " it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints(), + dev->size.width(), dev->size.height()); } } + +} + +void QXcbConnection::xi2SetupDevices() +{ +#if QT_CONFIG(tabletevent) + m_tabletData.clear(); +#endif + m_scrollingDevices.clear(); + m_touchDevices.clear(); + + Display *xDisplay = static_cast<Display *>(m_xlib_display); + int deviceCount = 0; + XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); + for (int i = 0; i < deviceCount; ++i) { + // Only non-master pointing devices are relevant here. + if (devices[i].use != XISlavePointer) + continue; + xi2SetupDevice(&devices[i], false); + } XIFreeDeviceInfo(devices); } @@ -835,8 +855,16 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) { xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event); switch (xiEvent->reason) { - case XIDeviceChange: + case XIDeviceChange: { + int nrDevices = 0; + Display *dpy = static_cast<Display *>(m_xlib_display); + XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, xiEvent->sourceid, &nrDevices); + if (nrDevices <= 0) + return; + xi2SetupDevice(deviceInfo); + XIFreeDeviceInfo(deviceInfo); break; + } case XISlaveSwitch: { #ifdef XCB_USE_XINPUT21 if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid)) |