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>
This commit is contained in:
Gatis Paeglis 2017-06-08 18:54:53 +02:00
parent 46001e6f49
commit 900abb116d
2 changed files with 183 additions and 154 deletions

View File

@ -547,6 +547,7 @@ private:
bool m_xi2Enabled = false; bool m_xi2Enabled = false;
int m_xi2Minor = -1; int m_xi2Minor = -1;
void initializeXInput2(); void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true);
void xi2SetupDevices(); void xi2SetupDevices();
struct TouchDeviceData { struct TouchDeviceData {
QTouchDevice *qtTouchDevice = nullptr; QTouchDevice *qtTouchDevice = nullptr;

View File

@ -93,28 +93,29 @@ 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) #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 #endif
m_scrollingDevices.clear(); m_scrollingDevices.remove(deviceInfo->deviceid);
m_touchDevices.clear(); m_touchDevices.remove(deviceInfo->deviceid);
}
Display *xDisplay = static_cast<Display *>(m_xlib_display); qCDebug(lcQpaXInputDevices) << "input device " << deviceInfo->name << "ID" << deviceInfo->deviceid;
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;
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
TabletData tabletData; TabletData tabletData;
#endif #endif
ScrollingDevice scrollingDevice; ScrollingDevice scrollingDevice;
for (int c = 0; c < devices[i].num_classes; ++c) { for (int c = 0; c < deviceInfo->num_classes; ++c) {
XIAnyClassInfo *classinfo = devices[i].classes[c]; XIAnyClassInfo *classinfo = deviceInfo->classes[c];
switch (classinfo->type) { switch (classinfo->type) {
case XIValuatorClass: { case XIValuatorClass: {
XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
@ -193,7 +194,7 @@ void QXcbConnection::xi2SetupDevices()
isTablet = true; isTablet = true;
// But we need to be careful not to take the touch and tablet-button devices as tablets. // But we need to be careful not to take the touch and tablet-button devices as tablets.
QByteArray name = QByteArray(devices[i].name).toLower(); QByteArray name = QByteArray(deviceInfo->name).toLower();
QString dbgType = QLatin1String("UNKNOWN"); QString dbgType = QLatin1String("UNKNOWN");
if (name.contains("eraser")) { if (name.contains("eraser")) {
isTablet = true; isTablet = true;
@ -231,7 +232,7 @@ void QXcbConnection::xi2SetupDevices()
} }
if (isTablet) { if (isTablet) {
tabletData.deviceId = devices[i].deviceid; tabletData.deviceId = deviceInfo->deviceid;
m_tabletData.append(tabletData); m_tabletData.append(tabletData);
qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType; qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType;
} }
@ -239,7 +240,7 @@ void QXcbConnection::xi2SetupDevices()
#ifdef XCB_USE_XINPUT21 #ifdef XCB_USE_XINPUT21
if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
scrollingDevice.deviceId = devices[i].deviceid; scrollingDevice.deviceId = deviceInfo->deviceid;
// Only use legacy wheel button events when we don't have real scroll valuators. // Only use legacy wheel button events when we don't have real scroll valuators.
scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
@ -248,7 +249,7 @@ void QXcbConnection::xi2SetupDevices()
#endif #endif
if (!isTablet) { if (!isTablet) {
TouchDeviceData *dev = populateTouchDevices(&devices[i]); TouchDeviceData *dev = populateTouchDevices(deviceInfo);
if (dev && lcQpaXInputDevices().isDebugEnabled()) { if (dev && lcQpaXInputDevices().isDebugEnabled()) {
if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d", qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d",
@ -261,6 +262,25 @@ void QXcbConnection::xi2SetupDevices()
dev->size.width(), dev->size.height()); 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); XIFreeDeviceInfo(devices);
} }
@ -835,8 +855,16 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
{ {
xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event); xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event);
switch (xiEvent->reason) { 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; break;
}
case XISlaveSwitch: { case XISlaveSwitch: {
#ifdef XCB_USE_XINPUT21 #ifdef XCB_USE_XINPUT21
if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid)) if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))