简体   繁体   中英

Qt 5, get the mouse position in a screen

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.

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();

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());

ie call this->mapFromGlobal .

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();
}

This may work for you? It did for me

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

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM