活动辅助功能和 Windows Vista 屏幕缩放

Windows Vista 使用户能够更改每英寸点数 (dpi) 设置,以便屏幕上的大多数 UI 元素显示得更大。 尽管此功能在 Microsoft Windows 中早已可用,但在早期版本中,缩放必须由应用程序实现。 在 Windows Vista 中,桌面窗口管理器对所有不处理自身缩放的应用程序执行默认缩放。 Microsoft Active Accessibility 客户端应用程序必须考虑此功能。

Windows Vista 中的缩放

默认 dpi 设置为 96,这意味着 96 像素占名义上一英寸的宽度或高度。 “一英寸”的确切度量取决于监视器的大小和物理分辨率。 例如,在 12 英寸宽、水平分辨率为 1280 像素的监视器上,96 像素的水平线将扩展大约 9/10 英寸。

更改 dpi 设置与更改屏幕分辨率不同。 通过 dpi 缩放,屏幕上的物理像素数保持不变。 但是,缩放将应用于 UI 元素的大小和位置。 桌面窗口管理器 (DWM) 可以自动对桌面和未显式要求缩放的应用程序执行这种扩展。

实际上,当用户将缩放比例设置为 120 dpi 时,屏幕上的垂直或水平英寸将增大 25%。 所有尺寸会相应缩放。 窗口与屏幕上边缘和左边缘的偏移量增加 25%。 窗口的大小以相同的比例增加,以及它包含的所有 UI 元素的偏移量和大小。

默认情况下,当用户将 dpi 设置为 120 时,DWM 不会对非 dpi 感知应用程序执行缩放,但当 dpi 被设置为自定义值 144 或更高值时,将执行缩放。 但是,用户可以重写默认行为。

屏幕缩放为以任何方式与屏幕坐标有关的应用程序带来了新的挑战。 屏幕现在包含两个坐标系:物理和逻辑。 点的物理坐标是距原点左上部的实际偏移量(以像素为单位)。 如果像素本身进行了缩放,则逻辑坐标为缩放后的偏移量。

假定你设计了一个对话框,其按钮位于坐标 (100, 48) 处。 当此对话框按默认值 96 dpi 显示时,该按钮所处的物理坐标为 (100, 48)。 当为 120 dpi 时,它所处的物理坐标为 (125, 60)。 但逻辑坐标与 dpi 设置相同:(100, 48)。

逻辑坐标非常重要,因为它们使操作系统和应用程序的行为保持一致,而不考虑 dpi 设置。 例如, System.Windows.Forms.Cursor.Position 通常返回逻辑坐标。 如果将光标移至对话框中的某个元素,则将返回相同的坐标,而不考虑 dpi 设置。 如果你在 (100, 100) 处拖动控件,它将被拖到这些逻辑坐标,并将占用与任何 dpi 设置相同的相对位置。

在活动辅助功能客户端中缩放

Microsoft Active Accessibility 不使用逻辑坐标。 以下方法和函数要么返回物理坐标,要么将它们作为参数。

默认情况下,在非 96 dpi 环境中运行的 Microsoft Active Accessibility 客户端应用程序将无法从这些调用中获得正确的结果。 例如,由于光标位置位于逻辑坐标中,因此客户端不能简单地将这些坐标传递给 AccessibleObjectFromPoint 来获取游标下的元素。

此外,在其工作区之外创建窗口的应用程序(例如突出显示重点 UI 元素的辅助功能应用程序)不会在正确的屏幕位置创建窗口,因为该窗口将放置在逻辑坐标上,而不是 IAccessible::accLocation 返回的物理坐标。

解决方案分为两部分:

  • 使客户端应用程序“dpi 感知”。 为此,请在启动时调用 SetProcessDPIAware 函数。 此函数使得整个进程成为 dpi 感知的进程,这意味着属于该进程的所有窗口都不会被缩放。
  • 使用 dpi 感知函数。 例如,若要获取光标坐标,请调用 GetPhysicalCursorPos 函数。 请勿使用 GetCursorPos;它在 dpi 感知应用程序中的行为未定义。

如果应用程序与非 dpi 感知应用程序执行直接跨进程通信,则可能已使用 PhysicalToLogicalPointLogicalToPhysicalPoint 函数在逻辑坐标和物理坐标之间进行转换。