Get monitor that mouse is in

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Get monitor that mouse is in

23 Aug 2018, 11:28

I wanted to keep my GUI from dropping off the monitor, so I needed the mousepos to tell me which monitor I was on (I have 3 monitors) and make sure the GUI stayed inside the boundaries of the current monitor.

I've found this: https://autohotkey.com/board/topic/9801 ... use-is-in/ but that only works for 2 monitors (and I have 3, as mentioned). The code below works for any monitor setup I've managed to try it on.

In the end, I came up with this script which does what I need:

Code: Select all

	#SingleInstance, Force
	#NoEnv
	
	; get the mouse coordinates first
	Coordmode, Mouse, Screen	; use Screen, so we can compare the coords with the sysget information`
	MouseGetPos, Mx, My
	
	information .= "Mx " . Mx . " x My " . My . "`n`n"	; this is just to fill the GUI with some information

	ActiveMon := MWAGetMonitorMouseIsIn()
			
	Gui, Add, Text, Border, % "Mx " . Mx . " x My " . My . "`n`nActive Monitor " . ActiveMon
	
	; this next part we need so the script knows the dimensions of the GUI as it's not fixed in dimensions (on purpose)
	Gui, Show, Hide
	Gui, +LastFound
	WinGetPos,,, W, H
	
	SysGet, mwa%ActiveMon%, MonitorWorkArea, %ActiveMon% ; "MonitorWorkArea" will get the desktop space of the monitor EXcluding taskbars

	Final_x := max(mwa%ActiveMon%left, min(Mx, mwa%ActiveMon%right - W))
	Final_y := max(mwa%ActiveMon%top, min(My, mwa%ActiveMon%bottom - H))
	
	Gui, Show, x%Final_x% y%Final_y%
	
	F12:: Reload ; press F12 to show the GUI, to see if it does what we want
Return

MWAGetMonitorMouseIsIn() ; we didn't actually need the "Monitor = 0"
{
	; get the mouse coordinates first
	Coordmode, Mouse, Screen	; use Screen, so we can compare the coords with the sysget information`
	MouseGetPos, Mx, My

	SysGet, MonitorCount, 80	; monitorcount, so we know how many monitors there are, and the number of loops we need to do
	Loop, %MonitorCount%
	{
		SysGet, mon%A_Index%, Monitor, %A_Index%	; "Monitor" will get the total desktop space of the monitor, including taskbars

		if ( Mx >= mon%A_Index%left ) && ( Mx < mon%A_Index%right ) && ( My >= mon%A_Index%top ) && ( My < mon%A_Index%bottom )
		{
			ActiveMon := A_Index
			break
		}
	}
	return ActiveMon
}
Last edited by Maestr0 on 03 Nov 2018, 04:23, edited 3 times in total.
User avatar
Nextron
Posts: 1391
Joined: 01 Oct 2013, 08:23
Location: Netherlands OS: Win10 AHK: Unicode x32

Re: Get monitor that mouse is in

23 Aug 2018, 12:03

I written a similar function, but note that right/bottom values return the first greater value not part of the set. So for those you need to check for < instead of <= to prevent errors when at the left/top of the screen.
User avatar
TheDewd
Posts: 1510
Joined: 19 Dec 2013, 11:16
Location: USA

Re: Get monitor that mouse is in

23 Aug 2018, 12:15

Your scrip calls the max() function, but you have not included it in this post.
User avatar
Nextron
Posts: 1391
Joined: 01 Oct 2013, 08:23
Location: Netherlands OS: Win10 AHK: Unicode x32

Re: Get monitor that mouse is in

23 Aug 2018, 12:18

User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Oct 2018, 08:04

TheDewd wrote:Your scrip calls the max() function, but you have not included it in this post.
ah, yeah, sorry, my scripts always assume you are running the most up to date version of Autohotkey. I guess I could make some code that checks for that, but then that could not work because you're using AHK version 1.0.0 ;)
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Oct 2018, 08:05

