Handling Keyboard Messages
In that a keyboard generates messages each time a key is pressed or released, monitoring keyboard events is similar to tracking mouse activity. However, the keyboard is somewhat simpler in that a keyboard event can only occur within the active window. Also, there is no location to be discovered, just whether or not a keyboard event took place. And finally, there are over twice as many times as many mouse messages as there are keyboard messages.
Each key on a keyboard is assigned a unique value called a scan code, which is sent to Windows when a key is pressed and when it is released. The keyboard device driver interprets a scan code and translates it to a virtual-key code.
A list of virtual key codes can be found at MSDN, and includes such values as VK_F5, VK_LButton, VK_TAB, VK_1, VK_A, VK_B, and so on. The virtual key codes are easily recognizable as the commonly used names for the keys.
On each key press and release, a Windows message is sent out. The message includes the scan code, virtual-key code, and other information.
The active Window, or one of it's child windows, receives the keyboard message.
Getting Key Status Using API
Key states can be retrieved at any time using the Windows GetKeyState and GetAsyncKeyState API. These differ slightly as follows:
GetKeyState - determines status of a virtual key at the time the current message was generated. this is the API most used for user interface applications GetAsyncKeyState - retrieves current status of a virtual key
However, it is worth mentioning that all of the common controls provide their own messages on key events of interest to the control. Most often, the messages supplied by the common controls are all that a programmer needs to create an application.
But since common control messages do not cover all possible keyboard actions, the additional of use of Windows API often proves useful in many applications.
An inconvenience of the all-API approach is that the program must include code to repeatedly test for the mouse information, usually as part of a message loop or by using a timer to trigger periodic use of the code to get the mouse information.
It is generally more convenient to let the Windows operating system send a keyboard event message, which usually contains the needed information, to the application for a program response.
The rest of this tutorial focuses on using keyboard messages.
Activating a Window
The user can activate a top-level window by clicking it, selecting it using the ALT+TAB or ALT+ESC key combination, or selecting it from the Task List. Only one window at a time can be the active window in the system.
To help the user identify the active window, the system places it at the top of the Z order and highlights its title bar (if it has one) and border.
When a windows is activated, it is sent the WM_ACTIVATE message. Also, the window which had been the active window also received the WM_ACTIVATE message. The message contains the following information.
WM_ACTIVATE - sent to window activated and to window deactivated Lo(Word, wParam) = 0 if window is being deactivated Lo(Word, wParam) is nonzero if window is being activated
At any time, a programmer can use the GetActiveWindow API to retrieve the handle of the active window.
Or, the active window can be set programmatically using the SetActiveWindow API.
Once a window is activated, it also receives the keyboard focus.
Just as only one windows can be the active window in the system, only one window can have the keyboard focus. A parent window can be the active window and have keyboard focus. A child window cannot be the active window but can have keyboard focus.
Keyboard focus can shit from one window to another. Once a window gets keyboard focus, it receives all keyboard messages until the focus changes to a different window. When keyboard focus changes, the following message are sent:
WM_KILLFOCUS - received by window that has lost the focus WM_SETFOCUS - received by window that has gained the focus.
At any time, a programmer can use the GetFocus API to retrieve the handles of the window with keyboard focus.
Or, a windows can be given keyboard focus using the SetFocus API.
The SetFocus can also assigned NULL as the window to receive keyboard messages, in which can keystrokes are ignored.
System and NonSystem Keystrokes
System keystrokes are key combinations which involve use of the Alt key, such as interfacing with a window's menu or System menu, for activating a different window (Alt+ESC and Alt-TAB), or for detecting when no window has keyboard focus (such as when the active application is minimized). System keystrokes are primarily for use by Windows rather than by an application.
All other keystrokes are considered nonsystem keystrokes and are intended for use by applications.
Basic Keystroke Messages
When a key is pressed a WM_KeyDown message is generated. And when a key is released, a WM_KeyUp message is generated.
This pairing of keydown/keyup message is always observed, except in the case where a key is pressed long enough that messages are generated faster than an application can process them (such as when a key is held long enough to active the automatic repeat feature of a keyboard). In this case a WM_KeyDown message may include a repeat count value rather than fill the message queue with multiple, identical messages.
In addition to providing the handle of the window with keyboard focus, the wParam and lParam content of both the WM_KEYDOWN and WM_KEYUP messages is as follows:
wParam - virtual-key code (VK_B, VK_2, ...) lParam - scan code plus other information (see below)
The lParam values contains multiple values, and is discussed fully in the next paragraph.
WM_KeyUp/WM_KeyDown: lParam Content
The lParam argument of a WM_KeyUp and WM_KeyDown message contains 6 different values, spread over the 32 bits of the argument.
The following illustration shows the locations of these flags and values in the lParam parameter.
0-15 Repeat count 16-23 Scan code 24 1 if extended key, 0 if not 25-28 Reserved 29 Context code. 0 for WM_KEYDOWN message 30 Previous key state. 1 if down, 0 if up. 31 Transition state. 0 for WM_KEYDOWN message
The repeat count allows checking to determine whether a keystroke message represents more than one keystroke, such as when the automatic repeat feature is activated. Releasing a key cannot start the automatic repeat feature, so the repeat count for WM_KEYUP and WM_SYSKEYUP messages is always set to 1.
Scan codes are typically ignored by applications. Instead, virtual-key codes are used to interpret keystroke messages.
The extended-key flag indicates whether the keystroke message originated from one of the additional keys on the enhanced keyboard. The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. The extended-key flag is set if the key is an extended key.
The context code indicates whether the ALT key was down when the keystroke message was generated. The code is 1 if the ALT key was down and 0 if it was up.
The previous key-state flag indicates whether the key that generated the keystroke message was previously up or down. It is 1 if the key was previously down and 0 if the key was previously up. You can use this flag to identify keystroke messages generated by the keyboard's automatic repeat feature. This flag is set to 1 for WM_KEYDOWN and WM_SYSKEYDOWN keystroke messages generated by the automatic repeat feature. It is always set to 0 for WM_KEYUP and WM_SYSKEYUP messages.
The transition-state flag indicates whether pressing a key or releasing a key generated the keystroke message. This flag is always set to 0 for WM_KEYDOWN and WM_SYSKEYDOWN messages; it is always set to 1 for WM_KEYUP and WM_SYSKEYUP messages.
ASCII Character Messages
While the virtual-key codes are the preferred way to interpret key strokes. But in some cases a programmer may want to know the ASCII code of the key that was pressed or released. Windows provides the TranslateMessage function for this purpose. Passing a virtual-key message (WM_KeyUp, WM_KeyDown, WM_SysKeyUp, WM_SysKeyDown) through TranslateMessage will cause Windows to generate additional messages which contain character code information.
In particular, here are the virtual-key messages and the corresponding messages which will be generated following use of the TranslateMessage API.
WM_KeyUp --- WM_DeadChar WM_KeyDown --- WM_Char and WM_UniChar WM_SysKeyUp --- WM_SysDeadChar WM_SysKeyDown --- WM_SysChar
Only the WM_Char message is typically used by PowerBASIC programmer, and less often, the WM_UniChar message.
The wParam parameter of all character messages contains the character code of the character key that was pressed.
The contents of the lParam parameter of a character message are identical to the contents of the lParam parameter of the key-down message that was translated to produce the character message.
Keyboard Keys for Browsing and Other Functions
Windows provides support for keyboards with special keys, such as for browser functions, media functions, application launching, and power management.
The WM_APPCOMMAND message is provided when such keys are pressed. The wParam argument contains the handle to the window where the key was pressed. The lParam argument contains one of 50+ codes which identify the key that was pressed.
See the MSDN section on WM_APPCOMMAND for a complete listing of keys, and their codes, supported by this command.
See the MSDN section on WM_HOTKEY for additional information.
If you have any suggestions or corrections, please let me know.