WindowFromPhysicalPoint is new with Vista. Its documentation is almost identical to WindowFromPoint. What's the difference? Both seem to take an absolute point (offset from screen origin) and return the topmost (Z order) HWND that contains the point.
http://msdn.microsoft.com/en-us/library/ms633533(VS.85).aspx
Windows Vista introduces the concept of physical coordinates. Desktop Window Manager (DWM) scales non-dots per inch (dpi) aware windows when the display is high dpi. The window seen on the screen corresponds to the physical coordinates. The application continues to work in logical space. Therefore, the application's view of the window is different from that which appears on the screen. For scaled windows, logical and physical coordinates are different.
WindowFromPhysicalPoint operates in physical screen coordinates, while WindowFromPoint works with logical ones. To understand the different read this page.
TL;DR; version would be:
Suppose you design a dialog box with a button at coordinates (100,
48). When this dialog box is displayed at the default 96 dpi, the
button is located at physical coordinates of (100, 48). At 120 dpi, it
is located at physical coordinates of (125, 60). But the logical
coordinates are the same at any dpi setting: (100, 48).
So unless you design your app to be DPI aware I would stick with logical coordinates, since most APIs and window messages operate in logical space. Another reason to use logical coordinates is to make your app backward compatible with Windows XP.
Related
Recently, I read this excellent page about DPI on Win32:
DPI and device-independent pixels
However, I am confused about GetDeviceCaps(hdc, LOGPIXELSX/Y) vs GetDpiForSystem(). On systems where I tested, all three values always match.
Questions:
Is it possible for GetDeviceCaps(hdc, LOGPIXELSX) and GetDeviceCaps(hdc, LOGPIXELSY) to return different values? I assume that LOGPIXELS means DPI. (Please correct me if wrong!)
If the previous answer is yes, then is GetDeviceCaps(GetDC(NULL), LOGPIXELSX/Y) the same as GetDpiForSystem()?
When possible, I should be using GetDpiForWindow(hWnd), but I want to clarify my understanding about "system" DPI in my questions above.
As far as I'm concerned, GetDeviceCaps(hdc, LOGPIXELSX/Y) is not a match with GetDpiForSystem().
LOGPIXELSX:Number of pixels per logical inch along the screen width.
In a system with multiple display monitors, this value is the same for
all monitors.
LOGPIXELSY:Number of pixels per logical inch along the screen height.
In a system with multiple display monitors, this value is the same for
all monitors.
This function is not able to return a per-monitor DPI. For that, you should use GetDpiForWindow().
GetDpiForWindow() also returns a different value based on the DPI_AWARENESS value.
GetDpiForSystem() returns the system DPI. The return value will be dependent based upon the calling context. If the current thread has a DPI_AWARENESS value of DPI_AWARENESS_UNAWARE, the return value will be 96.
Is it possible for GetDeviceCaps(hdc, LOGPIXELSX) != GetDeviceCaps(hdc, LOGPIXELSY)? I assume that "LOGPIXELS" means DPI. (Please correct me if wrong!)
For monitors, I believe LOGPIXELSX == LOGPIXELSY even if your display has non-square pixels (which is extremely rare nowadays). There are still many printers out there that have different horizontal and vertical dot densities. In some cases, the printer driver may hide that, giving the illusion of square pixels. Among ones that don't, you not only have to be careful to use the right value for the context, but you should be aware the some drivers forget to swap the horizontal and vertical values when you change the page orientation to landscape.
LOGPIXELSX and LOGPIXELSY refer to the number of pixels per logical inch, an idea that's been buried in recent versions of Windows. You used to be able to tell Windows that, when a program wants to display something that's 1-inch long, use my logical inch value rather than the actual DPI. (In the olden days of CRT monitors, it was usually impossible for Windows to discover the actual DPI anyway.)
Common values for logical inches were 96 and 120. If you had a really high-end monitor, you might've used 144. If you were into WYSIWYG applications or desktop publishing, you'd usually choose a value that was about 20% larger than an actual inch on your screen. I've heard various rationales for this, but I usually chose a higher value for easier reading.
When possible, I should be using GetDpiForWindow(hWnd)
That's fine. I use LOGPIXELSX and LOGPIXELSY because I'm old school and have always written high-DPI aware code.
but I want to clarify my understanding about "system" DPI in my questions above.
I believe the system DPI is the scaled DPI of the primary monitor. The scaling gives the programmer the same functionality as a logical inch, but it's presented to the user in a different way conceptually.
On systems where I tested, all three values always match.
Yes, it's very common for all of the methods to report the same DPI.
If your program is not high-DPI aware, you'll get 96 regardless of how you ask.
If it is aware, the system DPI is the DPI of the primary monitor. (Well, it's the possibly scaled native DPI of the monitor, but that's the same value you'll be told for the DPI of monitor.)
That covers a lot of common cases. To truly and thoroughly test, you'd need a second monitor with a different native DPI than the primary.
A couple points to keep in mind.
GetDeviceCaps approach is specific to the device context you reference with the HDC parameter. Remember that you can have printer DCs, enhanced metafile DCs, and memory DCs in addition to screen DCs. For screens, the return value will depend on the DPI awareness.
DPI awareness comes into play for screens (not printers). Your program's UI thread can be:
DPI unaware, in which all methods will return 96 dots per inch and actual differences will/might be handled by the system scaling things on the backend.
DPI aware, in which case most will return the system DPI. I believe the system DPI is the (scaled?) DPI of the primary monitor, but I'm not sure about that.
per-monitor DPI aware, in which case the GetDeviceCaps and GetDpiForWindow will return the actual DPI of the monitor that's referenced by the DC. I don't recall what it returns if the DC spans multiple monitors.
It might by the actual DPI if the monitors spanned have the same DPI, or it might be the system DPI, or it might be the DPI of one of the spanned monitors.
GetDpiForMonitor ignores DPI awareness altogether. I assume it remains for backward compatibility.
I know that I can collage display by Intel® Graphics Control Panel and Intel® Graphics Command Center.
However, can I collage display programmatically? Whatever the solution is Windows API, Intel API, Powershell, Command Line or any document.
Waiting for help, thanks!
I think you can do that with ChangeDisplaySettingsEx WinAPI. Set DM_POSITION bit in dmFields, and dmPosition to the value.
To find monitor device names, and current rectangles, EnumDisplayMonitors and GetMonitorInfo.
Couple more notes.
The primary display has top left position [ 0, 0 ] and you can’t change that. However, coordinates are signed integers, so you can set some other display position to negative X.
Beware of DPI scaling. The units you’ll be getting in the rectangles, and setting in the offsets, depend on DPI awareness manifest of your program.
My colleagues seem to have a lot of trouble using my AHK scripts and it sounds like the MouseClicks are not clicking the right positions within the active windows.
Both parties here are using Windows 7.
Their resolution is 1600 x 900 where as I'm using 1280 x 1024.
I thought the relative positions to a given window would be different so I got my IT people to get 16:9 monitors today for the computer next to mine. Unfortunately the monitors don't support 1600 x 900 resolution and when I noticed that I didn't check the coordinates on those monitors because it wasn't the right resolution.
I was looking around for another way to convert the coordinates to that resolution and found a thread that says converting my coordinates is as simple as:
x1 * 1600/1280 = x2
y1 * 900/1024 = y2
I applied this formula to the MouseClick command coordinates and I tested it on different resolutions and the clicks go to the wrong position everytime.
However, the regular coordinates from my starting resolution still work.
I'm not sure anymore if the coordinates are the problem which is why I'm here asking.
Thank you.
No. The coordinate system or point of origin is not affected by screen resolution, nor are the coordinates for the window itself.
However, the size or contents of the window may change depending on any number of factors, including screen resolution. It is up to the application.
Window coordinates (the default for most commands in AutoHotkey v1) depend on the current system theme and other settings which affect the size of the window's title bar and borders.
Client coordinates (the default for AutoHotkey v2) are less affected by differences between systems, so are recommended over Window coordinates.
Whatever the coord mode, any values you hard code in the script will need to take into account whatever changes in layout might occur within the application. Again, what those changes are depends on the application.
If the system has multiple monitors and they do not all have the same DPI (scaling), the system "lies" about the coordinates of objects on monitors other than the primary one, unless the program retrieving the coordinates is per-monitor DPI aware. This can cause issues with AutoHotkey, which is not per-monitor DPI aware.
If I maximize a Delphi form the width and height values are 8 pixles greater that the corresponding GetSystemMetrics SM_CXSCREEN and SM_CYSCREEN?
For Example:
When I right click on my screen and get properties I have a 1680 X 1050 screen resolution. Those are the same values returned from GetSystemMetrics(SM_CXSCREEN) and GetSystemMetrics(SM_CYSCREEN).
When I maximize the form in my Delphi application I get a width of 1688 and a height of 1058. There is an 8 pixel difference. What causes this difference?
When maximized windows were originally implemented, the designers wanted to remove the resizing borders. Rather than removing them, they instead decided to draw those borders beyond the edges of the screen, where they would not be seen. Hence the rather surprising window rectangle of a maximized window.
This implementation decision became a problem with the advent of multi-monitor systems. By that time there were applications that relied on this behaviour and so the Windows team decided to retain the behaviour for the sake of compatibility. This meant that maximized windows leaked onto neighbouring screens. In time the window manager acquired capabilities that meant it could suppress that leakage.
Raymond Chen, as usual, has an article that covers the details: Why does a maximized window have the wrong window rectangle?
I wrote simple program, which catches WM_GETMINMAXINFO. This message allows one to modify position and size of maximized window, before the actual maximization takes place. The default values provided by system were:
Position.x: -8
Position.y: -8
Size.x: 1456 (= 8 + width of screen + 8)
Size.y: 916 (= 8 + height of screen + 8)
The resolution of my screen is 1440x900.
It seems, that Windows positions the window after the maximization in such way, that the client area covers the most the available space and window's chrome is hidden outside the screen area.
experts.
How I can query the mouse DPI (pointer resolution) on Windows?
I read the article Pointer Ballistics for Windows XP. It says "the typical pointer resolution is 400 mickey/inch". But how I can query the exact value used by various kinds of mice?
It would be great if you could also point me to documents related to this topic.
Thanks!
It's impossible to tell. The mouse DPI is simply the number of times the mouse reports a change in location when it's moved by one inch. On the other side of the mouse cord all you know is that you periodically get a change in location, and you simply move the pointer on the screen every time.
One thing you can do if this is critically important for some special application is to have the user move his/her mouse exactly one inch and count the changes in location. If you're doing this in some professional environment then it's probably worth your while to issue special equipment- give your users the same model of high-end mouse with a particular known DPI. I say high-end because for most mice the approximate DPI number will be ludicrously inaccurate.