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 const Qt::KeyboardModifiers TRI_PRESS_MODIFIER = Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier;
76 Qt::MouseButton translateMouseButton(xcb_button_t detail)
79 case 1:
return Qt::LeftButton;
80 case 2:
return Qt::MidButton;
81 case 3:
return Qt::RightButton;
83 default:
return Qt::NoButton;
87 Qt::KeyboardModifiers translateMofidier(uint32_t mod)
89 Qt::KeyboardModifiers qtMod = Qt::NoModifier;
91 if (mod & 0x01) qtMod |= Qt::ShiftModifier;
92 if (mod & 0x04) qtMod |= Qt::ControlModifier;
93 if (mod & 0x08) qtMod |= Qt::AltModifier;
94 if (mod & 0x80) qtMod |= Qt::MetaModifier;
100 MouseTouchAdaptor::MouseTouchAdaptor()
102 , m_leftButtonIsPressed(false)
103 , m_triPressModifier(false)
106 QCoreApplication::instance()->installNativeEventFilter(
this);
108 m_touchDevice =
new QTouchDevice;
109 m_touchDevice->setType(QTouchDevice::TouchScreen);
110 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
115 MouseTouchAdaptor::~MouseTouchAdaptor()
117 g_instance =
nullptr;
120 MouseTouchAdaptor* MouseTouchAdaptor::instance()
123 g_instance =
new MouseTouchAdaptor;
129 void MouseTouchAdaptor::fetchXInput2Info()
131 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
132 Display *xDisplay =
static_cast<Display*
>(nativeInterface->nativeResourceForIntegration(
"Display"));
133 if (xDisplay && XQueryExtension(xDisplay,
"XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
136 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
138 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
140 m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest;
155 typedef struct qt_xcb_ge_event_t {
156 uint8_t response_type;
163 bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev,
int opCode)
165 qt_xcb_ge_event_t *
event = (qt_xcb_ge_event_t *)ev;
168 if (event->extension == opCode) {
173 memmove((
char*) event + 32, (
char*) event + 36, event->length * 4);
179 static inline qreal fixed1616ToReal(FP1616 val)
181 return qreal(val) / 0x10000;
184 bool MouseTouchAdaptor::xi2HandleEvent(xcb_ge_event_t *event)
186 if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
190 xXIGenericDeviceEvent *xiEvent =
reinterpret_cast<xXIGenericDeviceEvent *
>(event);
191 xXIDeviceEvent *xiDeviceEvent = 0;
193 switch (xiEvent->evtype) {
195 case XI_ButtonRelease:
197 xiDeviceEvent =
reinterpret_cast<xXIDeviceEvent *
>(event);
203 if (!xiDeviceEvent) {
207 switch (xiDeviceEvent->evtype) {
209 return handleButtonPress(
210 static_cast<WId>(xiDeviceEvent->event),
211 xiDeviceEvent->detail,
212 xiDeviceEvent->mods.base_mods,
213 fixed1616ToReal(xiDeviceEvent->event_x),
214 fixed1616ToReal(xiDeviceEvent->event_y));
215 case XI_ButtonRelease:
216 return handleButtonRelease(
217 static_cast<WId>(xiDeviceEvent->event),
218 xiDeviceEvent->detail,
219 xiDeviceEvent->mods.base_mods,
220 fixed1616ToReal(xiDeviceEvent->event_x),
221 fixed1616ToReal(xiDeviceEvent->event_y));
223 return handleMotionNotify(
224 static_cast<WId>(xiDeviceEvent->event),
225 xiDeviceEvent->mods.base_mods,
226 fixed1616ToReal(xiDeviceEvent->event_x),
227 fixed1616ToReal(xiDeviceEvent->event_y));
235 bool MouseTouchAdaptor::nativeEventFilter(
const QByteArray & eventType,
236 void * message,
long * )
238 static int eventCount = 0;
244 if (eventType !=
"xcb_generic_event_t") {
246 qWarning(
"MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
250 xcb_generic_event_t *xcbEvent =
static_cast<xcb_generic_event_t *
>(message);
252 switch (xcbEvent->response_type & ~0x80) {
253 case XCB_BUTTON_PRESS: {
254 auto pressEvent =
reinterpret_cast<xcb_button_press_event_t *
>(xcbEvent);
255 return handleButtonPress(static_cast<WId>(pressEvent->event), pressEvent->detail, 0,
256 pressEvent->event_x, pressEvent->event_y);
258 case XCB_BUTTON_RELEASE: {
259 auto releaseEvent =
reinterpret_cast<xcb_button_release_event_t *
>(xcbEvent);
260 return handleButtonRelease(static_cast<WId>(releaseEvent->event), releaseEvent->detail, 0,
261 releaseEvent->event_x, releaseEvent->event_y);
263 case XCB_MOTION_NOTIFY: {
264 auto motionEvent =
reinterpret_cast<xcb_motion_notify_event_t *
>(xcbEvent);
265 return handleMotionNotify(static_cast<WId>(motionEvent->event), 0,
266 motionEvent->event_x, motionEvent->event_y);
270 return xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(xcbEvent));
279 bool MouseTouchAdaptor::handleButtonPress(WId windowId, uint32_t detail, uint32_t modifiers,
int x,
int y)
281 Qt::MouseButton button = translateMouseButton(detail);
282 Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
285 if (button != Qt::LeftButton)
288 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
290 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
292 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
294 touchEvent.press(0 , windowPos);
295 if (qtMod == TRI_PRESS_MODIFIER) {
296 touchEvent.press(1, windowPos);
297 touchEvent.press(2, windowPos);
298 m_triPressModifier =
true;
300 touchEvent.commit(
false );
302 m_leftButtonIsPressed =
true;
306 bool MouseTouchAdaptor::handleButtonRelease(WId windowId, uint32_t detail, uint32_t,
int x,
int y)
308 Qt::MouseButton button = translateMouseButton(detail);
311 if (button != Qt::LeftButton)
314 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
316 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
318 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
320 touchEvent.release(0 , windowPos);
321 if (m_triPressModifier) {
322 touchEvent.release(1, windowPos);
323 touchEvent.release(2, windowPos);
325 touchEvent.commit(
false );
327 m_leftButtonIsPressed =
false;
328 m_triPressModifier =
false;
332 bool MouseTouchAdaptor::handleMotionNotify(WId windowId, uint32_t modifiers,
int x,
int y)
334 if (!m_leftButtonIsPressed) {
337 Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
339 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
341 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
343 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
345 touchEvent.move(0 , windowPos);
346 if (m_triPressModifier) {
347 if (qtMod == TRI_PRESS_MODIFIER) {
348 touchEvent.move(1, windowPos);
349 touchEvent.move(2, windowPos);
352 touchEvent.release(1, windowPos);
353 touchEvent.release(2, windowPos);
354 m_triPressModifier =
false;
357 touchEvent.commit(
false );
362 QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
364 QWindowList windowList = QGuiApplication::topLevelWindows();
365 QWindow *foundWindow =
nullptr;
368 while (!foundWindow && i < windowList.count()) {
369 QWindow *window = windowList[i];
370 if (window->winId() == windowId) {
371 foundWindow = window;
377 Q_ASSERT(foundWindow);
381 bool MouseTouchAdaptor::enabled()
const 386 void MouseTouchAdaptor::setEnabled(
bool value)
388 if (value != m_enabled) {
390 Q_EMIT enabledChanged(value);