Keyboard Information

Applications find out what the user is doing on the keyboard mainly through messages reporting key-down events. An application can usually determine what the user's intent was in pressing a key by looking at the character recorded in the message. But, as discussed under B_KEY_DOWN in the Message Protocols appendix, the message carries other keyboard information in addition to the character--the key the user pressed, the modifier states that were in effect at the time, and the current state of all keys on the keyboard.

Some of this information can be obtained in the absence of key-down messages through two global functions:

This section discusses in detail the kinds of information that you can get about the keyboard through interface messages and these functions.


Key Codes

To talk about the keys on the keyboard, it's necessary first to have a standard way of identifying them. For this purpose, each key is arbitrarily assigned a numerical code.

The illustrations on the next few pages show the key identifiers for typical keyboards. The codes for the main part of a standard 101-key keyboard are shown on page 4. Other keyboards differ primarily in having additional keys in the bottom row. These differences are illustrated on page 5. The codes for the numerical keypad and for the keys between it and the main keyboard are shown beginning on page 6.

Different keyboards locate keys in slightly different positions. The function keys may be to the left of the main keyboard, for example, rather than along the top. The backslash key (0x33) shows up in various places--sometimes above the Enter key, sometimes next to Shift, and sometimes in the top row (as shown here). No matter where these keys are located, they have the codes indicated in the illustration above.

Some keyboards have additional keys, mainly in the bottom row. The keys at the bottom of a Microsoft natural keyboard are coded as follows:

The keys on the bottom row of a 105-key extended keyboard for the Macintosh have the following codes:

The keys on the right of the keyboard are assigned the following codes:

Some of the keys on a Macintosh keyboard have different labels from those shown above, but they have the same key codes. The Macintosh also adds a Power key and an "=" key on the keypad, as shown below:

The "Euro" key on some European keyboards is coded 0x69.

The BMessage that reports a key-down event contains an entry named "key" for the code of the key that was pressed.


Kinds of Keys

Keys on the keyboard can be distinguished by the way they behave and by the kinds of information they provide. A principal distinction is between character keys and modifier keys:

If a key doesn't fall into one of these two categories, there's nothing for it to do; it has no role to play in the interface. For most keys, the categories are mutually exclusive. Modifier keys are typically not mapped to characters, and character keys don't set modifier states. However, the Scroll Lock key is an exception. It both sets a modifier state and generates a character.

Keys can be distinguished on two other grounds as well:

The system key map determines the role that each key plays--whether it's a character key or a modifier key, which modifier states it sets, which characters it produces, whether it's dead or not, how it combines with other keys, and so on. The map is shared by all applications.

Users can modify the key map with the Keymap utility. Applications can look at it by calling the get_key_map() global function. See that function in the Interface Kit chapter for details on the structure of the map. The discussion here assumes the default key map that comes with the computer.


Modifier Keys

The role of a modifier key is to set a temporary, modal state. There are eight modifier states--eight different kinds of modifier key--defined functionally. Three of them affect the character that's reported in a key-down event:

Two modifier keys permit users to give the application instructions from the keyboard:

Three modifiers toggle in and out of locked states:

There are two things to note about these eight modifier states. First, since applications can read the modifiers directly from the messages that report key-down events and obtain them at other times by calling the modifiers() and get_key_info() functions, they are free to interpret the modifier states in any way they desire. You're not tied to the narrow interpretation of, say, the Control key given above. Control, Option, and Shift, for example, often modify the meaning of a mouse event or are used to set other temporary modes of behavior.

Second, the set of modifier states listed above doesn't quite match the keys that are marked on a typical keyboard. A standard 101-key keyboard has left and right "Alt(ernate)" keys, but lacks those labeled "Command," "Option," or "Menu."

The key map must, therefore, bend the standard 101-key keyboard to the required modifier states. The default key map does this in three ways:

The illustration below shows the modifier keys on the main keyboard, with labels that match their functional roles. Users can, of course, remap these keys with the Keymap utility. Applications can remap them by calling set_modifier_key().

The extended Macintosh and Microsoft keyboards are mapped to closely match the key caps; all the modifier keys work as you'd expect:

Current modifier states are reported in a mask that can be tested against these constants:

B_SHIFT_KEY B_COMMAND_KEY B_CAPS_LOCK
B_CONTROL_KEY B_MENU_KEY B_NUM_LOCK
B_OPTION_KEY B_SCROLL_LOCK

The ..._KEY modifiers are set if the user is holding the key down. The ..._LOCK modifiers are set only if the lock is on--regardless of whether the key that sets the lock happens to be up or down at the time.

If it's important to know which physical key the user is holding down, the one on the right or the one on the left, the mask can be more specifically tested against these constants:

B_LEFT_SHIFT_KEY B_RIGHT_SHIFT_KEY
B_LEFT_CONTROL_KEY B_RIGHT_CONTROL_KEY
B_LEFT_OPTION_KEY B_RIGHT_OPTION_KEY
B_LEFT_COMMAND_KEY B_RIGHT_COMMAND_KEY

If no keyboard locks are on and the user isn't holding a modifier key down, the modifiers mask will be 0.

The modifiers mask is returned by the modifiers() function and, along with the state of all the keys, by get_key_info(). It's also included as a "modifiers" entry in every BMessage that reports a keyboard or mouse event.


Character Mapping

The key map records character values using the UTF-8 encoding of the Unicode Standard, making it possible to map keys to characters in any of the world's scripts. UTF-8 encodes 16-bit Unicode values in a variable number of bytes (from one to four).