Nextron wrote:I written a similar function, but note that right/bottom values return the first greater value not part of the set. So for those you need to check for < instead of <= to prevent errors when at the left/top of the screen.
Thanks, I'll adjust the top post.
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: Get monitor that mouse is in

01 Nov 2018, 06:08

Why is the code written on one single line?

On Windows 10 it does not work at all. Single monitor. No GUI shows up.

Here's the code fixed [at least on my system]:

Code: Select all

#SingleInstance, Force
#NoEnv
; get the mouse coordinates first
Coordmode, Mouse, Screen ; use Screen, so we can compare the coords with the sysget information

MouseGetPos, Mx, My
information .= "Mx " Mx " x My " My "`n`n" ; this is just to fill the GUI with some information
ActiveMon := MWAGetMonitorMouseIsIn()

Gui, Add, Text, Border, % "Mx " Mx " x My " My "`n`nActive Monitor " ActiveMon

; this next part we need so the script knows the dimensions of the GUI as it's not fixed in dimensions (on purpose)
Gui, Show, Hide
Gui, +LastFound
WinGetPos,,, W, H
SysGet, mwa%ActiveMon%, MonitorWorkArea, %ActiveMon%
; "MonitorWorkArea" will get the desktop space of the monitor excluding taskbars

Final_x := max(mwa%ActiveMon%left, min(Mx, mwa%ActiveMon%right - W))
Final_y := max(mwa%ActiveMon%top, min(My, mwa%ActiveMon%bottom - H))

Gui, Show, x%Final_x% y%Final_y%
; Gui, Show, x2 y2 AutoSize
Return

MWAGetMonitorMouseIsIn(Monitor = 0) {
    ; get the mouse coordinates first
    Coordmode, Mouse, Screen ; use Screen, so we can compare the coords with the sysget information

    MouseGetPos, Mx, My
    SysGet, MonitorCount, 80
    ; monitorcount, so we know how many monitors there are, and the number of loops we need to do

    Loop, %MonitorCount%
    {
      SysGet, mon%A_Index%, Monitor, %A_Index%
      ; "Monitor" will get the total desktop space of the monitor, including taskbars
      if ( Mx >= mon%A_Index%left ) && ( Mx < mon%A_Index%right ) && ( My >= mon%A_Index%top ) && ( My < mon%A_Index%bottom )
      {
         ActiveMon := A_Index
         break
      }
    }
    Return ActiveMon
}

F12::   ; press F12 to show the GUI, to see if it does what we want
  Reload
Return
Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

03 Nov 2018, 04:20

robodesign wrote:
01 Nov 2018, 06:08
Why is the code written on one single line?

On Windows 10 it does not work at all. Single monitor. No GUI shows up.

Best regards, Marius.
Ah, yes, the issue was the hotkey, if you move it down past the last Gui, Show line, it works. I've updated the code in the top post.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Get monitor that mouse is in

07 Nov 2018, 11:45

Alternative:

Code: Select all

