Automação da Interface do Usuário e Escala da Tela

Observação

Esta documentação destina-se a desenvolvedores de .NET Framework que querem usar as classes da Automação da Interface do Usuário gerenciadas definidas no namespace System.Windows.Automation. Para obter as informações mais recentes sobre a Automação da Interface do Usuário, confira API de Automação do Windows: Automação da Interface do Usuário.

A partir do Windows Vista, o Windows permite que os usuários alterem a configuração de pontos por polegada (dpi) para que a maioria dos elementos da interface do usuário na tela pareça maior. Embora esse recurso esteja disponível há muito tempo no Windows, em versões anteriores a escala precisava ser implementada por aplicativos. A partir do Windows Vista, o Gerenciador de Janelas da Área de Trabalho usa a escala padrão para todos os aplicativos que não lidam com o próprio dimensionamento. Os aplicativos cliente de Automação da Interface do Usuário devem levar esse recurso em conta.

Escala no Windows Vista

A configuração de dpi padrão é 96, o que significa que 96 pixels ocupam uma largura ou altura de uma polegada nocional. A medida exata de uma "polegada" depende do tamanho e da resolução física do monitor. Por exemplo, em um monitor de 12 polegadas de largura, com uma resolução horizontal de 1280 pixels, uma linha horizontal de 96 pixels se estende por cerca de 9/10 de polegada.

Alterar a configuração de dpi não é o mesmo que alterar a resolução da tela. Com a escala de dpi, o número de pixels físicos na tela permanece o mesmo. No entanto, a escala é aplicada ao tamanho e ao local dos elementos da interface do usuário. Essa escala pode ser aplicada automaticamente pelo DWM (Desktop Windows Manager, Gerenciador de Janelas da Área de Trabalho) no computador e nos aplicativos que não solicitam explicitamente que não sejam dimensionados.

Na verdade, quando o usuário define o fator de escala como 120 dpi, uma polegada vertical ou horizontal na tela fica 25% maior. Todas as dimensões são adequadamente alteradas. O deslocamento de uma janela de aplicativo das bordas superior e esquerda da tela aumenta em 25%. Se a escala do aplicativo estiver habilitada e ele não tiver reconhecimento de dpi, o tamanho da janela aumentará na mesma proporção, juntamente com os deslocamentos e tamanhos de todos os elementos da interface do usuário que ela contém.

Observação

Por padrão, o DWM não faz o dimensionamento em aplicativos sem reconhecimento de dpi quando o usuário define o dpi como 120, mas o executa quando o dpi está definido como um valor personalizado de 144 ou superior. No entanto, o usuário pode substituir o comportamento padrão.

A escala da tela traz novos desafios para aplicativos que se importam com as coordenadas da tela. A tela agora contém dois sistemas de coordenadas: físico e lógico. As coordenadas físicas de um ponto são o deslocamento real em pixels do canto superior esquerdo da origem. As coordenadas lógicas são os deslocamentos possíveis se os pixels em si fossem dimensionados.

Suponhamos que você crie uma caixa de diálogo com um botão nas coordenadas (100, 48). Quando essa caixa de diálogo for exibida no dpi padrão de 96, o botão estará localizado nas coordenadas físicas de (100, 48). Em 120 dpi, ele estará localizado nas coordenadas físicas de (125, 60). Mas, as coordenadas lógicas são as mesmas em qualquer configuração de dpi: (100, 48).

As coordenadas lógicas são importantes, pois torna consistente o comportamento do sistema operacional e dos aplicativos, independentemente da configuração de dpi. Por exemplo, Cursor.Position normalmente retorna as coordenadas lógicas. Se você mover o cursor sobre um elemento em uma caixa de diálogo, as mesmas coordenadas serão retornadas, independentemente da configuração de dpi. Se você desenhar um controle em (100, 100), ele será desenhado para essas coordenadas lógicas e ocupará a mesma posição relativa em qualquer configuração de dpi.

Escala nos clientes da Automação da Interface do Usuário

A API de Automação da Interface do Usuário não usa coordenadas lógicas. Os métodos e as propriedades a seguir retornam coordenadas físicas ou as tomam como parâmetros.

Por padrão, um aplicativo cliente de Automação da Interface do Usuário em execução em um ambiente que não seja de 96 dpi não será capaz de obter resultados corretos desses métodos e propriedades. Por exemplo, como a posição do cursor está em coordenadas lógicas, o cliente não pode simplesmente passar essas coordenadas para FromPoint a fim de obter o elemento que está sob o cursor. Além disso, o aplicativo não poderá colocar corretamente as janelas fora da área do cliente.

A solução está em duas partes.

  1. Primeiramente, o aplicativo cliente deve ter reconhecimento de dpi. Para isso, chame a função SetProcessDPIAware do Win32 na inicialização. No código gerenciado, a declaração a seguir disponibiliza essa função.

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    internal static extern bool SetProcessDPIAware();
    
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Friend Shared Function SetProcessDPIAware() As Boolean
    End Function
    

    Essa função faz com que todo o processo tenha reconhecimento de dpi, o que significa que todas as janelas que pertencem ao processo estão fora de escala. Na Amostra de realce, por exemplo, as quatro janelas que compõem o retângulo de realce estão localizadas nas coordenadas físicas obtidas da Automação da Interface do Usuário e não das coordenadas lógicas. Se a amostra não tivesse reconhecimento de dpi, o realce seria desenhado nas coordenadas lógicas na área de trabalho, o que resultaria em um posicionamento incorreto em um ambiente que não fosse 96 dpi.

  2. Para obter as coordenadas do cursor, chame a função GetPhysicalCursorPos do Win32. O exemplo a seguir mostra como declarar e usar essa função.

    public struct CursorPoint
    {
        public int X;
        public int Y;
    }
    
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    internal static extern bool GetPhysicalCursorPos(ref CursorPoint lpPoint);
    
    private bool ShowUsage()
    {
        CursorPoint cursorPos = new CursorPoint();
        try
        {
            return GetPhysicalCursorPos(ref cursorPos);
        }
        catch (EntryPointNotFoundException) // Not Windows Vista
        {
            return false;
        }
    }
    
    Structure CursorPoint
        Public X As Integer
        Public Y As Integer
    End Structure
    
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Friend Shared Function GetPhysicalCursorPos(ByRef lpPoint As CursorPoint) As Boolean
    End Function
    
    Private Function ShowUsage() As Boolean
    
        Dim cursorPos As New CursorPoint()
        Try
            Return GetPhysicalCursorPos(cursorPos)
        Catch e As EntryPointNotFoundException ' Not Windows Vista
            Return False
        End Try
    
    End Function
    

Cuidado

Não use Cursor.Position. O comportamento dessa propriedade fora das janelas do cliente em um ambiente dimensionado é indefinido.

Se o aplicativo executar comunicação direta entre processos com aplicativos sem reconhecimento de dpi, talvez você precise converter entre coordenadas lógicas e físicas usando as funções PhysicalToLogicalPoint e LogicalToPhysicalPoint do Win32.

Confira também