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
parent
f9d323279a
commit
55d1aa3121
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue