高DPI缩放,鼠标挂钩和WindowFromPoint

High DPI scaling, mouse hooks and WindowFromPoint

本文关键字:WindowFromPoint 鼠标 DPI 缩放      更新时间:2023-10-16

我有一个设置SetWindowsHookEx(WH_MOUSE_LL, , ,)右键钩子的进程。我的进程在windows 10.0.10586上以150%的比例设置为DPI系统感知。通过调用SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)设置。

我的问题场景是,例如Office 2007不支持DPI,所以让我们把MS Word放在屏幕的右四分之一。右击右下角任务栏上方,鼠标钩子发送坐标1279,675(按比例缩放到Word)。然后我右键点击visual studio (DPI感知),在屏幕的近四分之三处,鼠标钩子向我发送了visual studio的坐标,例如1279,1008。所以如果我点击屏幕上方,我可能会得到同样的1279,675。

我的进程试图通过调用WindowFromPoint API来确定哪个窗口处于该点,但这显然会在这种情况下失败,因为两个应用程序"共享"。同样的道理

是否有可能强制鼠标钩子总是发送原始的物理坐标,而不是那些缩放到不知道DPI的应用程序?如果有,是怎么做到的?或者,是否有其他方法可以从鼠标钩子中确定hWndprocessID ?

微软在10.0.14393中修复了它。

您的客户端网络中现在应该没有低版本号的东西,除非它们是LTSB 10.0.10240。

这是解决方案:DPI感知屏幕捕获

因为进程是DPI感知的,在鼠标钩子回调处理程序中调用GetCursorPos()总是获取原始的物理坐标,而不是缩放到应用程序的逻辑坐标。只需丢弃传递给鼠标回调函数的坐标。

添加30/09/2016

虽然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()调用期间调用Mouse回调处理程序,但这不会获取DPI虚拟化为进程激活的正确物理坐标。例如,物理x = 1909, y = 1072返回为1091,612,缩放率为175%,虽然这在算术上是正确的,但不是所需要的。