Entrada do teclado (Introdução a Win32 e C++)
O teclado é usado para vários tipos distintos de entrada, incluindo:
- Entrada de caractere. Texto que o usuário digita em um documento ou caixa de edição.
- Atalhos de teclado. Traços de chave que invocam funções de aplicativo; por exemplo, CTRL + O para abrir um arquivo.
- Comandos do sistema. Traços de chave que invocam funções do sistema; por exemplo, ALT + TAB para alternar janelas.
Ao pensar na entrada do teclado, é importante lembrar que um traço de tecla não é o mesmo que um caractere. Por exemplo, pressionar a tecla A pode resultar em qualquer um dos caracteres a seguir.
- um
- Um
- á (se o teclado der suporte à combinação de diacríticos)
Além disso, se a tecla ALT for mantida pressionada, pressionar a tecla A produzirá ALT+A, que o sistema não tratará como um caractere, mas sim como um comando do sistema.
Códigos de chave
Quando você pressiona uma tecla, o hardware gera um código de verificação. Os códigos de verificação variam de um teclado para o outro e há códigos de verificação separados para eventos de tecla para cima e para baixo. Você quase nunca se importará com códigos de verificação. O driver de teclado converte códigos de verificação em códigos de tecla virtual. Os códigos de chave virtual são independentes do dispositivo. Pressionar a tecla A em qualquer teclado gera o mesmo código de tecla virtual.
Em geral, os códigos de chave virtual não correspondem aos códigos ASCII ou a qualquer outro padrão de codificação de caracteres. Isso é óbvio se você pensar sobre isso, porque a mesma chave pode gerar caracteres diferentes (a, A, á) e algumas teclas, como teclas de função, não correspondem a nenhum caractere.
Dito isto, os seguintes códigos de chave virtual são mapeados para equivalentes ASCII:
- 0 a 9 chaves = ASCII '0' – '9' (0x30 – 0x39)
- Chaves A a Z = ASCII 'A' – 'Z' (0x41 – 0x5A)
Em alguns aspectos, esse mapeamento é lamentável, porque você nunca deve pensar em códigos de chave virtual como caracteres, pelos motivos discutidos.
O arquivo de cabeçalho WinUser.h define constantes para a maioria dos códigos de chave virtual. Por exemplo, o código de tecla virtual para a tecla SETA PARA A ESQUERDA é VK_LEFT (0x25). Para obter a lista completa de códigos de chave virtual, consulte Códigos de chave virtual. Nenhuma constante é definida para os códigos de chave virtual que correspondem aos valores ASCII. Por exemplo, o código de chave virtual para a chave A é 0x41, mas não há nenhuma constante chamada VK_A. Em vez disso, basta usar o valor numérico.
mensagens Key-Down e Key-Up
Quando você pressiona uma tecla, a janela que tem o foco do teclado recebe uma das mensagens a seguir.
A mensagem WM_SYSKEYDOWN indica uma chave do sistema, que é um traço de chave que invoca um comando do sistema. Há dois tipos de chave do sistema:
- ALT + qualquer tecla
- F10
A tecla F10 ativa a barra de menus de uma janela. Várias combinações de teclas ALT invocam comandos do sistema. Por exemplo, ALT + TAB alterna para uma nova janela. Além disso, se uma janela tiver um menu, a tecla ALT poderá ser usada para ativar itens de menu. Algumas combinações de teclas ALT não fazem nada.
Todos os outros traços de chave são considerados chaves não sistema e produzem a mensagem WM_KEYDOWN . Isso inclui as teclas de função diferentes de F10.
Quando você libera uma chave, o sistema envia uma mensagem de chave correspondente:
Se você segurar uma tecla por tempo suficiente para iniciar o recurso de repetição do teclado, o sistema enviará várias mensagens de tecla para baixo, seguidas por uma única mensagem de tecla.
Em todas as quatro mensagens de teclado discutidas até agora, o parâmetro wParam contém o código de tecla virtual da tecla. O parâmetro lParam contém algumas informações diversas empacotadas em 32 bits. Normalmente, você não precisa das informações no lParam. Um sinalizador que pode ser útil é o bit 30, o sinalizador "estado de chave anterior", que é definido como 1 para mensagens de tecla repetidas.
Como o nome indica, os traços de chave do sistema são destinados principalmente para uso pelo sistema operacional. Se você interceptar a mensagem WM_SYSKEYDOWN , chame DefWindowProc posteriormente. Caso contrário, você bloqueará o sistema operacional de manipular o comando.
Mensagens de caractere
Os traços principais são convertidos em caracteres pela função TranslateMessage , que vimos pela primeira vez no Módulo 1. Essa função examina mensagens de tecla para baixo e as converte em caracteres. Para cada caractere produzido, a função TranslateMessage coloca uma mensagem WM_CHAR ou WM_SYSCHAR na fila de mensagens da janela. O parâmetro wParam da mensagem contém o caractere UTF-16.
Como você pode imaginar, WM_CHAR mensagens são geradas a partir de mensagens WM_KEYDOWN , enquanto WM_SYSCHAR mensagens são geradas a partir de mensagens WM_SYSKEYDOWN . Por exemplo, suponha que o usuário pressione a tecla SHIFT seguida pela tecla A. Supondo um layout de teclado padrão, você obteria a seguinte sequência de mensagens:
WM_KEYDOWN: SHIFT
WM_KEYDOWN: A
WM_CHAR: 'A'
Por outro lado, a combinação ALT + P geraria:
WM_SYSKEYDOWN: VK_MENU
WM_SYSKEYDOWN: 0x50
WM_SYSCHAR: 'p'
WM_SYSKEYUP: 0x50
WM_KEYUP: VK_MENU
(O código de chave virtual para a chave ALT é nomeado VK_MENU por motivos históricos.)
A mensagem WM_SYSCHAR indica um caractere do sistema. Assim como acontece com WM_SYSKEYDOWN, você geralmente deve passar essa mensagem diretamente para DefWindowProc. Caso contrário, você poderá interferir nos comandos padrão do sistema. Em particular, não trate WM_SYSCHAR como texto que o usuário digitou.
A mensagem WM_CHAR é o que você normalmente considera como entrada de caractere. O tipo de dados para o caractere é wchar_t, representando um caractere Unicode UTF-16. A entrada de caracteres pode incluir caracteres fora do intervalo ASCII, especialmente com layouts de teclado que são comumente usados fora do Estados Unidos. Você pode experimentar layouts de teclado diferentes instalando um teclado regional e, em seguida, usando o recurso Teclado Virtual.
Os usuários também podem instalar um IME (Editor de Método de Entrada) para inserir scripts complexos, como caracteres japoneses, com um teclado padrão. Por exemplo, usando um IME japonês para inserir o caractere katakana カ (ka), você pode receber as seguintes mensagens:
WM_KEYDOWN: VK_PROCESSKEY (a chave PROCESS do IME)
WM_KEYUP: 0x4B
WM_KEYDOWN: VK_PROCESSKEY
WM_KEYUP: 0x41
WM_KEYDOWN: VK_PROCESSKEY
WM_CHAR: カ
WM_KEYUP: VK_RETURN
Algumas combinações de teclas CTRL são convertidas em caracteres de controle ASCII. Por exemplo, CTRL+A é convertido para o caractere ASCII ctrl-A (SOH) (valor ASCII 0x01). Para entrada de texto, você geralmente deve filtrar os caracteres de controle. Além disso, evite usar WM_CHAR para implementar atalhos de teclado. Em vez disso, use WM_KEYDOWN mensagens; ou melhor ainda, use uma tabela de aceleradores. Tabelas de acelerador são descritas no próximo tópico, Tabelas aceleradoras.
O código a seguir exibe as mensagens de teclado main no depurador. Tente reproduzir com diferentes combinações de pressionamento de tecla e veja quais mensagens são geradas.
Observação
Certifique-se de incluir wchar.h ou então swprintf_s será indefinido.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
wchar_t msg[32];
switch (uMsg)
{
case WM_SYSKEYDOWN:
swprintf_s(msg, L"WM_SYSKEYDOWN: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_SYSCHAR:
swprintf_s(msg, L"WM_SYSCHAR: %c\n", (wchar_t)wParam);
OutputDebugString(msg);
break;
case WM_SYSKEYUP:
swprintf_s(msg, L"WM_SYSKEYUP: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_KEYDOWN:
swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_KEYUP:
swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_CHAR:
swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
OutputDebugString(msg);
break;
/* Handle other messages (not shown) */
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
Mensagens de teclado diversas
Algumas outras mensagens de teclado podem ser ignoradas com segurança pela maioria dos aplicativos.
- A mensagem WM_DEADCHAR é enviada para uma chave de combinação, como um diacrítico. Por exemplo, em um teclado de idioma espanhol, digitar ênfase (') seguido por E produz o caractere é. O WM_DEADCHAR é enviado para o personagem de destaque.
- A mensagem WM_UNICHAR está obsoleta. Ele permite que programas ANSI recebam entrada de caractere Unicode.
- O caractere WM_IME_CHAR é enviado quando um IME converte uma sequência de pressionamento de teclas em caracteres. Ele é enviado além da mensagem de WM_CHAR usual.
Estado do teclado
As mensagens de teclado são controladas por eventos. Ou seja, você recebe uma mensagem quando algo interessante acontece, como uma tecla, e a mensagem informa o que acabou de acontecer. Mas você também pode testar o estado de uma chave a qualquer momento, chamando a função GetKeyState .
Por exemplo, considere como você detectaria a combinação de clique no mouse esquerdo + tecla ALT. Você pode acompanhar o estado da chave ALT escutando mensagens de traço de chave e armazenando um sinalizador, mas GetKeyState salva o problema. Ao receber a mensagem WM_LBUTTONDOWN , basta chamar GetKeyState da seguinte maneira:
if (GetKeyState(VK_MENU) & 0x8000)
{
// ALT key is down.
}
A mensagem GetKeyState usa um código de chave virtual como entrada e retorna um conjunto de sinalizadores de bits (na verdade, apenas dois sinalizadores). O valor 0x8000 contém o sinalizador de bit que testa se a tecla está pressionada no momento.
A maioria dos teclados tem duas teclas ALT, esquerda e direita. O exemplo anterior testa se um deles é pressionado. Você também pode usar GetKeyState para distinguir entre as instâncias esquerda e direita das teclas ALT, SHIFT ou CTRL. Por exemplo, o código a seguir testa se a tecla ALT correta é pressionada.
if (GetKeyState(VK_RMENU) & 0x8000)
{
// Right ALT key is down.
}
A função GetKeyState é interessante porque relata um estado de teclado virtual . Esse estado virtual é baseado no conteúdo da fila de mensagens e é atualizado à medida que você remove mensagens da fila. À medida que seu programa processa mensagens de janela, GetKeyState fornece uma instantâneo do teclado no momento em que cada mensagem foi enfileirada. Por exemplo, se a última mensagem na fila foi WM_LBUTTONDOWN, GetKeyState relata o estado do teclado no momento em que o usuário clicou no botão do mouse.
Como GetKeyState é baseado na fila de mensagens, ele também ignora a entrada de teclado que foi enviada para outro programa. Se o usuário alternar para outro programa, todas as teclas que forem enviadas para esse programa serão ignoradas por GetKeyState. Se você realmente quiser saber o estado físico imediato do teclado, há uma função para isso: GetAsyncKeyState. No entanto, para a maioria dos códigos de interface do usuário, a função correta é GetKeyState.
Avançar