Windows receives keyboard input in the form of messages. A physical keypress can generate both a keystroke message and a character. Keystrokes represent the physical keypress and characters represent the display symbol or glyphs generated as a result of the keypress. Not every keystroke will generate a character.
Each time a key is pressed a message is sent to the window with input focus. Input focus indicates the component of the graphical user interface which is selected to receive input. Since most applications will have more than one window, a particular window must have input focus in order to receive these messages. The window that has the keyboard focus receives all keyboard messages until the focus changes to a different window.
When a key is pressed, a WM_KEYDOWN or WM_SYSKEYDOWN message is placed in the message queue by Windows and when that key is released Windows places either a WM_KEYUP or WM_SYSKEYUP message in the message queue. These keystroke messages indicates the pressed key using a virtual key code. The virtual key code is a device-independent integer code that uniquely identifies a key on the keyboard. This virtual key code is stored in the wParam parameter of the message while the lParam contains other useful information about the keystroke including repeat count and key transition states ie if the key is being pressed or released.
The WM_SYSKEYDOWN and WM_SYSKEYUP message is generated when the user presses the F10 key (menu bar) or holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus with the message being sent to the active window.
The WM_SYSKEYDOWN and WM_SYSKEYUP messages are usually processed by Windows and not by Windows applications. Since the improper handling of system keystroke messages can result in all sorts of unpredictable behaviour the WM_KEYDOWN and WM_KEYUP are the mouse messages of most interest to the developer
Character messages are the result of translating keystroke messages into character codes. The most commonly used character message is WM_CHAR. When the WM_CHAR message is sent, the wparam contains the character code of the key pressed and the lparam parameter contains other information such as the repeat count, extended key flag, and transition state. To retrieve character codes, an application must include the TranslateMessage function in its thread message loop.
A dead key is a modifier key that does not generate a character on its own but modifies the character generated by the key pressed immediately after it. Dead keys are typically used to attach a specific diacritic to a base letter.
To process dead-key messages in an application will need to include an WM_DEADCHAR or WM_SYSDEADCHAR message map handler.
The GetKeyState() API function retrieves the status of a specified virtual key. The status specifies whether the key is up, down, or toggled. Since information about the current states of keys such as Shift and Ctrl keys is not included in keyboard messages, the GetKeyState API function allows the developer to determine these key states before deciding on a course of action. The syntax for this function is –
SHORT GetAsyncKeyState( int vKey);
vKey – Specifies one of 256 possible virtual-key codes.
If the function succeeds, the return value indicates whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down.
The following code segment demonstrates the WM_KEYDOWN AND WM_CHAR message by printing the virtual key code and the associated character to the screen. If there is no character associated with the keycode the 2nd line is left blank.
//record keyboard input
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("myWindowClass");
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("myWindowClass"),TEXT("Keyboard Input"), WS_VISIBLE | WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);//translate keyboard messages
DispatchMessage(&Msg);
}
return Msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
static TCHAR key[25];
static TCHAR chr[25];
static int chrlen;
static int keylen;
switch(msg)
{
case WM_PAINT:
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc,0,0,key,keylen);//displays keystroke value
TextOut(hdc,0,20,chr,chrlen);//displays character associated with keystroke
EndPaint(hwnd, &ps);
break;
case WM_KEYDOWN://responds to keydown message processing raw keyboard messages
keylen=wsprintf(key,TEXT("KEY is %i"), wParam);
break;
case WM_CHAR://responds to character translation after keypress
chrlen=wsprintf(chr,TEXT("Character is %c"), wParam);
InvalidateRect(hwnd,NULL,true);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}