CoordMode, Mouse, Screen
Sleep, 5000	; Give the user time to move the cursor to some other monitor
hCB := RegisterCallback("EP", "F", 4, 0)
MouseGetPos, x, y
if DllCall("user32\EnumDisplayMonitors", "Ptr", 0, "Ptr", 0, "Ptr", hCB, "UInt", 0)
	{
	r := DllCall("user32\MonitorFromPoint", "Int", x, "Int", y, "UInt", 2)	; MONITOR_DEFAULTTONEAREST
	Loop, Parse, hList, `n
		if (A_LoopField=r)
			idx := A_Index
	}
msgbox, hMonitor=%r%`nidx=%idx%`n`n%hList%
return

EP(hM, hDC, pRect, arg)
{
Global hList
if !hM
	return False
hList .= hM "`n"
return True
}
This could be improved further by using an array for hList and/or whatever other newer facilities. For scripts that may need monitor handles instead of/additionally to indexes.

There are two other APIs in user32.dll that may prove useful: MonitorFromRect and MonitorFromWindow, additionally to GetMonitorInfo (see MSDN).
Part of my AHK work can be found here.
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Nov 2018, 12:11

Hm, that code is not working for me, Drugwash, which version of AHK are you using?
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Get monitor that mouse is in

07 Nov 2018, 12:44

AHK v1.1.28.00 Unicode on XP x86.
I have two monitors, it correctly identifies monitor 1 or 2 according to mouse position.
20181107194747.png
20181107194747.png (113.2 KiB) Viewed 7592 times
What do you mean by "is not working"? Any errors? No messagebox? No monitor handles? Wrong monitor index?
Part of my AHK work can be found here.
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Nov 2018, 13:40

My bad, yes, no msgbox, not anything, it just.... quits, even after I added a #persistent
I'm on 10 x64, maybe that's why?
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Get monitor that mouse is in

07 Nov 2018, 13:58

Hm, that's weird. Even if first DllCall failed, a messagebox should still be displayed. There is no Structure involved to blame parameter type mismatch or bad size/alignment.
This means the script crashes earlier, possibly in RegisterCallback() or first DllCall(). Neither should happen, but that's what Win10 was invented for.

You may try to omit user32 from both DllCalls, and/or remove Fast mode from RegisterCallback() - put "" instead of "F" as second parameter.
You may also try to run the script through the 32bit AHK.

I'm curious whether anybody else experiences such weird crash.
Part of my AHK work can be found here.
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Nov 2018, 14:13

I don't know, but using 1.1.30 (both x86 and x64) shows no msgbox for me, I've tried combinations of the changes you've suggested. Sorry :(
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Get monitor that mouse is in

07 Nov 2018, 14:18

The function EP is missing. The RegisterCallBack function call returns 0.
This will cause an access exception in the DllCall. Since AHK v1 has a tendency not to throw this error went by unnoticed.

Note: it seems that it just was in the version that Maestr0 was running locally.
Recommends AHK Studio
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Nov 2018, 14:18

Drugwash wrote:
07 Nov 2018, 13:58
Hm, that's weird. Even if first DllCall failed, a messagebox should still be displayed. There is no Structure involved to blame parameter type mismatch or bad size/alignment.
This means the script crashes earlier, possibly in RegisterCallback() or first DllCall(). Neither should happen, but that's what Win10 was invented for.

You may try to omit user32 from both DllCalls, and/or remove Fast mode from RegisterCallback() - put "" instead of "F" as second parameter.
You may also try to run the script through the 32bit AHK.

I'm curious whether anybody else experiences such weird crash.
Cap'n'Odin solved it on Discord, the EP code was missing in your my code, when I add this, it works:

Code: Select all

EP(hM, hDC, pRect, arg)
{
Global hList
if !hM
    return False
hList .= hM "`n"
return True
}
Yes, I totally missed the scroll bar and failed to select that bottom part :crazy:
Last edited by Maestr0 on 07 Nov 2018, 14:23, edited 1 time in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Get monitor that mouse is in

07 Nov 2018, 14:20

It's not really missing in his code though.
Recommends AHK Studio
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

07 Nov 2018, 14:24

nnnik wrote:
07 Nov 2018, 14:20
It's not really missing in his code though.
Yeah, my bad :dance:
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Get monitor that mouse is in

07 Nov 2018, 15:03

Glad you solved it and it works. :)
BTW, what theme do you use for the board? I use prosilver and it displays "Select all" and "Expand view" for the code box, those options should help in viewing/copying the code.

Thanks for the help, nnnik. ;)
Part of my AHK work can be found here.
User avatar
Maestr0
Posts: 136
Joined: 05 Dec 2013, 17:43

Re: Get monitor that mouse is in

15 Nov 2018, 07:25

Drugwash wrote:
07 Nov 2018, 15:03
Glad you solved it and it works. :)
BTW, what theme do you use for the board? I use prosilver and it displays "Select all" and "Expand view" for the code box, those options should help in viewing/copying the code.

Thanks for the help, nnnik. ;)
I was using prosilver, now I switched to "Simplicity", better layout. Thanks for your help!

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 56 guests