高 DPI 缩放、鼠标挂钩和 WindowFromPoint
High DPI scaling, mouse hooks and WindowFromPoint
我有一个设置 SetWindowsHookEx(WH_MOUSE_LL, , ,)
右键单击挂钩的进程。我的进程在 Window 10.0.10586 上设置为 DPI 系统感知,在两个显示器上缩放比例为 150%。这是通过调用 SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
.
设置的
我的问题场景是Office 2007 不支持 DPI,所以让我们将 MS Word 放在屏幕的右四分之一处。右击右下角任务栏上方,鼠标钩发送坐标 1279、675 - 缩放到 Word。然后我右键单击 visual studio(DPI 感知),在屏幕上将近四分之三,鼠标钩向我发送坐标,例如来自 Visual Studio 的 1279、1008。因此,如果我点击屏幕上方的位置,我可能会得到相同的 1279、675。
我的进程试图通过调用 WindowFromPoint
API 来确定哪个 window 在该点,但是在这种情况下这显然会失败,因为两个应用程序“共享”相同点。
是否可以强制鼠标挂钩始终发送原始物理坐标,而不是那些缩放到 DPI 不感知应用程序的坐标?如果是这样,怎么办?或者,是否有其他方法可以通过鼠标挂钩确定 hWnd
或 processID
?
因为进程是 DPI 感知的,所以在鼠标钩子回调处理程序中调用 GetCursorPos() 总是获取原始物理坐标,而不是按比例缩放到应用程序的逻辑坐标。只需丢弃传递给鼠标回调的坐标。
添加于 2016 年 9 月 30 日
尽管 GetMessagePos 似乎有可能,但如果进程未虚拟化 dpi,则仅 returns 候选它是正确的坐标。
例如
VOID MessagePump()
{
MSG messageGet = { 0 };
DWORD dwPos;
POINTS p;
while (GetMessage(&messageGet,NULL,0,0))
{
dwPos = GetMessagePos();
p = MAKEPOINTS( dwPos );
TranslateMessage( &messageGet );
DispatchMessage( &messageGet );
}
}
鼠标回调处理程序在 GetMessage() 调用期间被调用,但这不会获取正确的物理坐标,其中 DPI 虚拟化对于进程是活动的。例如物理 x = 1909, y = 1072 返回为 1091, 612 缩放比例为 175%,虽然在算术上是正确的,但这并不是所需要的。
Microsoft 在 10.0.14393 中修复了它。
您的客户端网络中现在应该没有任何内部版本号较低的东西,除非它们在 LTSB 10.0.10240 上。
这是解决方案:
我有一个设置 SetWindowsHookEx(WH_MOUSE_LL, , ,)
右键单击挂钩的进程。我的进程在 Window 10.0.10586 上设置为 DPI 系统感知,在两个显示器上缩放比例为 150%。这是通过调用 SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
.
我的问题场景是Office 2007 不支持 DPI,所以让我们将 MS Word 放在屏幕的右四分之一处。右击右下角任务栏上方,鼠标钩发送坐标 1279、675 - 缩放到 Word。然后我右键单击 visual studio(DPI 感知),在屏幕上将近四分之三,鼠标钩向我发送坐标,例如来自 Visual Studio 的 1279、1008。因此,如果我点击屏幕上方的位置,我可能会得到相同的 1279、675。
我的进程试图通过调用 WindowFromPoint
API 来确定哪个 window 在该点,但是在这种情况下这显然会失败,因为两个应用程序“共享”相同点。
是否可以强制鼠标挂钩始终发送原始物理坐标,而不是那些缩放到 DPI 不感知应用程序的坐标?如果是这样,怎么办?或者,是否有其他方法可以通过鼠标挂钩确定 hWnd
或 processID
?
因为进程是 DPI 感知的,所以在鼠标钩子回调处理程序中调用 GetCursorPos() 总是获取原始物理坐标,而不是按比例缩放到应用程序的逻辑坐标。只需丢弃传递给鼠标回调的坐标。
添加于 2016 年 9 月 30 日
尽管 GetMessagePos 似乎有可能,但如果进程未虚拟化 dpi,则仅 returns 候选它是正确的坐标。
例如
VOID MessagePump()
{
MSG messageGet = { 0 };
DWORD dwPos;
POINTS p;
while (GetMessage(&messageGet,NULL,0,0))
{
dwPos = GetMessagePos();
p = MAKEPOINTS( dwPos );
TranslateMessage( &messageGet );
DispatchMessage( &messageGet );
}
}
鼠标回调处理程序在 GetMessage() 调用期间被调用,但这不会获取正确的物理坐标,其中 DPI 虚拟化对于进程是活动的。例如物理 x = 1909, y = 1072 返回为 1091, 612 缩放比例为 175%,虽然在算术上是正确的,但这并不是所需要的。
Microsoft 在 10.0.14393 中修复了它。
您的客户端网络中现在应该没有任何内部版本号较低的东西,除非它们在 LTSB 10.0.10240 上。
这是解决方案: