[SOLVED] How do AHK's A_ScreenWidth/Height work?

Discuss other programming languages besides AutoHotkey
Miguel7
Posts: 186
Joined: 08 Sep 2014, 07:06

[SOLVED] How do AHK's A_ScreenWidth/Height work?

20 Dec 2017, 15:56

Hey. I've been working on a C++ function to save a screenshot of the entire desktop to memory (for some cool computer vision stuff with OpenCV later) and I've run into a kinda weird problem: None of the Win32 APIs seem to be able to include the entire screen. Here's some of the things I've tried:

Code: Select all

// C++
std::cout << GetSystemMetrics(SM_CXVIRTUALSCREEN) << std::endl;
RECT r;
GetWindowRect(GetDesktopWindow(), &r);
std::cout << r.right << std::endl;
RECT r2;
GetClientRect(GetDesktopWindow(), &r2);
std::cout << r2.right << std::endl;
This prints out "1280" (for the screen width) 3 times. All these Win32 functions seem to "think" my screen is 1280x720. But if I look at the screen resolution settings, or call A_ScreenWidth/Height in AHK, I get 1920x1080; pressing PrintScreen also gives me a 1920x1080 image. After Googling myself stupid the only semi-related results I could find talked about multiple monitors. This kinda-sorta makes sense, because my workstation is a laptop that "docks" to a setup with a desktop-sized monitor... but then how do I get the "active" monitor? There doesn't seem to be such a concept (at least there doesn't seem to be anything like that on MSDN), but the Windows settings and AHK are obviously accessing "something else" to get the correct numbers. So I'm kind of grasping at straws here. Any ideas?
Last edited by Miguel7 on 21 Dec 2017, 09:34, edited 1 time in total.
User avatar
jeeswg
Posts: 5152
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How do AHK's A_ScreenWidth/Height work?

20 Dec 2017, 16:04

I believe that the source code does this:

Code: Select all

;AutoHotkey via DllCall: AutoHotkey functions as custom functions - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=7&t=37871

q:: ;get screen width/height
;SM_CXSCREEN := 0 ;SM_CYSCREEN := 1
vScreenWidth := DllCall("user32\GetSystemMetrics", Int,0)
vScreenHeight := DllCall("user32\GetSystemMetrics", Int,1)
MsgBox, % vScreenWidth " " vScreenHeight
return
[EDIT:] See BIV_ScreenWidth_Height in script2.cpp of the source code.
Miguel7
Posts: 186
Joined: 08 Sep 2014, 07:06

Re: How do AHK's A_ScreenWidth/Height work?

20 Dec 2017, 16:40

Yeah, I've often had a hard time understanding the AHK source; so much of it seems to be in supporting the interpreter for the custom language that figuring out the actual functionality is like finding that one Christmas light out of hundreds that isn't lighting (lol). So I went where you suggested and found this:

Code: Select all

