20

First of all, I'd like to mention that I found that related post How to get the mouse position on the screen in Qt? but it "just didn't work" for me. I made some tests, and the results didn't work as I expected, so I decided to make a new post to talk about the test I made and to find an alternative solution.

That's the code I used to make the test:

QScreen *screen0 = QApplication::screens().at(0);
QScreen *screen1 = QApplication::screens().at(1);

printf("screen0 %s \n", screen0->name().toStdString().c_str());
printf("screen1 %s \n", screen1->name().toStdString().c_str());

// Position on first screen.
QPoint pos0 = QCursor::pos(screen0);

// Position on second screen.
QPoint pos1 = QCursor::pos(screen1);

printf("pos 0: %d, %d \n", pos0.x(), pos0.y());
printf("pos 1: %d, %d \n", pos1.x(), pos1.y());

// Get position without screen.
QPoint pos = QCursor::pos();
printf("pos: %d, %d \n", pos.x(), pos.y());

What I was expecting, is that only one screen would return a valid position, since the cursor is only at one screen, not on both. But it's not the case, the both positions (pos0 and pos1) has the exactly same value, as we can see on the output:

screen0 DVI-D-0 
screen1 HDMI-0 
pos 0: 1904, 1178 
pos 1: 1904, 1178 
pos: 1904, 1178 

Since the both positions has the same values, I can't know at which screen is the cursor. I don't know if that's a normal behavior or a bug, since the documentation doesn't say what happens when the screen argument isn't the screen where the mouse is.

My idea, is to open/launch an application (executed by a Qt daemon that must detect the selected screen) to the screen where the mouse is. I know that with libX11 it's possible, because I did it in the past, but I need to work with Qt 5, and I can't figure out how to do detect the selected screen with Qt.

I also made other tests, using QApplication and QDesktopWidget classes with no luck.

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
armitage
  • 201
  • 1
  • 2
  • 5

7 Answers7

18

That's really weird. As a workaround, you could try this:

QPoint globalCursorPos = QCursor::pos();
int mouseScreen = qApp->desktop()->screenNumber(globalCursorPos);

Now you know which screen the cursor is in. Then you could find the cursor position within that screen doing this:

QRect mouseScreenGeometry = qApp->desktop()->screen(mouseScreen)->geometry();
QPoint localCursorPos = globalCursorPos - mouseScreenGeometry.topLeft();
Rafael Monteiro
  • 4,509
  • 1
  • 16
  • 28
  • I tried that, but it allways returns the screen 0. Even if you take the point from the screen1 (with pos(QScreen*)), it returns 0. – armitage Aug 17 '15 at 00:14
  • I'm using Getoo, with KDE and Awesome as window manager. Maybe that's a configuration problem. Rafael, could you share the output and the code you executed? – armitage Aug 17 '15 at 00:21
  • Perhaps it's a Qt bug. Just FYI: I tried what you did in your question and it also didn't work on Windows. I was getting the same coordinate values on pos(QScreen*), regardless on which screen it was given and where the cursor was. Sorry I can't help more than that. – Rafael Monteiro Aug 17 '15 at 00:26
  • Your solution worked for me. And you are right `QCursor::pos(QScreen*)` appears to not work correctly (still). – bweber Mar 12 '16 at 14:42
7

This may seem like a trivial solution, but on my KDE it works (I ran into the same problems originally). If you want to determine the local mouse coordinates with respect to a widget (this will be in device pixels and relative to the top left corner of the widget I believe) you can use

QWidget::mapFromGlobal(QCursor::pos());

i.e. call this->mapFromGlobal.

GPMueller
  • 2,881
  • 2
  • 27
  • 36
2

This may work for you? It did for me

QDesktopWidget *widget = QApplication::desktop(); QPosition globalCursorPosition = widget->cursor().pos();

samarth
  • 21
  • 2
1

To figure out on which screen you are, you can iterate throught QGuiApplication::screens() and check whether the cursor fits in the geometry of the screen.

Here is a more complex example to compute the native cursor position (note the additional work needed to work with High DPI screens):

QPoint getNativeCursorPosition()
{
    QPoint pos = cursorPosToNative(QCursor::pos());

    // Cursor positions from Qt are calculated in a strange way, the offset to
    // the origin of the current screen is in device-independent pixels while
    // the origin itself is native!

    for (QScreen *screen : QGuiApplication::screens()) {
        QRect screenRect = screen->geometry();
        if (screenRect.contains(pos)) {
            QPoint origin = screenRect.topLeft();
            return origin + (pos - origin) * screen->devicePixelRatio();
        }
    }

    // should not happen, but try to find a good fallback.
    return pos * qApp->devicePixelRatio();
}
Lekensteyn
  • 64,486
  • 22
  • 159
  • 192
  • in this code, I believe cursorPos should be renamed pos. – Dave Apr 14 '17 at 22:29
  • Which header do I need for this `cursorPosToNative` function - it doesn't seem to exist within Qt 5.9.3? – Vertigo Jan 17 '18 at 13:13
  • @Vertigo There should be a platform-independent way to calculate that, but for simplicity I did not implement that and instead queried the native APIs directly. See for example https://github.com/KDE/spectacle/commit/a41e83edbaadd27cd8ea85d4dfa375033e8ade84#diff-d0fc42a0f2e357991342776195467997R700 – Lekensteyn Jan 19 '18 at 11:45
0

Sice it seems that it can't be done with Qt (at least with my system configuration, and it seems that also in Windows) I decided to use the libX11 to make that implementation, which works like charm.

It's not an ideal solution because I wanted to only use Qt, but it works.

armitage
  • 201
  • 1
  • 2
  • 5
0

With QML you can use the properties of the Screen QML Type:

Screen.virtualX : The x coordinate of the screen within the virtual desktop.

Screen.virtualY : The y coordinate of the screen within the virtual desktop.

import QtQuick 2.6
import QtQuick.Window 2.2

console.log("Pos x : " + Screen.virtualX )
console.log("Pos y : " + Screen.virtualY )

This work with single screen as well multi-monitor systems.

Adriano Campos
  • 1,121
  • 7
  • 14
0

I recently ran into a similar problem on Qt 5.15 + Windows + mixed DPI and needed this work around within a QWindow object.

QScreen* primaryScreen = QGuiApplication::primaryScreen();
QScreen* thisScreen = screen();
qreal primaryDPR = primaryScreen->devicePixelRatio();
qreal thisDPR = thisScreen->devicePixelRatio();
qreal scale = thisDPR / primaryDPR;
QPoint pos = scale  * QCursor::pos();

I'm unsure if this works on other platforms.

Kyle Spagnoli
  • 196
  • 2
  • 4