Use runtime detection of XInput 2.1 to disable legacy wheel events

Ensure we fall back to using wheel button events if xinput 2.1
scroll events are not available. Handles lack of xinput 2.1
support in the server or in the input devices drivers.

Task-number: QTBUG-38169
Change-Id: Ie4ad9069f648d0ab02d8f9540ed01ad58fd9e9d8
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
bb10
Allan Sandfeld Jensen 2014-04-24 14:53:50 +02:00 committed by The Qt Project
parent f9d323279a
commit 55d1aa3121
4 changed files with 75 additions and 12 deletions

View File

@ -1791,6 +1791,19 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub
return true;
}
bool QXcbConnection::xi2GetButtonState(void *event, int buttonNum)
{
xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event);
unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1];
for (int i = 0; i < (xideviceevent->buttons_len * 4); i++) {
if (buttonNum < 8)
return (buttonsMaskAddr[i] & (1 << buttonNum));
buttonNum -= 8;
}
return false;
}
// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
// - "pad0" became "extension"
// - "pad1" and "pad" became "pad0"

View File

@ -402,6 +402,12 @@ public:
#elif defined(XCB_USE_XINPUT2)
void xi2Select(xcb_window_t window);
#endif
#ifdef XCB_USE_XINPUT21
bool isUsingXInput21() { return m_xi2Enabled && m_xi2Minor >= 1; }
#else
bool isUsingXInput21() { return false; }
#endif
void sync();
void flush() { xcb_flush(m_connection); }
@ -511,11 +517,12 @@ private:
QVector<TabletData> m_tabletData;
#endif
struct ScrollingDevice {
ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0) { }
ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { }
int deviceId;
int verticalIndex, horizontalIndex;
double verticalIncrement, horizontalIncrement;
Qt::Orientations orientations;
Qt::Orientations legacyOrientations;
QPointF lastScrollPosition;
};
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
@ -525,6 +532,7 @@ private:
#if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO)
static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value);
static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode);
static bool xi2GetButtonState(void *event, int buttonNum);
#endif
xcb_connection_t *m_connection;

View File

@ -134,7 +134,6 @@ void QXcbConnection::initializeXInput2()
#ifdef XCB_USE_XINPUT21
case XIScrollClass: {
XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]);
scrollingDevice.deviceId = devices[i].deviceid;
if (sci->scroll_type == XIScrollTypeVertical) {
scrollingDevice.orientations |= Qt::Vertical;
scrollingDevice.verticalIndex = sci->number;
@ -147,6 +146,20 @@ void QXcbConnection::initializeXInput2()
}
break;
}
case XIButtonClass: {
XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
for (int i=0; i < bci->num_buttons; ++i) {
const int buttonAtom = qatom(bci->labels[i]);
if (buttonAtom == QXcbAtom::ButtonWheelUp
|| buttonAtom == QXcbAtom::ButtonWheelDown) {
scrollingDevice.legacyOrientations |= Qt::Vertical;
} else if (buttonAtom == QXcbAtom::ButtonHorizWheelLeft
|| buttonAtom == QXcbAtom::ButtonHorizWheelRight) {
scrollingDevice.legacyOrientations |= Qt::Horizontal;
}
}
break;
}
#endif
default:
break;
@ -170,7 +183,10 @@ void QXcbConnection::initializeXInput2()
#endif // QT_NO_TABLETEVENT
#ifdef XCB_USE_XINPUT21
if (scrollingDevice.orientations) {
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);
if (Q_UNLIKELY(debug_xinput_devices))
qDebug() << " it's a scrolling device";
@ -256,6 +272,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
bitMask = XI_MotionMask;
bitMask |= XI_ButtonReleaseMask;
int i=0;
Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
xiEventMask[i].deviceid = scrollingDevice.deviceId;
@ -595,6 +612,31 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
} else if (xiEvent->evtype == XI_ButtonRelease) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint angleDelta;
if (scrollingDevice.legacyOrientations & Qt::Vertical) {
if (xi2GetButtonState(xiDeviceEvent, 4))
angleDelta.setY(120);
else if (xi2GetButtonState(xiDeviceEvent, 5))
angleDelta.setY(-120);
}
if (scrollingDevice.legacyOrientations & Qt::Horizontal) {
if (xi2GetButtonState(xiDeviceEvent, 6))
angleDelta.setX(120);
if (xi2GetButtonState(xiDeviceEvent, 7))
angleDelta.setX(-120);
}
if (!angleDelta.isNull()) {
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers);
}
}
}
#else
Q_UNUSED(event);

View File

@ -1705,16 +1705,16 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
if (isWheel) {
#ifndef XCB_USE_XINPUT21
// Logic borrowed from qapplication_x11.cpp
int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
bool hor = (((event->detail == 4 || event->detail == 5)
&& (modifiers & Qt::AltModifier))
|| (event->detail == 6 || event->detail == 7));
if (!connection()->isUsingXInput21()) {
// Logic borrowed from qapplication_x11.cpp
int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
bool hor = (((event->detail == 4 || event->detail == 5)
&& (modifiers & Qt::AltModifier))
|| (event->detail == 6 || event->detail == 7));
QWindowSystemInterface::handleWheelEvent(window(), event->time,
local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers);
#endif
QWindowSystemInterface::handleWheelEvent(window(), event->time,
local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers);
}
return;
}