VarSizeType BIV_ScreenWidth_Height(LPTSTR aBuf, LPTSTR aVarName)
{
	return aBuf
		? (VarSizeType)_tcslen(ITOA(GetSystemMetrics(aVarName[13] ? SM_CYSCREEN : SM_CXSCREEN), aBuf))
		: MAX_INTEGER_LENGTH;
}
So I can see it takes two strings as its parameters, and it seems to be calling several different functions in several different places... I'm not sure what a "VarSizeType" (class? structure? vector? etc?) is, or where MAX_INTEGER_LENGTH is defined, or why it's used. I know itoa from C (though I've never seen it in all-caps) and I'm guessing _tcslen is a TCHAR thing... but sadly, this leads to more questions than answers. So I did a search, and the only other result found was in script.h:

Code: Select all

BIV_DECL_R (BIV_ScreenWidth_Height);
What does this even mean? Of course GitHub's search feature is pretty much useless, so plan B was to port your AHK example to C++. I wrote this:

Code: Select all

std::cout << GetSystemMetrics(0) << " x " << GetSystemMetrics(1);
Which printed "1280 x 720". So thanks, but I don't think it's gonna be anything that simple.
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: How do AHK's A_ScreenWidth/Height work?

20 Dec 2017, 17:12

Windows 8+ is known to lie about certain things when things are missing from the manifest for compatibility reaons. AutoHotkey's manifest sets <dpiAware>true</dpiAware>. I can't test anything, but I think that might help.

EDIT: No problem, and happy holidays to you too!
Last edited by qwerty12 on 21 Dec 2017, 17:37, edited 1 time in total.
User avatar
nnnik
Posts: 3351
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: How do AHK's A_ScreenWidth/Height work?

21 Dec 2017, 01:14

@Miguel7 An interpreter is doing more than just executing code.
1st it Tokenizes the code - meaning that it will recognize and evaluate the Syntax that was given to it, and replace it with tokens that are easier to read when executing.
2..I actually forgot all the stuff that comes afterwards
nth now it will actually execute the code that stands behind the Tokens and call the Tokens corresponding to the Tokens it inserted earlier.

I assume that
BIV_DECL_R (BIV_ScreenWidth_Height);
Defines some sort of Token or whats behind some sort of Token.
After thinking it through this is actually not that complex.

Code: Select all

VarSizeType BIV_ScreenWidth_Height(LPTSTR aBuf, LPTSTR aVarName)
{
return aBuf
		? (VarSizeType)_tcslen(ITOA(GetSystemMetrics(aVarName[13] ? SM_CYSCREEN : SM_CXSCREEN), aBuf))
		: MAX_INTEGER_LENGTH
}
aBuf is a output parameter in form of a pointer to a string. If this pointer is not null the function will put the data of GetSystemMetrics in form of a string inside aBuf and return the length of the string put inside aBuf.
aVarName[13] is a specific place for the 2 variable names A_ScreenWidth ( 13 characters long ) and A_ScreenHeight ( 14 characters long ). Checking for the 14th ( starting from 0 ) character will return 0 for A_ScreenWidth and 116 for A_ScreenHeight.
If there is no output the function returns MAX_INTEGER_LENGTH
Recommends AHK Studio
Miguel7
Posts: 186
Joined: 08 Sep 2014, 07:06

Re: How do AHK's A_ScreenWidth/Height work?

21 Dec 2017, 08:31

@nnnik - Thanks for explaining all that! I assumed the code had something to do with the interpreter but never actually knew how an interpreter works. I've also never seen nested ternary operators like that before (though obviously it works) - guess they were trying to be Pythonic even though it's C++? :lol: Seriously though, I appreciate the info, cuz this isn't the first time (and probably won't be the last) that I end up looking at the AHK source - someday I'd like to understand it well enough to contribute! AHK has been a big part of my work, and it would be great to be able to pitch in and give something back.

@qwerty12 - You're probably on to something. One thing looking at the AHK source did tell me is that it uses GetSystemMetrics, which in all my tests gives me the wrong numbers. But I've never seen the manifest file you're talking about before, so I'll definitely be Googling that today. Thanks!

@anyone (lol) - I guess another approach might be to come up with another way to do the screen capture. The HWND returned by GetDesktopWindow is 1280x720, even though my laptop is 1366x768 and when docked shows 1920x1080 (so definitely weird), and it's that HWND that I'm using to capture the screen. I've thought about automating the PrintScreen button AHK-style, but that wouldn't work because then the clipboard would be basically useless (since my app would be using it constantly for screenshots). But maybe there's some other way to do a screenshot? I don't know, just putting it out there in case you do. :)
User avatar
jeeswg
Posts: 5152
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How do AHK's A_ScreenWidth/Height work?

21 Dec 2017, 08:45

- @nnnik: Thanks for your explanation, much appreciated.

- @Miguel7: In this example, there is some complicated use of the ternary operator.
Switch/Case statement - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 86#p187486
- You could try GetDesktopWindow and GetWindowRect in AHK as well as C++ for comparison.
- If you wanted to do screenshots in C++, perhaps you could translate some of the code from Gdip.ahk/Gdip_All.ahk.
- Often, to do things in C++, I try and do everything via DllCall in AutoHotkey, and then try and convert. See examples here:
AutoHotkey via DllCall: AutoHotkey functions as custom functions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=37871
The problems are then usually the lower level stuff in C++, that I'm not always familiar with.
Miguel7
Posts: 186
Joined: 08 Sep 2014, 07:06

Re: How do AHK's A_ScreenWidth/Height work?

21 Dec 2017, 09:33

@jeeswg - Thanks for the suggestion. I like the idea of trying something in AHK to then translate it into C++, mostly because it would give me a lot more experience with DllCall and maybe lead to some fun AHK projects using open-source libs I use all the time.

But in the end, it was querty12's answer that solved the problem! It had nothing to do with code, but was a settings thing (and obscure settings like this have driven me nuts before, so I'm not surprised lol). Under project properties > manifest tool > input and output, there is a "DPI awareness" setting; changing this to "per monitor high DPI aware" caused GetSystemMetrics to start finally returning the correct screen size! I still have to scale my template image to 200% for my code to find it some reason, but that's unrelated to my question and is probably a stupid mistake on my part somewhere in the OpenCV stuff. :lol:

Anyway, thanks to everyone for your suggestions,, and Merry Christmas / happy holiday to all! :)

Return to “Other Programming Languages”

Who is online

Users browsing this forum: No registered users and 2 guests