trismarck wrote:- Autohotkey determines DPI settings based on the 'screen' (which is really based on the DPI of the primary monitor only I guess)
Windows 8.1 and up have two separate DPI settings:
- system DPI setting
- per-monitor DPI setting.
What Autohotkey reads is the System DPI setting.
Autohotkey is the system DPI–aware application, but not per monitor-DPI aware application.
trismarck wrote:- -DPIScale / DPIScale only really affects positions explicitly specified by the user (vs auto-placement of gui controls/windows, which seems to _always_ use
the DPI of the primary monitor described above the System DPI settings). Positions given part of Gui related commands: Gui, GuiControl, Move and related (vs WinGetPos or ControlGetPos)
Seems to be correct.
trismarck wrote:- the size of the text within the control is scaled by Windows itself, so DPIScale doesn't have an effect on the text; only on the 'rectangle' / size of the control in which the text is displayed
- DPIScale was added mainly for older Autohotkey scripts, created with GUI creator tool (don't remember the exact name of the tool). The GUI creator tool generated a layout of gui controls within the gui window, and that layout had fixed coords, coords that would only 'work' on systems with DPI set to 100%. By adding DPIScale, one could make something like GuiControl, Move, x200 to really move 300px on 150% DPI settings or to make a text control not to be truncated / cut-out at the bottom/right
Ok.
trismarck wrote:Here is a note on the compatibility setting. Autohotkey is DPI-aware, so compatibility is disabled by default, one can only enable it. But in this thread's scenario, lets leave enable compatibility disabled.
To be precise, Autohotkey is
system DPI–aware. And lets refer to the 'compatibility' setting with its full name - "Disable display scaling on high DPI settings", which is disabled by default.
What "Disable display scaling on high DPI settings" does is it enables or disables DPI virtualization.
For Windows 8.1 and up:
- if the application is not DPI-aware, DPI virtualization makes the application as if the application was per monitor-DPI aware
- if the application is system DPI–aware, DPI virtualization also makes the application as if the application was per-monitor aware (our case).
Note that even if the application has some DPI awareness in it, it doesn't mean the DPI virtualization layer won't trigger.
DPI virtualization introduces side-effects.
From this point onward, lets call "Disable display scaling on high DPI settings" "Disable DPI virtualization".
Enabling "Disable display scaling on high DPI settings" seems to mean: disable DPI virtualization (so that everything works as if on Windows XP, which lacks DPI virtualization altogether). But enabling that option also means:
do be aware of the system DPI setting (just don't provide any mechanism for fixing DPI related issues). This is why in the table, even if DPI virtualization is disabled, Autohotkey's DPIScale still works (which means that the application is still able to read the system DPI setting and that that setting doesn't have to be 100% at that point):
trismarck wrote:- the script uses explicit coords to position Gui window / Gui controls. For explicit coords, DPIScale does take an effect:
- if DPIScale [for a given window] is enabled, positions of Gui window / controls are rescaled according to the DPI of the primary monitor (150% DPI)
- if DPIScale [for a given window] is disabled, positions of Gui window / controls are not rescaled (100% DPI)
This seems to be correct and is actually the mechanism behind Autohotkey being system DPI–aware.
trismarck wrote:- because Autohotkey only really understands one system-level DPI (vs per-monitor DPI), just [statically] using either DPIScale or -DPIScale for particular window won't work - one has to dynamically change DPIScale and redraw controls / the Gui window as the window moves between monitors
Now here is the flaw in my thinking. If DPI virtualization is enabled (which it is, by default), one
doesn't have to change DPI settings 'per-monitor' with DPIScale - the DPI virtualization layer will do it for the application. So the only thing the application should do is: enable DPIScale for all windows (which Autohotkey does by default).
trismarck wrote:Code: Select all
Gui, -DPIScale
Gui, Add, Text, vMyText1, abc
Gui, Add, Text, vMyText2, abc
Gui, Add, Text, vMyText3, abc
Guicontrol, Move, MyText1, x100 y100
Guicontrol, Move, MyText2, x100 y120
Guicontrol, Move, MyText3, x100 y140
Gui, Show, w500 h500
sleep 3000
Gui, +DPIScale
Guicontrol, Move, MyText1, x100 y100
Guicontrol, Move, MyText2, x100 y120
Guicontrol, Move, MyText3, x100 y140
Gui, Show, w500 h500
; positions of all controls rescaled correctly
;
return
GuiClose:
GuiEscape:
Exitapp
The problem with this script is that if dimensions of the Gui window are removed (
Gui, Show) then the Gui window won't be automatically rescaled. And, this is approach is really the wrong way of support DPI scaled applications in the first place (I presume). This is because, from the point of view of a system DPI–aware application, fonts in all text controls are of same height regardless of DPIScale settings for particular gui windows, so disabling DPIScale for a given window will probably make either the text unnaturally large in relation to the margins or will make the margins too small.
trismarck wrote:- In the scenario in this thread, one only deals with 150% DPI or 100% DPI. But if there were more monitors, each having a different DPI setting, one would have to use DPIScale for _each_ particular monitor (which is currently impossible). So perhaps something like DPIScale<DPI> could have been added to Autohotkey so that one could rescale all gui controls according to a custom rescale ratio (according to custom DPI settings) (vs DPIScale just being a bool / ratio being read off of the primary monitor). For now, I guess one could partially workaround that by disabling DPIScale and doing something like: GuiControl, Move, % "x" DPIScale(100) " y" DPIScale(200) (or DPIScale(100, mon1), where DPIScale() would have DPIs of all monitors listed). But would have to rethink the whole approach of whether it would work with auto-sized controls / margins / being compatible with older scripts / other stuff.
I think this falls out too?, bc of the above description.
trismarck wrote://edit:
dev719 wrote:In the two cases with a mx tr value marked >2158, it means that when I went further than the 2/3 of my second screen on the right, nothing happened anymore.
This is because by default, mouse coords are relative to the active window, unless
CoordMode is used. The result of
MouseGetPos has nothing to do with DPI - it's just pixels on the screen.
This seems correct. Another note about the mouse position is that I guess every even row in the table isn't needed, as the mouse coord was retrieved in relation to the active window, but this has nothing to do with DPIScaling.
trismarck wrote:dev719 wrote:Finally solved my problem by moving the gui to the primary screen before moving it to the corresponding screen.
By that, do you mean that you've just always moved the window to the primary monitor? From what I've tested, it doesn't matter as on what monitor the Gui window was first shown up - if coords of the Gui window specified explicitly, the size of the window will always be the same (will only depend on DPIScale, but not on which monitor the Gui window was shown).
I suspect that the monitor on which the gui window is shown first doesn't really matter. The case has to do with something else;
Gui, OSD: Show, x0 y0 Hide does not use
w and
h, while
Gui, OSD: Show, x%ax% y%ay% h100 w100 NA does use it - if one would specify w and h for both of Gui commands, there would have been no discrepancy:
Code: Select all
- Gui, OSD: Show, x0 y0 Hide ; w100 and h100 missing
- Gui, OSD: Show, x%ax% y%ay% h100 w100 NA
Explanation: for Autohotkey Gui commands, it does matter at what point the WinAPI window is actually created / its coords are calculated. Some Autohotkey commands do create a Gui window, but don't change dimensions of that window. I.e.:
Code: Select all
Gui, Add, Text
; gui window created
; gui window has dimensions 0 0 0 0
Gui, 2:Show, Hide
; gui window created
; gui window has dimensions calculated according to controls inside of the window
Gui, 3:Add, Text
; gui control created
; gui control dimensions set
TODO: example for the above, with using DetectHiddenWindows see first example in next post.
TODO: find Ahk documentation about what sentence was about what gui command creates gui window - and create ahk thread about this. Here.
So when one uses
Gui, Show, Hide w/o specifying w and h, dimensions of that gui window are calculated anyway, and bc w and h weren't specified, the width and height of that gui window are generated automatically. So in the table, I guess that the 67 number is just coincidently 2/3 of 100, because how what the OSD window contained. But instead of 67, the value could have been different, i.e. 80 or 30.
Or actually, I think the above effect is related to this part of the source code (and to what width the gui control was resized):
Code: Select all
w := TextWidth(text, 30, "Trebuchet MS")
tw := w + 20
GuiControl, OSD:Move, OSDText, w%w%
GuiControl, OSD:, OSDText, %text%
So 67 is not a coincidence, but the effect described above is likely to still apply.
Other miscellaneous stuff:
- w2 in the legend of the table - add 'b'
- w2 in the table - add 'a'
[/list]
So the most interesting case is with the 2227 x coord. 2260 vs 2227 may be because: SysGet uses GetSystemMetrics(). GetSystemMetrics() _is_ DPI virtualization aware as described
here. So perhaps that DPI virtualization layer interferes with how GetSystemMetrics() reads information about the monitor. Also, because of the values that the author gets, I'd presume there is a taskbar to the left/right of the second monitor? (x'th working area smaller, normally it would have been the y'th coord that changed more.
//edit: actually MonitorWorkArea uses SystemParametersInfo(), to which DPI virtualization doesn't apply?
So what one would wonder about that particular case is this: isn't the value returned by SysGet _correct_? (~the value that one might expect if dpi scaling was per-monitor) .
To position the gui window _always_ at 100px from the bottom of the screen (~ignoring DPI rescaling), perhaps moving the window with something like WinMove would work better than Gui, Show? - not sure if it would entirely skip the dpi cause, but at least WinMove works with pixels only, ignoring DPI settings.
I've made a presumption that all pixel related data in the table was gathered with pixel-only aware functions, like WinMove - so that all dimensions are just pixels on the end screen, regardless of any DPI settings and rescaling on top of that. I.e. on the second screen, window was at 2200x500 and was 500px wide and 600px in height.
Update: not sure if there is actually difference between Gui, Show, x y and WinMove in how gui window is positioned.
TODO: perhaps describe the table again, describing each row separately.
Conclusion
- Use DPIScale, leave DPI virtualization enabled and wonder why x coord isn't like it was supposed to be (is GetSystemMetrics() affected by DPI virtualization?).
- is the system DPI setting 150% DPI or 100% DPI.