MouseGetPos does not include DPI scalling but gui.move does Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
IMTheNachoMan
Posts: 59
Joined: 01 Mar 2022, 17:07
Contact:

MouseGetPos does not include DPI scalling but gui.move does

24 Sep 2023, 00:21

I've read around in the forums and still can't seem to figure this out.

I have an AHK script that will be used in different monitor configurations:
  1. single monitor, no DPI scaling
  2. single monitor, with DPI scaling
  3. multiple monitors, none with DPI scalling
  4. multiple monitors, one with DPI scalling
My script will show a GUI under the mouse. To do this, I get the mouse coordinates with MouseGetPos and then move the gui using gui.move.

It appears that for #2 and #4, MouseGetPos returns the actual X and Y without DPI scaling but gui.move does GPI scaling. So then things go off screen cause the X/Y are being multiplied by DPI scaling.

How can I fix this?

Code: Select all

#Requires AutoHotkey v2.0
#Warn Unreachable, off
#SingleInstance Force

allMonitorDetails := getAllMonitorDetails()

myGUI := Gui()
myGUI.SetFont("s12", "Calibri")
myGUI.Title := "ExquisiteW"
myGUI.Opt("+AlwaysOnTop -MinimizeBox")   ; WS_EX_NOACTIVATE
myGUI.OnEvent("Close", CloseIt)
myGUI.OnEvent("Escape", CloseIt) ; allow closing with the escape key

myGUI.add("Text", "", "Some text goes here")
myGUI.add("Text", "", "Some text goes here")
myGUI.add("Text", "", "Some text goes here")
myGUI.add("Text", "", "Some text goes here")
myGUI.add("Text", "", "Some text goes here")
myGUI.add("Text", "", "Some text goes here")
myGUI.add("Button", "", "A Button")

return

^!d::
{
    global myGUI

    ; we want mouse position based on screen, so temporarily set the current coordinate mode
    Local CMM := A_CoordModeMouse
    A_CoordModeMouse := "Screen"
    ; get the mouse position
    MouseGetPos(&mousePositionLeft, &mousePositionTop)
    A_CoordModeMouse := CMM

    ; get the details of the monitor the mouse is on
    monitorDetails := getDetailsOfMonitorMouseIsIn(&mousePositionLeft, &mousePositionTop)

    myGUI.show()

    myGUI.GetPos(&junk, &junk, &myGUIWidth, &myGUIHeight)
    myGUILeft := mousePositionLeft - round(myGUIWidth / 2)
    myGUITop := mousePositionTop - round(myGUIHeight / 2)
    myGUI.Move(myGUILeft, myGUITop)
    
    return
}

CloseIt(*)
{
    global myGUI

    myGUI.hide()
    return
}


; get details about all the connected monitors
getAllMonitorDetails()
{
    allMonitorDetails := []

    ; loop through the number of monitors
    Loop MonitorGetCount()
    {
        ; get details about the monitor
        monitorIndex := A_Index
        monitorName := MonitorGetName(monitorIndex)
        MonitorGet(monitorIndex, &screenLeft, &screenTop, &screenRight, &screenBottom)
        MonitorGetWorkArea(monitorIndex, &workAreaLeft, &workAreaTop, &workAreaRight, &workAreaBottom)

        ; save for later
        allMonitorDetails.Push({
            index: monitorIndex,
            name: monitorName,
            screen: {
                left: screenLeft,
                top: screenTop,
                right: screenRight,
                bottom: screenBottom,
                width: screenRight - screenLeft,
                height: screenBottom - screenTop
            },
            workArea: {
                left: workAreaLeft,
                top: workAreaTop,
                right: workAreaRight,
                bottom: workAreaBottom,
                width: workAreaRight - workAreaLeft,
                height: workAreaBottom - workAreaTop
            }
        })
    }

    return allMonitorDetails
}

; get the details of the monitor the mouse is under
getDetailsOfMonitorMouseIsIn(&mousePositionLeft, &mousePositionTop)
{
    for arrayIndex, monitorDetails in allMonitorDetails
    {
        if (mousePositionLeft >= monitorDetails.screen.left) && (mousePositionLeft <= monitorDetails.screen.right) && (mousePositionTop >= monitorDetails.screen.top) && (mousePositionTop <= monitorDetails.screen.bottom)
        {
            return monitorDetails
        }
    }
    return -1
}
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: MouseGetPos does not include DPI scalling but gui.move does

24 Sep 2023, 00:39

does adding this line to the top of your script fix it?

Code: Select all

DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr")
(from this thread)

User avatar
andymbody
Posts: 904
Joined: 02 Jul 2017, 23:47

Re: MouseGetPos does not include DPI scalling but gui.move does  Topic is solved

24 Sep 2023, 00:50

Not sure whether it will help but... have you looked into these yet... I don't see any adjustments in the code that you posted (but I may have missed it)...
ScreenDPI
DPIScale
IMTheNachoMan
Posts: 59
Joined: 01 Mar 2022, 17:07
Contact:

Re: MouseGetPos does not include DPI scalling but gui.move does

24 Sep 2023, 16:33

andymbody wrote:
24 Sep 2023, 00:50
Not sure whether it will help but... have you looked into these yet... I don't see any adjustments in the code that you posted (but I may have missed it)...
ScreenDPI
DPIScale
The DPIScale one seems to be working now. Not sure why I couldn't get it to work earlier.
just me
Posts: 9465
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: MouseGetPos does not include DPI scalling but gui.move does

25 Sep 2023, 03:52

Code: Select all

    myGUI.GetPos(&junk, &junk, &myGUIWidth, &myGUIHeight)  ; <<< scaled values
    myGUILeft := mousePositionLeft - round(myGUIWidth / 2)
    myGUITop := mousePositionTop - round(myGUIHeight / 2)
    myGUI.Move(myGUILeft, myGUITop)
In this piece of code only myGUIWidth and myGUIHeight retrieve scaled values.
You can replace myGUI.GetPos() with WinGetClientPos() to change it:

Code: Select all

WinGetClientPos( , , &myGUIWidth, &myGUIHeight, myGUI.Hwnd)
(if you really want to use the client area dimensions)

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: No registered users and 168 guests