Support hotplugging of input devices with XInput2
Since we only scan for XInput2 devices on application start, we will currently miss any devices plugged in while the application is running. This patch makes QXcbConnection listen for XInput2 hierachyChanged events and use them to trigger a rescan of XInput2 devices. This fixes a regression in Qt 5.3, where the scroll wheel on hot- plugged mice does not work until the Qt application is restarted. Change-Id: I2cdc7ca24d3ab00716cedc4b22355b6e4935b184 Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
parent
02b7b21f9b
commit
da5dea807f
@ -496,8 +496,10 @@ private:
|
|||||||
#ifdef XCB_USE_XINPUT2
|
#ifdef XCB_USE_XINPUT2
|
||||||
void initializeXInput2();
|
void initializeXInput2();
|
||||||
void finalizeXInput2();
|
void finalizeXInput2();
|
||||||
|
void xi2SetupDevices();
|
||||||
XInput2DeviceData *deviceForId(int id);
|
XInput2DeviceData *deviceForId(int id);
|
||||||
void xi2HandleEvent(xcb_ge_event_t *event);
|
void xi2HandleEvent(xcb_ge_event_t *event);
|
||||||
|
void xi2HandleHierachyEvent(void *event);
|
||||||
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
|
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
|
||||||
#ifndef QT_NO_TABLETEVENT
|
#ifndef QT_NO_TABLETEVENT
|
||||||
struct TabletData {
|
struct TabletData {
|
||||||
|
@ -73,10 +73,6 @@ void QXcbConnection::initializeXInput2()
|
|||||||
{
|
{
|
||||||
debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT");
|
debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT");
|
||||||
debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES");
|
debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES");
|
||||||
#ifndef QT_NO_TABLETEVENT
|
|
||||||
m_tabletData.clear();
|
|
||||||
#endif
|
|
||||||
m_scrollingDevices.clear();
|
|
||||||
Display *xDisplay = static_cast<Display *>(m_xlib_display);
|
Display *xDisplay = static_cast<Display *>(m_xlib_display);
|
||||||
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
|
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
|
||||||
int xiMajor = 2;
|
int xiMajor = 2;
|
||||||
@ -97,6 +93,23 @@ void QXcbConnection::initializeXInput2()
|
|||||||
#else
|
#else
|
||||||
qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
|
qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
xi2SetupDevices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QXcbConnection::xi2SetupDevices()
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_TABLETEVENT
|
||||||
|
m_tabletData.clear();
|
||||||
|
#endif
|
||||||
|
m_scrollingDevices.clear();
|
||||||
|
|
||||||
|
if (!m_xi2Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Display *xDisplay = static_cast<Display *>(m_xlib_display);
|
||||||
int deviceCount = 0;
|
int deviceCount = 0;
|
||||||
XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
|
XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
|
||||||
for (int i = 0; i < deviceCount; ++i) {
|
for (int i = 0; i < deviceCount; ++i) {
|
||||||
@ -211,8 +224,6 @@ void QXcbConnection::initializeXInput2()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
XIFreeDeviceInfo(devices);
|
XIFreeDeviceInfo(devices);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbConnection::finalizeXInput2()
|
void QXcbConnection::finalizeXInput2()
|
||||||
@ -303,6 +314,16 @@ void QXcbConnection::xi2Select(xcb_window_t window)
|
|||||||
#else
|
#else
|
||||||
Q_UNUSED(xiBitMask);
|
Q_UNUSED(xiBitMask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
// Listen for hotplug events
|
||||||
|
XIEventMask xiEventMask;
|
||||||
|
bitMask = XI_HierarchyChangedMask;
|
||||||
|
xiEventMask.deviceid = XIAllDevices;
|
||||||
|
xiEventMask.mask_len = sizeof(bitMask);
|
||||||
|
xiEventMask.mask = xiBitMask;
|
||||||
|
XISelectEvents(xDisplay, window, &xiEventMask, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XInput2DeviceData *QXcbConnection::deviceForId(int id)
|
XInput2DeviceData *QXcbConnection::deviceForId(int id)
|
||||||
@ -402,6 +423,10 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
|
|||||||
if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
|
if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
|
||||||
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
|
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
|
||||||
|
|
||||||
|
if (xiEvent->evtype == XI_HierarchyChanged) {
|
||||||
|
xi2HandleHierachyEvent(xiEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
#ifndef QT_NO_TABLETEVENT
|
#ifndef QT_NO_TABLETEVENT
|
||||||
for (int i = 0; i < m_tabletData.count(); ++i) {
|
for (int i = 0; i < m_tabletData.count(); ++i) {
|
||||||
if (m_tabletData.at(i).deviceId == xiEvent->deviceid) {
|
if (m_tabletData.at(i).deviceId == xiEvent->deviceid) {
|
||||||
@ -561,6 +586,19 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QXcbConnection::xi2HandleHierachyEvent(void *event)
|
||||||
|
{
|
||||||
|
xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event);
|
||||||
|
// We only care about hotplugged devices
|
||||||
|
if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded)))
|
||||||
|
return;
|
||||||
|
xi2SetupDevices();
|
||||||
|
// Reselect events for all event-listening windows.
|
||||||
|
Q_FOREACH (xcb_window_t window, m_mapper.keys()) {
|
||||||
|
xi2Select(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
|
void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
|
||||||
{
|
{
|
||||||
#ifdef XCB_USE_XINPUT21
|
#ifdef XCB_USE_XINPUT21
|
||||||
|
Loading…
x
Reference in New Issue
Block a user