57#include "MouseTouchAdaptor.h"
59#include <qpa/qplatformnativeinterface.h>
60#include <qpa/qwindowsysteminterface.h>
62#include <QCoreApplication>
66#include <X11/extensions/XInput2.h>
67#include <X11/extensions/XI2proto.h>
69using QTest::QTouchEventSequence;
72MouseTouchAdaptor *g_instance =
nullptr;
74const Qt::KeyboardModifiers TRI_PRESS_MODIFIER = Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier;
75const Qt::KeyboardModifiers QUAD_PRESS_MODIFIER = TRI_PRESS_MODIFIER|Qt::MetaModifier;
77Qt::MouseButton translateMouseButton(xcb_button_t detail)
80 case 1:
return Qt::LeftButton;
81 case 2:
return Qt::MidButton;
82 case 3:
return Qt::RightButton;
84 default:
return Qt::NoButton;
88Qt::KeyboardModifiers translateMofidier(uint32_t mod)
90 Qt::KeyboardModifiers qtMod = Qt::NoModifier;
92 if (mod & 0x01) qtMod |= Qt::ShiftModifier;
93 if (mod & 0x04) qtMod |= Qt::ControlModifier;
94 if (mod & 0x08) qtMod |= Qt::AltModifier;
95 if (mod & 0x40) qtMod |= Qt::MetaModifier;
101MouseTouchAdaptor::MouseTouchAdaptor()
103 , m_leftButtonIsPressed(false)
104 , m_triPressModifier(false)
105 , m_quadPressModifier(false)
108 QCoreApplication::instance()->installNativeEventFilter(
this);
110 m_touchDevice =
new QTouchDevice;
111 m_touchDevice->setType(QTouchDevice::TouchScreen);
112 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
117MouseTouchAdaptor::~MouseTouchAdaptor()
119 g_instance =
nullptr;
122MouseTouchAdaptor* MouseTouchAdaptor::instance()
125 g_instance =
new MouseTouchAdaptor;
131void MouseTouchAdaptor::fetchXInput2Info()
133 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
134 Display *xDisplay =
static_cast<Display*
>(nativeInterface->nativeResourceForIntegration(
"Display"));
135 if (xDisplay && XQueryExtension(xDisplay,
"XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
138 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
140 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
142 m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest;
157typedef struct qt_xcb_ge_event_t {
158 uint8_t response_type;
165bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev,
int opCode)
167 qt_xcb_ge_event_t *
event = (qt_xcb_ge_event_t *)ev;
170 if (event->extension == opCode) {
175 memmove((
char*) event + 32, (
char*) event + 36, event->length * 4);
181static inline qreal fixed1616ToReal(FP1616 val)
183 return qreal(val) / 0x10000;
186bool MouseTouchAdaptor::xi2HandleEvent(xcb_ge_event_t *event)
188 if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
192 xXIGenericDeviceEvent *xiEvent =
reinterpret_cast<xXIGenericDeviceEvent *
>(event);
193 xXIDeviceEvent *xiDeviceEvent = 0;
195 switch (xiEvent->evtype) {
197 case XI_ButtonRelease:
199 xiDeviceEvent =
reinterpret_cast<xXIDeviceEvent *
>(event);
205 if (!xiDeviceEvent) {
209 switch (xiDeviceEvent->evtype) {
211 return handleButtonPress(
212 static_cast<WId
>(xiDeviceEvent->event),
213 xiDeviceEvent->detail,
214 xiDeviceEvent->mods.base_mods,
215 fixed1616ToReal(xiDeviceEvent->event_x),
216 fixed1616ToReal(xiDeviceEvent->event_y));
217 case XI_ButtonRelease:
218 return handleButtonRelease(
219 static_cast<WId
>(xiDeviceEvent->event),
220 xiDeviceEvent->detail,
221 xiDeviceEvent->mods.base_mods,
222 fixed1616ToReal(xiDeviceEvent->event_x),
223 fixed1616ToReal(xiDeviceEvent->event_y));
225 return handleMotionNotify(
226 static_cast<WId
>(xiDeviceEvent->event),
227 xiDeviceEvent->mods.base_mods,
228 fixed1616ToReal(xiDeviceEvent->event_x),
229 fixed1616ToReal(xiDeviceEvent->event_y));
237bool MouseTouchAdaptor::nativeEventFilter(
const QByteArray & eventType,
238 void * message,
long * )
240 static int eventCount = 0;
246 if (eventType !=
"xcb_generic_event_t") {
248 qWarning(
"MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
252 xcb_generic_event_t *xcbEvent =
static_cast<xcb_generic_event_t *
>(message);
254 switch (xcbEvent->response_type & ~0x80) {
255 case XCB_BUTTON_PRESS: {
256 auto pressEvent =
reinterpret_cast<xcb_button_press_event_t *
>(xcbEvent);
257 return handleButtonPress(
static_cast<WId
>(pressEvent->event), pressEvent->detail, 0,
258 pressEvent->event_x, pressEvent->event_y);
260 case XCB_BUTTON_RELEASE: {
261 auto releaseEvent =
reinterpret_cast<xcb_button_release_event_t *
>(xcbEvent);
262 return handleButtonRelease(
static_cast<WId
>(releaseEvent->event), releaseEvent->detail, 0,
263 releaseEvent->event_x, releaseEvent->event_y);
265 case XCB_MOTION_NOTIFY: {
266 auto motionEvent =
reinterpret_cast<xcb_motion_notify_event_t *
>(xcbEvent);
267 return handleMotionNotify(
static_cast<WId
>(motionEvent->event), 0,
268 motionEvent->event_x, motionEvent->event_y);
272 return xi2HandleEvent(
reinterpret_cast<xcb_ge_event_t *
>(xcbEvent));
281bool MouseTouchAdaptor::handleButtonPress(WId windowId, uint32_t detail, uint32_t modifiers,
int x,
int y)
283 Qt::MouseButton button = translateMouseButton(detail);
284 Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
287 if (button != Qt::LeftButton)
290 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
292 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
294 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
296 touchEvent.press(0 , windowPos);
297 if (qtMod == TRI_PRESS_MODIFIER) {
298 touchEvent.press(1, windowPos);
299 touchEvent.press(2, windowPos);
300 m_triPressModifier =
true;
302 if (qtMod == QUAD_PRESS_MODIFIER) {
303 touchEvent.press(1, windowPos);
304 touchEvent.press(2, windowPos);
305 touchEvent.press(3, windowPos);
306 m_quadPressModifier =
true;
309 touchEvent.commit(
false );
311 m_leftButtonIsPressed =
true;
315bool MouseTouchAdaptor::handleButtonRelease(WId windowId, uint32_t detail, uint32_t,
int x,
int y)
317 Qt::MouseButton button = translateMouseButton(detail);
320 if (button != Qt::LeftButton)
323 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
325 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
327 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
329 touchEvent.release(0 , windowPos);
330 if (m_triPressModifier) {
331 touchEvent.release(1, windowPos);
332 touchEvent.release(2, windowPos);
334 if (m_quadPressModifier) {
335 touchEvent.release(1, windowPos);
336 touchEvent.release(2, windowPos);
337 touchEvent.release(3, windowPos);
339 touchEvent.commit(
false );
341 m_leftButtonIsPressed =
false;
342 m_triPressModifier =
false;
343 m_quadPressModifier =
false;
347bool MouseTouchAdaptor::handleMotionNotify(WId windowId, uint32_t modifiers,
int x,
int y)
349 if (!m_leftButtonIsPressed) {
352 Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
354 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
356 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
358 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
360 touchEvent.move(0 , windowPos);
361 if (m_triPressModifier) {
362 if (qtMod == TRI_PRESS_MODIFIER) {
363 touchEvent.move(1, windowPos);
364 touchEvent.move(2, windowPos);
367 touchEvent.release(1, windowPos);
368 touchEvent.release(2, windowPos);
369 m_triPressModifier =
false;
372 if (m_quadPressModifier) {
373 if (qtMod == QUAD_PRESS_MODIFIER) {
374 touchEvent.move(1, windowPos);
375 touchEvent.move(2, windowPos);
376 touchEvent.move(3, windowPos);
378 touchEvent.release(1, windowPos);
379 touchEvent.release(2, windowPos);
380 touchEvent.release(3, windowPos);
381 m_quadPressModifier =
false;
384 touchEvent.commit(
false );
389QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
391 QWindowList windowList = QGuiApplication::topLevelWindows();
392 QWindow *foundWindow =
nullptr;
395 while (!foundWindow && i < windowList.count()) {
396 QWindow *window = windowList[i];
397 if (window->winId() == windowId) {
398 foundWindow = window;
404 Q_ASSERT(foundWindow);
408bool MouseTouchAdaptor::enabled()
const
413void MouseTouchAdaptor::setEnabled(
bool value)
415 if (value != m_enabled) {
417 Q_EMIT enabledChanged(value);