A B_KEY_DOWN message holds the character mapped to the key the user pressed as an array of bytes named, simply, "byte". The array is passed as a string to KeyDown() along with a count of the number of bytes in the string:

virtual void KeyDown(const char *bytes, int32 numBytes)

See Character Encoding in the Interface Kit for a description of UTF-8 encoding and get_key_map() for an explanation of the key map.

Most keys are mapped to more than one character. The precise character that the key produces depends on which modifier keys are being held down and which lock states the keyboard is in at the time the key is pressed.

A few examples are given in the table below:

Key No modifiers Shift alone Option alone Shift & Option Control
0x15 4 $ ¢ 4
0x18 7 & § 7
0x26 B_TAB B_TAB B_TAB B_TAB B_TAB
0x2e i I B_TAB
0x40 g G © 0x07
0x51 n N ñ Ñ 0x0e
0x55 / ? ÷ ¿ /
0x64 B_INSERT 0 B_INSERT 0 B_INSERT

The mapping follows some fixed rules, including these:

The default key map also follows the conventional rules for Caps Lock and Control:


Character Constants

The Interface Kit defines constants for characters that aren't normally represented by a visible symbol. This includes the usual space and backspace characters, but most invisible characters are produced by the function keys and the navigation keys located between the main keyboard and the numeric keypad. The character values associated with these keys are more or less arbitrary, so you should always use the constant in your code rather than the actual character value. Many of these characters are also produced by alphabetic keys when a Control key is held down.

The table below lists character constants defined in the kit and the keys they're associated with.

Key label Key code Character reported
Backspace 0x1e B_BACKSPACE
Tab 0x26 B_TAB
Enter 0x47 B_ENTER
(space bar) 0x5e B_SPACE
Escape 0x01 B_ESCAPE
F1 - F12 0x02 through 0x0d B_FUNCTION_KEY
Print Screen 0x0e B_FUNCTION_KEY
Scroll Lock 0x0f B_FUNCTION_KEY
Pause 0x10 B_FUNCTION_KEY
System Request 0x7e 0xc8
Break 0x7f 0xca
Insert 0x1f B_INSERT
Home 0x20 B_HOME
Page Up 0x21 B_PAGE_UP
Delete 0x34 B_DELETE
End 0x35 B_END
Page Down 0x36 B_PAGE_DOWN
(up arrow) 0x57 B_UP_ARROW
(left arrow) 0x61 B_LEFT_ARROW
(down arrow) 0x62 B_DOWN_ARROW
(right arrow) 0x63 B_RIGHT_ARROW

Several keys are mapped to the B_FUNCTION_KEY character. An application can determine which function key was pressed to produce the character by testing the key code against these constants:

B_F1_KEY B_F6_KEY B_F11_KEY
B_F2_KEY B_F7_KEY B_F12_KEY
B_F3_KEY B_F8_KEY B_PRINT_KEY (the "Print Screen" key)
B_F4_KEY B_F9_KEY B_SCROLL_KEY (the "Scroll Lock" key)
B_F5_KEY B_F10_KEY B_PAUSE_KEY

Note that key 0x30 (P) is also mapped to B_FUNCTION_KEY when the Control key is held down.

Each of the character constants listed above is a one-byte value falling in the range of values where ASCII and Unicode overlap. For convenience, the Interface Kit also defines some constants for common characters that fall outside that range. These characters have multibyte representations in UTF-8, so the constant is defined as a character string. For example:

#define B_UTF8_OPEN_QUOTE "\xE2\x80\x9C"
#define B_UTF8_CLOSE_QUOTE "\xE2\x80\x9D"
#define B_UTF8_COPYRIGHT "\xC2\xA9"

See Character Constants in the Interface Kit for a full list of these constants.


Key States

You can look at the state of all the keys on the keyboard at a given moment in time. This information is captured and reported in two ways:

In both cases, the bitfield is an array of 16 bytes,

   uint8 states[16];

with one bit standing for each key on the keyboard. Bits are numbered from left to right, beginning with the first byte in the array, as illustrated below:

Bit numbers start with 0 and match key codes. For example, bit 0x3c corresponds to the A key, 0x3d to the S key, 0x3e to the D key, and so on. The first bit is 0x00, which doesn't correspond to any key. The first meaningful bit is 0x01, which corresponds to the Escape key.

When a key is down, the bit corresponding to its key code is set to 1. Otherwise, the bit is 0. However, for the three keys that toggle keyboard locks--Caps Lock (key 0x3b), Num Lock (key 0x22), and Scroll Lock (key 0x0f)--the bit is set to 1 if the lock is on and set to 0 if the lock is off, regardless of the state of the key itself.

To test the bitfield against a particular key,

For example:

   if ( states[keyCode>>3] & (1 << (7 - (keyCode%8))) )
       . . .

Here, on the left, the key code is divided by 8 to obtain an index into the states array. This selects the byte (the uint8) in the array that contains the bit for that key. On the right, the part of the key code that remains after dividing by 8 is used to calculate how far a bit needs to be shifted to the left so that it's in the same position as the bit corresponding to the key. This mask is compared to the states byte with the bitwise & operator.






The Be Book, in lovely HTML, for the BeOS Preview Release.

Copyright © 1997 Be, Inc. All rights reserved.

Be is a registered trademark; BeOS, BeBox, BeWare, GeekPort, the Be logo, and the BeOS logo are trademarks of Be, Inc.

Last modified June 28, 1997.