首页 > 解决方案 > 在多 DPI 环境中将 HIMETRIC 转换为像素

问题描述

我的 UI 框架使用双精度值作为像素坐标,这在视网膜显示器上为我提供了很好的分数虚拟坐标。为此,我以 HIMETRIC 单位从 Windows 获取鼠标坐标。但是,我遇到了一个我无法弄清楚的错误。

我将 Surface Book 2 (3000x2000 @ 225%) 插入带有两个外接显示器 (1920x1080 @ 100%) 的底座。如果我在插入扩展坞的情况下登录 Windows(并将外接显示器 @ 100% 设置为主要显示器),我会收到正确的 HIMETRIC 坐标,该坐标可在外部显示器和视网膜显示器上工作。

但是,如果我在 Dock 未插入的情况下登录到 Windows,那么只有视网膜显示器,然后插入 Dock,然后运行我的应用程序 - 现在它接收由显示器的缩放因子缩放的HIMETRIC 坐标,这在我是主要的登录到 Windows

我已将我的应用程序的 DPI 感知设置为 PerMonitorV2,这就是为什么我觉得每个系统的 DPI 比例设置甚至与我的应用程序相关如此奇怪的原因。

这是我用来从 HIMETRIC 转换的函数:

double fromHimetric(uint i)
{
    return (double)i / 2540 * Monitor::DefaultDPI; 
}

Monitor::DefaultDPI是一个设置为 96 的常量。

我错过了什么吗?我需要在公式中添加系统比例因子吗?在这种情况下,当我登录 Windows 时,如何找出哪个显示器是主要显示器?因为无论我将窗口移动到哪个监视器,这似乎都保持不变,因为我收到的 HIMETRIC 值显然是按过去的值缩放的。

编辑:因为多显示器的东西很难在互联网上描述,所以我制作了一个小视频,展示了这个错误是如何为我表现出来的。https://www.youtube.com/watch?v=pTZiTZFXsc0

编辑 2:为了进一步澄清,我的应用程序完全尊重每个显示器的 DPI,我的所有 UI 都是矢量化的,因此它可以正确缩放,我处理WM_DISPLAYCHANGE所有WM_DPICHANGED这些东西。笔和触摸坐标在所有情况下都可以正常工作。

如果我最初启动计算机时,唯一会中断的是,我从鼠标获得的 HIMETRIC 坐标是GetPointerInfo()由计算机启动时主要的显示器的显示比例缩放的。

我努力确保我能很好地处理多显示器多 DPI 情况。如果我忽略了一件简单的事情会破坏一切,我会感到非常愚蠢。

编辑 3:看看 Chrome 中的滚动条有多大。https://imgur.com/a/F3dFHAj

或 OBS 工作室:https ://imgur.com/a/11aG5Kw

他们似乎遭受了类似的错误。不知道他们的是否与 HIMETRIC 有任何关系,但这些元素的呈现方式会根据我启动计算机的方式而有所不同。

Win32 是否定义了启动监视器之类的东西?

编辑 4:我不使用的原因AtlHiMetricToPixel()PhysicalToLogicalPoint()它们返回整数逻辑坐标,并且我特别希望在逻辑空间中使用双精度,因为我的整个 UI 都是基于矢量的。我自己做所有的缩放,它似乎工作正常,除了在这种情况下。:(

标签: windowswinapicoordinatesdpimultiple-monitors

解决方案


对于任何对此感兴趣的人,我在这里得到了答案。

会话登录时主监视器的 DPI 为

HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics | AppliedDPI

我已经对其进行了测试,根据我的登录方式,它总是正确的。所以在我的情况下,我的应用程序只需要在启动时从注册表中读取它,然后使用它来调整鼠标的传入 HIMETRIC 坐标。


推荐阅读