57 #include "MouseTouchAdaptor.h"
59 #include <qpa/qplatformnativeinterface.h>
60 #include <qpa/qwindowsysteminterface.h>
62 #include <QCoreApplication>
63 #include <QMouseEvent>
66 #include <X11/extensions/XInput2.h>
67 #include <X11/extensions/XI2proto.h>
69 using QTest::QTouchEventSequence;
72 MouseTouchAdaptor *g_instance =
nullptr;
74 Qt::MouseButton translateMouseButton(xcb_button_t detail)
77 case 1:
return Qt::LeftButton;
78 case 2:
return Qt::MidButton;
79 case 3:
return Qt::RightButton;
81 default:
return Qt::NoButton;
86 MouseTouchAdaptor::MouseTouchAdaptor()
87 : QObject(nullptr), m_leftButtonIsPressed(false), m_enabled(true)
89 QCoreApplication::instance()->installNativeEventFilter(
this);
91 m_touchDevice =
new QTouchDevice;
92 m_touchDevice->setType(QTouchDevice::TouchScreen);
93 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
98 MouseTouchAdaptor::~MouseTouchAdaptor()
100 g_instance =
nullptr;
103 MouseTouchAdaptor* MouseTouchAdaptor::instance()
106 g_instance =
new MouseTouchAdaptor;
112 void MouseTouchAdaptor::fetchXInput2Info()
114 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
115 Display *xDisplay =
static_cast<Display*
>(nativeInterface->nativeResourceForIntegration(
"Display"));
116 if (xDisplay && XQueryExtension(xDisplay,
"XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
119 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
121 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
123 m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest;
138 typedef struct qt_xcb_ge_event_t {
139 uint8_t response_type;
146 bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev,
int opCode)
148 qt_xcb_ge_event_t *
event = (qt_xcb_ge_event_t *)ev;
151 if (event->extension == opCode) {
156 memmove((
char*) event + 32, (
char*) event + 36, event->length * 4);
162 static inline qreal fixed1616ToReal(FP1616 val)
164 return qreal(val) / 0x10000;
167 bool MouseTouchAdaptor::xi2HandleEvent(xcb_ge_event_t *event)
169 if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
173 xXIGenericDeviceEvent *xiEvent =
reinterpret_cast<xXIGenericDeviceEvent *
>(event);
174 xXIDeviceEvent *xiDeviceEvent = 0;
176 switch (xiEvent->evtype) {
178 case XI_ButtonRelease:
180 xiDeviceEvent =
reinterpret_cast<xXIDeviceEvent *
>(event);
186 if (!xiDeviceEvent) {
190 switch (xiDeviceEvent->evtype) {
192 return handleButtonPress(
193 static_cast<WId>(xiDeviceEvent->event),
194 xiDeviceEvent->detail,
195 fixed1616ToReal(xiDeviceEvent->event_x),
196 fixed1616ToReal(xiDeviceEvent->event_y));
197 case XI_ButtonRelease:
198 return handleButtonRelease(
199 static_cast<WId>(xiDeviceEvent->event),
200 xiDeviceEvent->detail,
201 fixed1616ToReal(xiDeviceEvent->event_x),
202 fixed1616ToReal(xiDeviceEvent->event_y));
204 return handleMotionNotify(
205 static_cast<WId>(xiDeviceEvent->event),
206 fixed1616ToReal(xiDeviceEvent->event_x),
207 fixed1616ToReal(xiDeviceEvent->event_y));
215 bool MouseTouchAdaptor::nativeEventFilter(
const QByteArray & eventType,
216 void * message,
long * )
218 static int eventCount = 0;
224 if (eventType !=
"xcb_generic_event_t") {
226 qWarning(
"MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
230 xcb_generic_event_t *xcbEvent =
static_cast<xcb_generic_event_t *
>(message);
232 switch (xcbEvent->response_type & ~0x80) {
233 case XCB_BUTTON_PRESS: {
234 auto pressEvent =
reinterpret_cast<xcb_button_press_event_t *
>(xcbEvent);
235 return handleButtonPress(static_cast<WId>(pressEvent->event), pressEvent->detail,
236 pressEvent->event_x, pressEvent->event_y);
238 case XCB_BUTTON_RELEASE: {
239 auto releaseEvent =
reinterpret_cast<xcb_button_release_event_t *
>(xcbEvent);
240 return handleButtonRelease(static_cast<WId>(releaseEvent->event), releaseEvent->detail,
241 releaseEvent->event_x, releaseEvent->event_y);
243 case XCB_MOTION_NOTIFY: {
244 auto motionEvent =
reinterpret_cast<xcb_motion_notify_event_t *
>(xcbEvent);
245 return handleMotionNotify(static_cast<WId>(motionEvent->event), motionEvent->event_x, motionEvent->event_y);
249 return xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(xcbEvent));
258 bool MouseTouchAdaptor::handleButtonPress(WId windowId, uint32_t detail,
int x,
int y)
260 Qt::MouseButton button = translateMouseButton(detail);
263 if (button != Qt::LeftButton)
266 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
268 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
270 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
272 touchEvent.press(0 , windowPos);
273 touchEvent.commit(
false );
275 m_leftButtonIsPressed =
true;
279 bool MouseTouchAdaptor::handleButtonRelease(WId windowId, uint32_t detail,
int x,
int y)
281 Qt::MouseButton button = translateMouseButton(detail);
284 if (button != Qt::LeftButton)
287 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
289 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
291 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
293 touchEvent.release(0 , windowPos);
294 touchEvent.commit(
false );
296 m_leftButtonIsPressed =
false;
300 bool MouseTouchAdaptor::handleMotionNotify(WId windowId,
int x,
int y)
302 if (!m_leftButtonIsPressed) {
306 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
308 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
310 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
312 touchEvent.move(0 , windowPos);
313 touchEvent.commit(
false );
318 QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
320 QWindowList windowList = QGuiApplication::topLevelWindows();
321 QWindow *foundWindow =
nullptr;
324 while (!foundWindow && i < windowList.count()) {
325 QWindow *window = windowList[i];
326 if (window->winId() == windowId) {
327 foundWindow = window;
333 Q_ASSERT(foundWindow);
337 bool MouseTouchAdaptor::enabled()
const
342 void MouseTouchAdaptor::setEnabled(
bool value)
344 if (value != m_enabled) {
346 Q_EMIT enabledChanged(value);