在多 DPI 环境中将 HIMETRIC 转换为像素
Converting HIMETRIC to pixels in a multi-DPI environment
我的 UI 框架对像素坐标使用双精度值,这在视网膜显示器上为我提供了很好的分数虚拟坐标。为此,我以 HIMETRIC 单位从 Windows 获取鼠标坐标。但是,我 运行 遇到了一个我无法弄清楚的错误。
我将 Surface Book 2 (3000x2000 @ 225%) 插入带有两个外接显示器 (1920x1080 @ 100%) 的扩展坞。如果我在插入扩展坞的情况下登录 Windows(并且外接显示器 @ 100% 设置为主要显示器),我会收到正确的 HIMETRIC 坐标,该坐标适用于外接显示器和视网膜显示器。
但是,如果我在拔下扩展坞时登录 Windows,那么 只有 视网膜显示器,然后插入扩展坞,然后 运行 我的应用程序 — 现在它接收 HIMETRIC 坐标 由显示的比例因子缩放,当我登录 Windows 时, 是主要的 .
我已将我的应用程序的 DPI 感知设置为 PerMonitorV2,这就是为什么我觉得每个系统的 DPI 比例设置甚至与我的应用程序相关如此奇怪。
这是我用来从 HIMETRIC 转换的函数:
double fromHimetric(uint i)
{
return (double)i / 2540 * Monitor::DefaultDPI;
}
Monitor::DefaultDPI
是一个设置为 96 的常量。
我错过了什么吗?我是否需要在公式中添加系统比例因子?在那种情况下,我如何在登录 Windows 时找出哪个监视器是主监视器?因为无论我将 window 移动到哪个监视器,这似乎都保持不变,因为我收到的 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()
的原因是它们 return 整数逻辑坐标,我特别想要逻辑 space 中的双打,因为我的整个 UI 是基于矢量的。我自己做了所有的缩放,它似乎工作正常,除了这个案例。 :(
对于任何对此感兴趣的人,我得到了答案 here。
会话登录时主监视器的 DPI 为
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics | AppliedDPI
我已经对其进行了测试,它始终是正确的,具体取决于我的登录方式。因此,在我的情况下,我的应用程序只需在启动时从注册表中读取它,然后使用它来调整鼠标的传入 HIMETRIC 坐标。
我的 UI 框架对像素坐标使用双精度值,这在视网膜显示器上为我提供了很好的分数虚拟坐标。为此,我以 HIMETRIC 单位从 Windows 获取鼠标坐标。但是,我 运行 遇到了一个我无法弄清楚的错误。
我将 Surface Book 2 (3000x2000 @ 225%) 插入带有两个外接显示器 (1920x1080 @ 100%) 的扩展坞。如果我在插入扩展坞的情况下登录 Windows(并且外接显示器 @ 100% 设置为主要显示器),我会收到正确的 HIMETRIC 坐标,该坐标适用于外接显示器和视网膜显示器。
但是,如果我在拔下扩展坞时登录 Windows,那么 只有 视网膜显示器,然后插入扩展坞,然后 运行 我的应用程序 — 现在它接收 HIMETRIC 坐标 由显示的比例因子缩放,当我登录 Windows 时, 是主要的 .
我已将我的应用程序的 DPI 感知设置为 PerMonitorV2,这就是为什么我觉得每个系统的 DPI 比例设置甚至与我的应用程序相关如此奇怪。
这是我用来从 HIMETRIC 转换的函数:
double fromHimetric(uint i)
{
return (double)i / 2540 * Monitor::DefaultDPI;
}
Monitor::DefaultDPI
是一个设置为 96 的常量。
我错过了什么吗?我是否需要在公式中添加系统比例因子?在那种情况下,我如何在登录 Windows 时找出哪个监视器是主监视器?因为无论我将 window 移动到哪个监视器,这似乎都保持不变,因为我收到的 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()
的原因是它们 return 整数逻辑坐标,我特别想要逻辑 space 中的双打,因为我的整个 UI 是基于矢量的。我自己做了所有的缩放,它似乎工作正常,除了这个案例。 :(
对于任何对此感兴趣的人,我得到了答案 here。
会话登录时主监视器的 DPI 为
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics | AppliedDPI
我已经对其进行了测试,它始终是正确的,具体取决于我的登录方式。因此,在我的情况下,我的应用程序只需在启动时从注册表中读取它,然后使用它来调整鼠标的传入 HIMETRIC 坐标。