diff options
Diffstat (limited to 'src/window-lib/touchemulation_x11.cpp')
-rw-r--r-- | src/window-lib/touchemulation_x11.cpp | 298 |
1 files changed, 0 insertions, 298 deletions
diff --git a/src/window-lib/touchemulation_x11.cpp b/src/window-lib/touchemulation_x11.cpp deleted file mode 100644 index db72906f..00000000 --- a/src/window-lib/touchemulation_x11.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtAppManCommon/global.h> - -#include "touchemulation_x11_p.h" - -#include <QGuiApplication> -#include <QMouseEvent> -#include <QPointingDevice> -#include <QWindow> -#include <QTest> - -#include <QtAppManCommon/logging.h> - -#include <qpa/qplatformnativeinterface.h> -#include <qpa/qwindowsysteminterface.h> - -#include <xcb/xcb.h> -#include <X11/extensions/XInput2.h> -#include <X11/extensions/XI2proto.h> - -// this event type was added in libxcb 1.10, -// but we support also older version -#ifndef XCB_GE_GENERIC -# define XCB_GE_GENERIC 35 -#endif - -#if defined None -# undef None -#endif - -QT_BEGIN_NAMESPACE_AM - -using QTest::QTouchEventSequence; - - -static Qt::MouseButton xcbButtonToQtMouseButton(xcb_button_t detail) -{ - switch (detail) { - case 1: return Qt::LeftButton; - case 2: return Qt::MiddleButton; - case 3: return Qt::RightButton; - // don't care about the rest - default: return Qt::NoButton; - } -} - -// Function copied from the XCB QPA -static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event) -{ - // xcb event structs contain stuff that wasn't on the wire, the full_sequence field - // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. - // Move this data back to have the same layout in memory as it was on the wire - // and allow casting, overwriting the full_sequence field. - memmove(reinterpret_cast<char *>(event) + 32, reinterpret_cast<char*>(event) + 36, event->length * 4); -} - -static qreal fixed1616ToReal(FP1616 val) -{ - return qreal(val) / 0x10000; -} - - -TouchEmulationX11::TouchEmulationX11() -{ - qGuiApp->installNativeEventFilter(this); - - // Create a fake touch device to deliver our synthesized events - m_touchDevice = new QPointingDevice(qSL("Fake Touch"), -1, QInputDevice::DeviceType::TouchScreen, - QPointingDevice::PointerType::Finger, - QInputDevice::Capability::None, 0, 0); - QWindowSystemInterface::registerInputDevice(m_touchDevice); - - queryForXInput2(); -} - -void TouchEmulationX11::queryForXInput2() -{ - QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); - Display *xDisplay = static_cast<Display*>(nativeInterface->nativeResourceForIntegration("Display")); - - int xiOpCode, xiEventBase, xiErrorBase; - if (xDisplay && XQueryExtension(xDisplay, "XInputExtension", &xiOpCode, &xiEventBase, &xiErrorBase)) { - // 2.0 is enough for our needs - int xiMajor = 2; - int xi2Minor = 0; - m_haveXInput2 = XIQueryVersion(xDisplay, &xiMajor, &xi2Minor) != BadRequest; - } -} - -bool TouchEmulationX11::nativeEventFilter(const QByteArray &eventType, void *message, qintptr * /*result*/) -{ - if (eventType != "xcb_generic_event_t") - return false; // just ignore non-XCB-native events - - xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message); - - switch (xcbEvent->response_type & ~0x80) { - case XCB_BUTTON_PRESS: { - auto xcbPress = reinterpret_cast<xcb_button_press_event_t *>(xcbEvent); - return handleButtonPress(static_cast<WId>(xcbPress->event), xcbPress->detail, 0, - xcbPress->event_x, xcbPress->event_y); - } - case XCB_BUTTON_RELEASE: { - auto xcbRelease = reinterpret_cast<xcb_button_release_event_t *>(xcbEvent); - return handleButtonRelease(static_cast<WId>(xcbRelease->event), xcbRelease->detail, 0, - xcbRelease->event_x, xcbRelease->event_y); - } - case XCB_MOTION_NOTIFY: { - auto xcbMotion = reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent); - return handleMotionNotify(static_cast<WId>(xcbMotion->event), 0, - xcbMotion->event_x, xcbMotion->event_y); - } - case XCB_GE_GENERIC: { - if (!m_haveXInput2) - return false; - - auto xcbGeneric = reinterpret_cast<xcb_ge_event_t *>(xcbEvent); - - // Because xi2PrepareXIGenericDeviceEvent modifies data inplace - backupEventData(xcbGeneric); - - xi2PrepareXIGenericDeviceEvent(xcbGeneric); - auto xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(xcbGeneric); - xXIDeviceEvent *xiDeviceEvent = nullptr; - - switch (xiEvent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_Motion: - xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xcbGeneric); - break; - default: - break; - } - - bool result = false; - - if (xiDeviceEvent) { - switch (xiDeviceEvent->evtype) { - case XI_ButtonPress: - result = handleButtonPress( - static_cast<WId>(xiDeviceEvent->event), - xiDeviceEvent->detail, - xiDeviceEvent->mods.base_mods, - fixed1616ToReal(xiDeviceEvent->event_x), - fixed1616ToReal(xiDeviceEvent->event_y)); - break; - case XI_ButtonRelease: - result = handleButtonRelease( - static_cast<WId>(xiDeviceEvent->event), - xiDeviceEvent->detail, - xiDeviceEvent->mods.base_mods, - fixed1616ToReal(xiDeviceEvent->event_x), - fixed1616ToReal(xiDeviceEvent->event_y)); - break; - case XI_Motion: - handleMotionNotify( - static_cast<WId>(xiDeviceEvent->event), - xiDeviceEvent->mods.base_mods, - fixed1616ToReal(xiDeviceEvent->event_x), - fixed1616ToReal(xiDeviceEvent->event_y)); - result = true; - break; - default: - break; - } - } - - // Put the event back in its original state so that the XCB QPA can process it normally - restoreEventData(xcbGeneric); - return result; - } - default: - return false; - }; -} - -bool TouchEmulationX11::handleButtonPress(WId windowId, uint32_t detail, uint32_t /*modifiers*/, qreal x, qreal y) -{ - Qt::MouseButton button = xcbButtonToQtMouseButton(static_cast<xcb_button_t>(detail)); - - // Filter out the other mouse buttons - if (button != Qt::LeftButton) - return true; - - QWindow *targetWindow = findQWindowWithXWindowID(windowId); - - QPointF windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio()); - - QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false /* autoCommit */); - touchEvent.press(0 /* touchId */, windowPos.toPoint(), targetWindow); - touchEvent.commit(false /* processEvents */); - - m_leftButtonIsPressed = true; - return true; -} - -bool TouchEmulationX11::handleButtonRelease(WId windowId, uint32_t detail, uint32_t, qreal x, qreal y) -{ - Qt::MouseButton button = xcbButtonToQtMouseButton(static_cast<xcb_button_t>(detail)); - - // Don't eat the event if it wasn't a left mouse press - if (button != Qt::LeftButton) - return false; - - QWindow *targetWindow = findQWindowWithXWindowID(windowId); - - QPointF windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio()); - - QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false /* autoCommit */); - touchEvent.release(0 /* touchId */, windowPos.toPoint(), targetWindow); - touchEvent.commit(false /* processEvents */); - - m_leftButtonIsPressed = false; - return true; -} - -bool TouchEmulationX11::handleMotionNotify(WId windowId, uint32_t /*modifiers*/, qreal x, qreal y) -{ - if (!m_leftButtonIsPressed) - return true; - - QWindow *targetWindow = findQWindowWithXWindowID(windowId); - - QPointF windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio()); - - QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false /* autoCommit */); - touchEvent.move(0 /* touchId */, windowPos.toPoint(), targetWindow); - touchEvent.commit(false /* processEvents */); - - return true; -} - -QWindow *TouchEmulationX11::findQWindowWithXWindowID(WId windowId) -{ - QWindowList windowList = QGuiApplication::topLevelWindows(); - QWindow *foundWindow = nullptr; - - int i = 0; - while (!foundWindow && (i < windowList.count())) { - QWindow *window = windowList[i]; - if (window->winId() == windowId) - foundWindow = window; - else - ++i; - } - - Q_ASSERT(foundWindow); - return foundWindow; -} - - -// backup event data before a xi2PrepareXIGenericDeviceEvent() call -void TouchEmulationX11::backupEventData(void *event) -{ - memcpy(reinterpret_cast<char *>(m_xiEventBackupData), reinterpret_cast<char *>(event) + 32, 4); -} - -// restore event data after a xi2PrepareXIGenericDeviceEvent() call -void TouchEmulationX11::restoreEventData(void *ev) -{ - auto *event = static_cast<xcb_ge_event_t *>(ev); - - memmove(reinterpret_cast<char *>(event) + 36, reinterpret_cast<char *>(event) + 32, event->length * 4); - memcpy(reinterpret_cast<char *>(event) + 32, reinterpret_cast<char *>(m_xiEventBackupData), 4); -} - -QT_END_NAMESPACE_AM |