xcb: added env variables to show input devices and events

export QT_XCB_DEBUG_XINPUT_DEVICES=anything to show detected
input devices at startup
export QT_XCB_DEBUG_XINPUT=anything to log mouse, touch and tablet events

Change-Id: Id14844b68ad376740f82a36aab2c59c84d2017ab
Task-number: QTBUG-35583
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Shawn Rutledge 2013-12-23 10:17:06 +01:00 committed by The Qt Project
parent 5ee3d1e456
commit ecf11d62fc
3 changed files with 56 additions and 45 deletions

View File

@ -262,6 +262,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, has_input_shape(false) , has_input_shape(false)
, has_touch_without_mouse_emulation(false) , has_touch_without_mouse_emulation(false)
, has_xkb(false) , has_xkb(false)
, debug_xinput_devices(false)
, debug_xinput(false)
, m_buttons(0) , m_buttons(0)
, m_focusWindow(0) , m_focusWindow(0)
, m_systemTrayTracker(0) , m_systemTrayTracker(0)
@ -749,6 +751,8 @@ void QXcbConnection::handleButtonPress(xcb_generic_event_t *ev)
// the rest we need to manage ourselves // the rest we need to manage ourselves
m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
m_buttons |= translateMouseButton(event->detail); m_buttons |= translateMouseButton(event->detail);
if (Q_UNLIKELY(debug_xinput))
qDebug("xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
} }
void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev) void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
@ -759,6 +763,8 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
// the rest we need to manage ourselves // the rest we need to manage ourselves
m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
m_buttons &= ~translateMouseButton(event->detail); m_buttons &= ~translateMouseButton(event->detail);
if (Q_UNLIKELY(debug_xinput))
qDebug("xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
} }
#ifndef QT_NO_XKB #ifndef QT_NO_XKB
@ -814,6 +820,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleButtonRelease(event); handleButtonRelease(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
case XCB_MOTION_NOTIFY: case XCB_MOTION_NOTIFY:
if (Q_UNLIKELY(debug_xinput)) {
xcb_motion_notify_event_t *mev = (xcb_motion_notify_event_t *)event;
qDebug("xcb: moved mouse to %4d, %4d; button state %X", mev->event_x, mev->event_y, static_cast<unsigned int>(m_buttons));
}
#ifdef QT_NO_XKB #ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state); m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state);
#endif #endif

View File

@ -574,6 +574,8 @@ private:
bool has_input_shape; bool has_input_shape;
bool has_touch_without_mouse_emulation; bool has_touch_without_mouse_emulation;
bool has_xkb; bool has_xkb;
bool debug_xinput_devices;
bool debug_xinput;
Qt::MouseButtons m_buttons; Qt::MouseButtons m_buttons;

View File

@ -44,10 +44,7 @@
#include "qxcbwindow.h" #include "qxcbwindow.h"
#include "qtouchdevice.h" #include "qtouchdevice.h"
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
//#define XI2_DEBUG
#ifdef XI2_DEBUG
#include <QDebug> #include <QDebug>
#endif
#ifdef XCB_USE_XINPUT2 #ifdef XCB_USE_XINPUT2
@ -73,6 +70,8 @@ struct XInput2DeviceData {
void QXcbConnection::initializeXInput2() void QXcbConnection::initializeXInput2()
{ {
debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT");
debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES");
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
m_tabletData.clear(); m_tabletData.clear();
#endif #endif
@ -87,8 +86,11 @@ void QXcbConnection::initializeXInput2()
m_xi2Enabled = true; m_xi2Enabled = true;
} }
if (m_xi2Enabled) { if (m_xi2Enabled) {
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices))
qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); #ifdef XCB_USE_XINPUT22
qDebug("XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor);
#else
qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
#endif #endif
int deviceCount = 0; int deviceCount = 0;
XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
@ -96,9 +98,8 @@ void QXcbConnection::initializeXInput2()
// Only non-master pointing devices are relevant here. // Only non-master pointing devices are relevant here.
if (devices[i].use != XISlavePointer) if (devices[i].use != XISlavePointer)
continue; continue;
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices))
qDebug() << "input device "<< devices[i].name; qDebug() << "input device "<< devices[i].name;
#endif
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
TabletData tabletData; TabletData tabletData;
#endif #endif
@ -107,9 +108,8 @@ void QXcbConnection::initializeXInput2()
case XIValuatorClass: { case XIValuatorClass: {
XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]); XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
const int valuatorAtom = qatom(vci->label); const int valuatorAtom = qatom(vci->label);
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices))
qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
#endif
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
if (valuatorAtom < QXcbAtom::NAtoms) { if (valuatorAtom < QXcbAtom::NAtoms) {
TabletData::ValuatorClassInfo info; TabletData::ValuatorClassInfo info;
@ -136,26 +136,23 @@ void QXcbConnection::initializeXInput2()
tabletData.pointerType = QTabletEvent::Eraser; tabletData.pointerType = QTabletEvent::Eraser;
m_tabletData.append(tabletData); m_tabletData.append(tabletData);
isTablet = true; isTablet = true;
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices))
qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; qDebug() << " it's a tablet with pointer type" << tabletData.pointerType;
#endif
} }
#endif // QT_NO_TABLETEVENT #endif // QT_NO_TABLETEVENT
if (!isTablet) { if (!isTablet) {
XInput2DeviceData *dev = deviceForId(devices[i].deviceid); XInput2DeviceData *dev = deviceForId(devices[i].deviceid);
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices)) {
if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d", qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
dev->qtTouchDevice->maximumTouchPoints()); dev->qtTouchDevice->maximumTouchPoints());
else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad) else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
dev->qtTouchDevice->maximumTouchPoints(), dev->qtTouchDevice->maximumTouchPoints(),
dev->size.width(), dev->size.height()); dev->size.width(), dev->size.height());
#else }
Q_UNUSED(dev);
#endif // XI2_DEBUG
} }
} }
XIFreeDeviceInfo(devices); XIFreeDeviceInfo(devices);
@ -236,9 +233,8 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
case XITouchClass: { case XITouchClass: {
XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo);
maxTouchPoints = tci->num_touches; maxTouchPoints = tci->num_touches;
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput_devices))
qDebug(" has touch class with mode %d", tci->mode); qDebug(" has touch class with mode %d", tci->mode);
#endif
switch (tci->mode) { switch (tci->mode) {
case XIModeRelative: case XIModeRelative:
type = QTouchDevice::TouchPad; type = QTouchDevice::TouchPad;
@ -324,13 +320,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#ifdef XCB_USE_XINPUT22 #ifdef XCB_USE_XINPUT22
if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput))
qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f", qDebug("XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f",
event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail,
xiDeviceEvent->event_x, xiDeviceEvent->event_y, fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
#endif
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
XInput2DeviceData *dev = deviceForId(xiEvent->deviceid); XInput2DeviceData *dev = deviceForId(xiEvent->deviceid);
@ -356,10 +350,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
double value; double value;
if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value))
continue; continue;
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput))
qDebug(" valuator %20s value %lf from range %lf -> %lf", qDebug(" valuator %20s value %lf from range %lf -> %lf",
atomName(vci->label).constData(), value, vci->min, vci->max ); atomName(vci->label).constData(), value, vci->min, vci->max );
#endif
if (vci->label == atom(QXcbAtom::RelX)) { if (vci->label == atom(QXcbAtom::RelX)) {
nx = valuatorNormalized(value, vci); nx = valuatorNormalized(value, vci);
} else if (vci->label == atom(QXcbAtom::RelY)) { } else if (vci->label == atom(QXcbAtom::RelY)) {
@ -435,10 +428,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
touchPoint.normalPosition = QPointF(nx, ny); touchPoint.normalPosition = QPointF(nx, ny);
#ifdef XI2_DEBUG if (Q_UNLIKELY(debug_xinput))
qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << qDebug() << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
" area " << touchPoint.area << " pressure " << touchPoint.pressure; " area " << touchPoint.area << " pressure " << touchPoint.pressure;
#endif
QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values()); QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values());
if (touchPoint.state == Qt::TouchPointReleased) if (touchPoint.state == Qt::TouchPointReleased)
// If a touchpoint was released, we can forget it, because the ID won't be reused. // If a touchpoint was released, we can forget it, because the ID won't be reused.
@ -560,6 +552,13 @@ void QXcbConnection::xi2ReportTabletEvent(const TabletData &tabletData, void *ev
} }
} }
if (Q_UNLIKELY(debug_xinput))
qDebug("XI2 tablet event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f pressure %4.2lf tilt %d, %d rotation %6.2lf",
ev->type, ev->sequenceNumber, ev->detail,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
pressure, xTilt, yTilt, rotation);
QWindowSystemInterface::handleTabletEvent(window, tabletData.down, local, global, QWindowSystemInterface::handleTabletEvent(window, tabletData.down, local, global,
QTabletEvent::Stylus, tabletData.pointerType, QTabletEvent::Stylus, tabletData.pointerType,
pressure, xTilt, yTilt, 0, pressure, xTilt, yTilt, 0,