Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
5.6.0
-
None
-
computer with three monitors in Windows 10
Description
Reopened because the response was not correct. The function clearly states "global screen position":
[static] void QCursor::setPos(const QPoint &p) This is an overloaded function. Moves the cursor (hot spot) to the global screen position at point p.
Even if the position is required to be on the primary screen, this function is moving the mouse cursor to the far left side of screen #2.
There is confusion in some of the documentation on what a global screen coordinate is (it appears that the window geometry docs pre-date QScreen). The most commonly used function that I'm aware of is "QWidget::move()." which, for a top level window, moves a widget to a global position. In fact, internally, it contains code similar to the workaround code below. QWidget::move() is consistent with QWheelEvent::globalPos(), QCursor::globalPos(), QWidget::pos() and all other functions I've seen in Qt dealing with global positions. The only outlier is QCursor::setPos().
Even this fails: QCursor::setPos(QCursor::pos()) because they are not consistent.
If you simply do code like this:
void MyWidget::wheelEvent(QWheelEvent *e) { QCursor::setPos(e->globalPos()); }
That code should not actually move the mouse. However, in Windows on a multiple monitor system with High DPI Support enabled, using Windows DPI Awareness level 1 (System DPI Aware), this code will cause the mouse cursor to fly off the screen on secondary monitors.
I think that the problem is here:
void QCursor::setPos(int x, int y) { QCursor::setPos(QGuiApplication::primaryScreen(), x, y); }
Since the position is a global position, there is no reason to assume it is on the primary screen. (The code that follows makes a transformation incorrectly because it grabbed the wrong screen.) It seems that the code should mirror other code which figures out what screen it is on. I've used code like this locally:
QPoint newPt = e->globalPos(); const QList<QScreen *> screens = QGuiApplication::screens(); for (int i = 0; i < screens.size(); ++i) { QScreen *screen = screens[i]; if (screen->geometry().contains(newPt)) { QCursor::setPos(screen, newPt); break; } }
That seems to work properly, at least in my scenario.
.h2 Environment:
I have a computer with three monitors in Windows 10. Left monitor (2) is 1920x1200, set to 100% scaling in control panel. Center monitor (primary, 0) is 3840x2160, 200%. Right monitor (laptop, 1) is 1920x1080, 125%.
If I loop through the screens, here's the data I see:
Using system dpi aware mode Screen 0 Geometry, 0,0, 1920, 1080. Available, 0,0, 1920, 1040, 527mm x 296mm DevicePixelRatio = 2 192 dpi Screen 1 Geometry, 7680, 2150, 1536, 864. Available 7680, 2150, 1536, 824. 344mm x 193mm DevicePixelRatio = 2 192 dpi Screen 2 Geometry, -3840, 870, 1920, 1200. Available -3840, 870, 1920, 1160. 519mm x 324mm DevicePixelRatio = 2 192 dpi
Attachments
Issue Links
- is duplicated by
-
QTBUG-78320 [HighDPI multi-monitor Mixed screen scale factors] QCursor::setPos setting incorrect positions on non-primary monitor
- Reported
- relates to
-
QTBUG-78320 [HighDPI multi-monitor Mixed screen scale factors] QCursor::setPos setting incorrect positions on non-primary monitor
- Reported
-
QTBUG-99009 QCursor::setPos X coordinates is wrong when DPI scaling is used
- Reported