高 DPI 缩放、鼠标挂钩和 WindowFromPoint
Posted
技术标签:
【中文标题】高 DPI 缩放、鼠标挂钩和 WindowFromPoint【英文标题】:High DPI scaling, mouse hooks and WindowFromPoint 【发布时间】:2016-09-24 14:41:11 【问题描述】:我有一个设置SetWindowsHookEx(WH_MOUSE_LL, , ,)
右键单击钩子的进程。我的进程在 Window 10.0.10586 上设置为 DPI 系统感知,在两个显示器上以 150% 的比例缩放。这是通过调用SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
设置的。
我的问题场景是例如Office 2007 不知道 DPI,所以让我们将 MS Word 放在屏幕的右四分之一。右击右下角任务栏上方,鼠标钩子发送坐标 1279, 675 - 缩放到 Word。然后我右键单击视觉工作室(DPI 感知),在屏幕上将近四分之三,鼠标钩向我发送坐标,例如1279、1008 来自 Visual Studio。因此,如果我在屏幕上方单击,我可能会得到相同的 1279、675。
我的进程试图通过调用WindowFromPoint
API 来确定该点所在的窗口,但在这种情况下这显然会失败,因为两个应用程序“共享”同一点。
是否可以强制鼠标挂钩始终发送原始物理坐标,而不是那些缩放到 DPI 不感知应用程序的坐标?如果是这样,如何?或者,是否有其他方法可以通过鼠标钩子确定hWnd
或processID
?
【问题讨论】:
【参考方案1】:Microsoft 在 10.0.14393 中修复了它。
除非它们在 LTSB 10.0.10240 上,否则现在您的客户网络中应该没有任何具有较低内部版本号的东西。
这是解决方案:DPI aware screen capture
【讨论】:
【参考方案2】:因为进程是 DPI 感知的,所以在鼠标挂钩回调处理程序中调用 GetCursorPos() 总是获取原始物理坐标,而不是缩放到应用程序的逻辑坐标。只需丢弃传递给鼠标回调的坐标。
于 2016 年 9 月 30 日添加
尽管 GetMessagePos 看起来很可能,但它仅在进程未进行 dpi 虚拟化时才返回正确的坐标,这一点毫无价值。
例如
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 以 175% 的缩放比例返回 1091, 612,虽然算术上正确,但不是必需的。
【讨论】:
听起来是个坏主意。调用 GetCursorPos 时,光标可能在别处。 这是迄今为止我能想到的最好的,而且似乎几乎是瞬间完成的,但我愿意接受任何更好的建议。 GetMessagePos 可能更合适。 我今天试了GetMessagePos,结果没用。它们根本不对应。 看到SetProcessDpiAwareness 是在 Windows 8.1 中引入的,因此相对于 Windows 7 的行为会发生变化,这是预期的结果。由于我们看不到您的代码,因此无法知道您是否正确提取了鼠标位置。文档告诉你怎么做。以上是关于高 DPI 缩放、鼠标挂钩和 WindowFromPoint的主要内容,如果未能解决你的问题,请参考以下文章