Here a small program that shows the issue. I couldn't find a way to upload files so I copy pasted the content below.
main.cpp:
#include "myitem.hpp"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QString>
#include <QSurfaceFormat>
#include <QUrl>
#include <QtQml>
int main(int argc, char** argv) {
{
QGuiApplication::setAttribute(Qt::ApplicationAttribute::AA_ShareOpenGLContexts);
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
// Surface
// Force OpenGL 3.3 core profile
QSurfaceFormat format;
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
}
QGuiApplication app(argc, argv);
qmlRegisterType<MyItem>("MyLib", 1, 0, "MyItem");
QQmlApplicationEngine engine;
engine.load(QUrl(QString("qrc:/qml/main.qml")));
return app.exec();
}
myitem.hpp
#pragma once
#include <QQuickItem>
#include <memory>
class QMouseEvent;
class MyItem : public QQuickItem {
Q_OBJECT
public:
MyItem(QQuickItem* parent = nullptr);
~MyItem() override;
protected:
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
private:
void handleMouseWarping(QMouseEvent& event);
private:
struct Private;
std::unique_ptr<Private> d;
};
myitem.cpp
#include "myitem.hpp"
#include <QCursor>
#include <QMouseEvent>
#include <iostream>
struct MyItem::Private {
bool mouseWarpingEnabled{ false };
unsigned int mouseWarpingMargin{ 5u };
QCursor cursor;
};
MyItem::MyItem(QQuickItem* parent) : QQuickItem{ parent }, d{ new Private } {
setAcceptedMouseButtons(Qt::LeftButton);
}
MyItem::~MyItem() = default;
void MyItem::mousePressEvent(QMouseEvent* event) {
d->mouseWarpingEnabled = true;
}
void MyItem::mouseReleaseEvent(QMouseEvent* event) {
d->mouseWarpingEnabled = false;
}
void MyItem::mouseMoveEvent(QMouseEvent* event) {
handleMouseWarping(*event);
}
// ==== PRIVATE IMPL
void MyItem::handleMouseWarping(QMouseEvent& event) {
// Only manipulate QCursor coordinates to prevent having a desync between cursor and event information
if(!d->mouseWarpingEnabled) {
event.ignore();
return;
}
const auto globalPos = d->cursor.pos();
const auto topLeftRectPos = mapToGlobal({ 0, 0 });
const auto localPos = globalPos - topLeftRectPos;
QPoint offset{ 0, 0 };
if(localPos.x() < d->mouseWarpingMargin) {
offset.setX(width() - 2 * d->mouseWarpingMargin - 1);
}
else if(localPos.x() > width() - d->mouseWarpingMargin) {
offset.setX(-(width() - 2 * d->mouseWarpingMargin - 1));
}
if(localPos.y() < d->mouseWarpingMargin) {
offset.setY(height() - 2 * d->mouseWarpingMargin - 1);
}
else if(localPos.y() > height() - d->mouseWarpingMargin) {
offset.setY(-(height() - 2 * d->mouseWarpingMargin - 1));
}
if(offset.x() != 0 || offset.y() != 0) {
const auto newGlobalPos = globalPos + offset;
d->cursor.setPos(newGlobalPos);
const auto actualNewGlobalPos = d->cursor.pos();
std::cout << "Expected new coordinates: " << newGlobalPos.x() << ", " << newGlobalPos.y()
<< ". Actual new coordinates: " << actualNewGlobalPos.x() << ", " << actualNewGlobalPos.y() << std::endl;
}
}
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import MyLib 1.0
ApplicationWindow {
id : root
title : 'Mouse warping issue in 4K'
visible : true
width : 800
height : 400
color: Qt.hsla(0, 0, 0.13)
MyItem {
anchors.fill: parent
Text {
text: 'Press left-click down and move over to edge of window to warp to the other side'
anchors.centerIn: parent
color: Qt.hsla(0, 0, 0.89)
}
}
}
qml.qrc
<RCC>
<qresource prefix="/qml">
<file>main.qml</file>
</qresource>
</RCC>