Introduction
As we all know, we have two methods to get the mouse position which is relative to other controls. One is Mouse.GetPosition(IInputElement relativeTo)
, the other is MouseEventArgs.GetPosition(IInputElement relativeTo)
. But, what will we get when the mouse is outside the window’s client area? And how does it calculate?
This article is to tell developers about what and how we get the mouse coordinate.
Detail
The original link is WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里? - walterlv. But this blog was written in Chinese, so I translate its content to English. Waterlv is an MVP(Microsoft Most Valuable Professional), and he is good at .NET Core\WPF\.NET. Here is his Blog.
Demo
Creates a default WPF application with Visual Studio 2019. And this application is developed with default .NET Core version, it contains a Button
and Textblock
. Now, we try to get mouse position relative to these two FrameworkElement
with Mouse.GetPosition
method. Here are the codes.
1 | using System; |
Observation
We ran this simple application, then we noticed that when the mouse is outside the window’s client area, the values of mouse position are exactly the same. See this .gif file below for more details.
For more information about Client Area, visit
WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome).
This blog was written in Chinese. I will translate it later.
Conclusion
We can get a conclusion from the messages applied above, the coordinate we get when the mouse is outside window client area is the screen’s left top position (0,0)
.
We moved the window to the screen’s left top position to check our conclusion. And then we got the coordinate of outside mouse position, and the value is (0,31)
.
It should note that
31
is the height of the window’s title bar.
It shows that the conclusion is right. So, how does GetPosition
work?
Theory
After reading the source code of the GetPosition
method. It is easy to find that it gets the coordinate depends on ClientToScreen
API.
Here is the source codes.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28[ ]
internal Point GetScreenPositionFromSystem()
{
// Win32 has issues reliably returning where the mouse is. Until we figure
// out a better way, just return the last mouse position in screen coordinates.
Point ptScreen = new Point(0, 0);
// Security Mitigation: do not give out input state if the device is not active.
if (IsActive)
{
try
{
PresentationSource activeSource = CriticalActiveSource;
if (activeSource != null)
{
ptScreen = PointUtil.ClientToScreen(_lastPosition, activeSource);
}
}
catch (System.ComponentModel.Win32Exception)
{
// The window could be shutting down, so just return (0,0).
ptScreen = new Point(0, 0);
}
}
return ptScreen;
}
1 | [ ] |
And here is the definition of the ClientToScreen
method in user32.dll
.1
2[ ]
static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
This method requires a window handle hWnd
as a parameter,and its usage is listed below.
A handle to the window whose client area is used for the conversion.
Essentially, we use the ClientToScreen
method to get the mouse’s coordinate. And this method will return two different results:
- If the function succeeds, the return value is nonzero.
- If the function fails, the return value is zero.
So, this function fails when the mouse position is outside the window client area.And ClientToScreen
returns (0,0) as result. Then, it will run the ToPoint
method to translate the coordinate to relative control’s coordinate system. And that is the result we saw.