【发布时间】:2020-10-11 10:16:59
【问题描述】:
我有以下鼠标钩子程序(为解释而简化)。
SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, GetModuleHandle(NULL), 0) ;
LRESULT mouseHookProc(int code, WPARAM wParam, LPARAM lParam){
if(code==HC_ACTION){
const auto& data = *(MSLLHOOKSTRUCT*)lParam ;
data.pt ; //This point gives physical coordinates. It ignores the monitor's scaling factor.
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msllhookstruct
}
return CallNextHookEx(NULL, code, wParam, lParam) ;
}
我从钩子上得到的鼠标坐标没有被显示器的比例因子调整。
无论我将显示器的缩放系数设置为 100% 还是 200%,鼠标挂钩总是给我物理像素。
另一方面,GetCursorPos winapi 函数以逻辑像素给出坐标。即如果缩放因子为 200%,GetCursorPos 将给出除以 2 的坐标,而鼠标钩将给出未经调整的数字。
如果程序不支持 DPI,则系统会补偿缩放因子,以便程序像什么都没发生一样继续工作。
这正是GetCursorPos 的返回值所发生的情况。它提供的是逻辑像素而不是物理像素。
另一方面,鼠标钩子程序并没有被系统调整。
我尝试在清单中将我的程序设置为不支持 DPI,如下:
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
但这并没有什么区别。 我还尝试将其声明为可识别 DPI,如下所示:
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware>True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
这也没什么区别。
我是否可以通过清单或其他方式将任何设置添加到我的程序中,这将使鼠标钩子程序像GetCursorPos 一样提供逻辑坐标?
我正在 Windows 10 中测试所有这些。
跟进:
我发现了问题。我的清单文件不正确。 XML 命名空间设置不正确。
这是一个有效的方法。
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" name="AppName" type="win32"/>
<asmv3:application>
<asmv3:windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
为了让系统为程序提供逻辑坐标,程序必须能够识别 DPI。 不具备 DPI 感知能力的程序在处理坐标时会不一致,不仅在鼠标钩子中,在 BitBlt、IAccesibility、UIAutomation 等中也是如此。
我不明白为什么微软决定倒退。没有表现出 DPI 意识的程序应该像往常一样运行,而不是相反。
这意味着每当在监视器上设置缩放因子时,大多数程序都会默认中断。为了破解它们,它们必须具备 DPI 意识,并且......就像那样......它们会再次工作。
【问题讨论】:
-
一个低级鼠标钩子在系统开始确定目标窗口之前运行。因此,系统无法对坐标应用任何类型的虚拟化。
标签: winapi windows-10 mouse-hook mouse-coordinates dpi-aware