Como lidar com mensagens de entrada de teclado no formulário

O Windows Forms fornece a capacidade de lidar com mensagens de teclado no nível do formulário, antes que as mensagens atinjam um controle. Este artigo mostra como realizar essa tarefa.

Manipular uma mensagem de teclado

Manipule o evento KeyPress ou KeyDown do formulário ativo e defina a propriedade KeyPreview do formulário como true. Essa propriedade faz com que a entrada do teclado atinja o formulário antes de atingir todos os controles no formulário. O exemplo de código a seguir manipula o KeyPress evento detectando todas as chaves numéricas e consumindo 1, 4 e 7.

// Detect all numeric characters at the form level and consume 1, 4, and 7.
// Form.KeyPreview must be set to true for this event handler to be called.
void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (char.IsDigit(e.KeyChar))
    {
        MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' pressed.");

        switch (e.KeyChar)
        {
            case '1':
            case '4':
            case '7':
                MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' consumed.");
                e.Handled = true;
                break;
        }
    }
}
' Detect all numeric characters at the form level and consume 1, 4, and 7.
' Form.KeyPreview must be set to true for this event handler to be called.
Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs)
    If Char.IsDigit(e.KeyChar) Then
        MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' pressed.")

        Select Case e.KeyChar
            Case "1"c, "4"c, "7"c
                MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' consumed.")
                e.Handled = True
        End Select
    End If

End Sub

Quando KeyPreview não for suficiente

A configuração Form.KeyPreview = true não garante que cada chave atinja manipuladores de eventos no nível do formulário. Determinadas chaves passam pelo pré-processamento antes da execução de eventos de formulário padrão. Entender essas exceções é importante para lidar corretamente com chaves de comando, chaves de diálogo e entrada específica do controle.

Pré-processamento de teclas de comando e de caixa de diálogo

Antes que os eventos de teclado no nível do formulário sejam acionados, Windows pré-processa determinadas teclas por meio desses métodos (em ordem):

  1. ProcessCmdKey: intercepta teclas de comando, como atalhos de menu e aceleradores. Se este método retornar true, a tecla é consumida e nenhum evento é disparado.
  2. IsInputKey: determina se uma chave deve gerar um KeyDown evento ou ir para ProcessDialogKey.
  3. ProcessDialogKey: manipula as teclas de navegação (teclas Escape, Tab, Return e seta). Se processada, nenhum evento é disparado.

Se um controle com foco consumir uma tecla durante o pré-processamento, o formulário nunca a receberá, independentemente de KeyPreview.

Casos especiais que ignoram os manipuladores de nível de formulário

  • Enter e Escape: essas chaves podem ser manipuladas por AcceptButton e CancelButton antes de atingir eventos de formulário.
  • Tab: frequentemente consumida pelo gerenciamento de foco do controle e não chegará aos manipuladores de formulário.
  • Atalhos de menu: as combinações de teclas Alt são manipuladas pelo pré-processamento de menu.

Interceptar teclas de comando no nível do formulário

Para manipular chaves de comando (incluindo atalhos de menu e teclas de diálogo) no nível do formulário, substitua ProcessCmdKey em seu formulário. Isso é executado durante o pré-processamento, antes dos eventos de formulário padrão.

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // Intercept Ctrl+A for custom handling
    if (keyData == (Keys.Control | Keys.A))
    {
        MessageBox.Show("Ctrl+A intercepted at form level");
        return true; // Mark as handled
    }

    // Pass other keys to the base handler
    return base.ProcessCmdKey(ref msg, keyData);
}
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
    ' Intercept Ctrl+A for custom handling
    If keyData = (Keys.Control Or Keys.A) Then
        MessageBox.Show("Ctrl+A intercepted at form level")
        Return True ' Mark as handled
    End If

    ' Pass other keys to the base handler
    Return MyBase.ProcessCmdKey(msg, keyData)
End Function

Para teclas que devem disparar eventos padrão em um controle específico, use PreviewKeyDown com IsInputKey definido como true nesse controle.

Consulte também