Scrolling devices should not override touch or tablet devices

XISelectEvents override any earlier set event mask for the same device
ids. This may cause touch devices to stop reporting touch events if they
export scroll buttons or axis.

The patch checks for each scrolling device if they are also a touch
devices and includes the necessary bitmask if they are, and skips
any devices also recognized as tablet devices as they already capture
all relevant events.

In addition tablet event handling will no longer block handling of wheel
button events for scroll devices with the same device id.

Task-number: QTBUG-38935
Change-Id: Ifd4657beb0a0cebffe89d3470ef2bd605eb3552e
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
This commit is contained in:
Allan Sandfeld Jensen 2014-05-12 15:45:24 +02:00 committed by The Qt Project
parent 7cc175c9d6
commit a8877f529d

View File

@ -248,6 +248,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
} }
#endif // XCB_USE_XINPUT22 #endif // XCB_USE_XINPUT22
QSet<int> tabletDevices;
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
// For each tablet, select some additional event types. // For each tablet, select some additional event types.
// Press, motion, etc. events must never be selected for _all_ devices // Press, motion, etc. events must never be selected for _all_ devices
@ -255,15 +256,19 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// similar handlers useless and we have no intention to infect // similar handlers useless and we have no intention to infect
// all the pure xcb code with Xlib-based XI2. // all the pure xcb code with Xlib-based XI2.
if (!m_tabletData.isEmpty()) { if (!m_tabletData.isEmpty()) {
unsigned int tabletBitMask = bitMask;
unsigned char *xiTabletBitMask = reinterpret_cast<unsigned char *>(&tabletBitMask);
QVector<XIEventMask> xiEventMask(m_tabletData.count()); QVector<XIEventMask> xiEventMask(m_tabletData.count());
bitMask |= XI_ButtonPressMask; tabletBitMask |= XI_ButtonPressMask;
bitMask |= XI_ButtonReleaseMask; tabletBitMask |= XI_ButtonReleaseMask;
bitMask |= XI_MotionMask; tabletBitMask |= XI_MotionMask;
bitMask |= XI_PropertyEventMask; tabletBitMask |= XI_PropertyEventMask;
for (int i = 0; i < m_tabletData.count(); ++i) { for (int i = 0; i < m_tabletData.count(); ++i) {
xiEventMask[i].deviceid = m_tabletData.at(i).deviceId; int deviceId = m_tabletData.at(i).deviceId;
xiEventMask[i].mask_len = sizeof(bitMask); tabletDevices.insert(deviceId);
xiEventMask[i].mask = xiBitMask; xiEventMask[i].deviceid = deviceId;
xiEventMask[i].mask_len = sizeof(tabletBitMask);
xiEventMask[i].mask = xiTabletBitMask;
} }
XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count()); XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count());
} }
@ -273,17 +278,30 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// Enable each scroll device // Enable each scroll device
if (!m_scrollingDevices.isEmpty()) { if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size()); QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
bitMask = XI_MotionMask; unsigned int scrollBitMask = 0;
unsigned char *xiScrollBitMask = reinterpret_cast<unsigned char *>(&scrollBitMask);
scrollBitMask = XI_MotionMask;
scrollBitMask |= XI_ButtonReleaseMask;
bitMask |= XI_MotionMask;
bitMask |= XI_ButtonReleaseMask; bitMask |= XI_ButtonReleaseMask;
int i=0; int i=0;
Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
xiEventMask[i].deviceid = scrollingDevice.deviceId; xiEventMask[i].deviceid = scrollingDevice.deviceId;
if (m_touchDevices.contains(scrollingDevice.deviceId)) {
xiEventMask[i].mask_len = sizeof(bitMask); xiEventMask[i].mask_len = sizeof(bitMask);
xiEventMask[i].mask = xiBitMask; xiEventMask[i].mask = xiBitMask;
} else {
xiEventMask[i].mask_len = sizeof(scrollBitMask);
xiEventMask[i].mask = xiScrollBitMask;
}
i++; i++;
} }
XISelectEvents(xDisplay, window, xiEventMask.data(), m_scrollingDevices.size()); XISelectEvents(xDisplay, window, xiEventMask.data(), i);
} }
#else
Q_UNUSED(xiBitMask);
#endif #endif
} }
@ -657,13 +675,15 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus
tabletData->down = true; tabletData->down = true;
xi2ReportTabletEvent(*tabletData, xiEvent); xi2ReportTabletEvent(*tabletData, xiEvent);
} } else
handled = false;
break; break;
case XI_ButtonRelease: // stylus up case XI_ButtonRelease: // stylus up
if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) {
tabletData->down = false; tabletData->down = false;
xi2ReportTabletEvent(*tabletData, xiEvent); xi2ReportTabletEvent(*tabletData, xiEvent);
} } else
handled = false;
break; break;
case XI_Motion: case XI_Motion:
// Report TabletMove only when the stylus is touching the tablet. // Report TabletMove only when the stylus is touching the tablet.