typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword;
Additionally, the type definition `number' is used generically to indicate a numeric value. The actual size of the `number' type may be one or two bytes depending upon how the data is stored in the key map. Although most key maps use byte-sized numeric values, word-sized values are also allowed.
Multi-byte values in a key mapping file are stored in big-endian byte order.
struct KeyMappingFile { char magic_number[4]; // `KYM1' DeviceMapping maps[...]; // Variable number of maps };
struct DeviceMapping { dword interface; // Interface type dword handler_id; // Interface subtype dword map_size; // Byte count of `map' (below) KeyMapping map; };
The value of `interface' represents a family of keyboard device types (such as Intel "PC, ADB, NeXT," Sun Type5, etc.), and is generally specified as one of the constant values "NX_EVS_DEVICE_INTERFACE_ADB, NX_EVS_DEVICE_INTERFACE_ACE," etc., which are are defined in IOHIDTypes.h on MacOS/X and Darwin, and in ev_types.h on MacOS/X Server, OpenStep, and NextStep.
The value of `handler_id' represents a specific keyboard layout within the much broader `interface' family. For instance, for a 101-key Intel PC keyboard (of type NX_EVS_DEVICE_INTERFACE_ACE ) the `handler_id' is '0', whereas for a 102-key keyboard it is `1'.
Together, `interface' and `handler_id' identify the exact keyboard hardware to which this mapping applies. Programs which display a visual representation of a keyboard layout, match `interface' and `handler_id' from the .keymapping file against the `interface' and `handler_id' values found in each .keyboard file.
struct KeyMapping { word number_size; // 0=1 byte, non-zero=2 bytes number num_modifier_groups; // Modifier groups ModifierGroup modifier_groups[...]; number num_scan_codes; // Scan groups ScanGroup scan_table[...]; number num_sequence_lists; // Sequence lists Sequence sequence_lists[...]; number num_special_keys; // Special keys SpecialKey special_key[...]; };
The `number_size' flag determines the size, in bytes, of all remaining numeric values (denoted by the type definition `number') within the key mapping. If its value is zero, then numbers are represented by a single byte. If it is non-zero, then numbers are represented by a word (two bytes).
enum Modifier { ALPHALOCK = 0, SHIFT, CONTROL, ALTERNATE, COMMAND, KEYPAD, HELP };
struct ModifierGroup { number modifier; // A Modifier constant number num_scan_codes; number scan_codes[...]; // Variable number of scan codes };
The scan_codes[] array contains a list of all scan codes which map to the specified modifier. The shift, command, and alternate modifiers are frequently mapped to two different scan codes, apiece, since these modifiers often appear on both the left and right sides of the keyboard.
enum ModifierMask { ALPHALOCK_MASK = 1 << 0, SHIFT_MASK = 1 << 1, CONTROL_MASK = 1 << 2, ALTERNATE_MASK = 1 << 3, CARRIAGE_RETURN_MASK = 1 << 4 }; #define NOT_BOUND 0xff
struct ScanGroup { number mask; Character characters[...]; };
For each scan code, `mask' defines which modifier combinations generate characters. If `mask' is NOT_BOUND (0xff) then then this scan code does not generate any characters ever, and its characters[] array is zero length. Otherwise, the characters[] array contains one Character record for each modifier combination.
The number of records in characters[] is determined by computing (1 << bits_set_in_mask). In other words, if mask is zero, then zero bits are set, so characters[] contains only one record. If `mask' is "(SHIFT_MASK | CONTROL_MASK)," then two bits are set, so characters[] contains four records.
The first record always represents the character which is generated by that key when no modifiers are active. The remaining records represent characters generated by the various modifier combinations. Using the example with the shift and control masks set, record two would represent the character with the shift modifier active; record three, the control modifier active; and record four, both the shift and control modifiers active.
As a special case, ALPHALOCK_MASK implies SHIFT_MASK, though only ALPHALOCK_MASK appears in `mask'. In this case the same character is generated for both the shift and alpha-lock modifiers, but only needs to appear once in the characters[] array.
CARRIAGE_RETURN_MASK does not actually refer to a modifier key. Instead, it is used to distinguish the scan code which is given the special pseudo-designation of carriage return key. Typically, this mask appears solo in a ScanGroup record and only the two Character records for control-M and control-C follow. This flag may be a throwback to an earlier time or may be specially interpreted by the low-level keyboard driver, but its purpose is otherwise enigmatic.
enum CharacterSet { ASCII = 0x00, SYMBOL = 0x01, ... FUNCTION_KEY = 0xfe, KEY_SEQUENCE = 0xff };
struct Character { number set; // CharacterSet of generated character number char_code; // Actual character generated };
enum FunctionKey { F1 = 0x20, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INSERT, DELETE, HOME, END, PAGE_UP, PAGE_DOWN, PRINT_SCREEN, SCROLL_LOCK, PAUSE, SYS_REQUEST, BREAK, RESET, STOP, MENU, USER, SYSTEM, PRINT, CLEAR_LINE, CLEAR_DISPLAY, INSERT_LINE, DELETE_LINE, INSERT_CHAR, DELETE_CHAR, PREV, NEXT, SELECT };
#define MODIFIER_KEY 0xff
struct Sequence { number num_chars; Character characters[...]; };
Each generated Character is represented as previously described, with the exception that MODIFIER_KEY may appear in place of KEY_SEQUENCE. When the value of Character::set is MODIFIER_KEY then Character::char_code represents a modifier key rather than an actual character. If the modifier represented by `char_code' is non-zero, then it indicates that the associated modifier key has been depressed. In this case, the value is one of the constants enumerated by Modifier ("SHIFT, CONTROL, ALTERNATE," etc.). If the value is zero then it means that the modifier keys have been released.
enum SpecialKeyType { VOLUME_UP = 0, VOLUME_DOWN, BRIGHTNESS_UP, BRIGHTNESS_DOWN, ALPHA_LOCK, HELP, POWER, SECONDARY_ARROW_UP, SECONDARY_ARROW_DOWN };
struct SpecialKey { number type; // A SpecialKeyType constant number scan_code; // Actual scan code };
For a more thorough discussion of any particular piece of information described here, refer to the detailed description of the internal layout of a key mapping provided by the Key Mapping Description section above.
For each raw mapping, the following information is emitted:
- The title `KEYMAP' along with the mapping's relative position in the .keymapping file.
- The `interface' identifier.
- The `handler_id' sub-identifier.
·- The size of the raw mapping resource counted in bytes.
The `interface' and `handler_id' values, taken together, define a specific keyboard device. A .keyboard file, which describes the visual layout of a keyboard, also contains `interface' and `handler_id' identifiers. The .keyboard file corresponding to a particular key mapping can be found by matching the `interface' and `handler_id' values from each resource.
MODIFIERS [4] alternate: 0x1d 0x60 control: 0x3a keypad: 0x52 0x53 ... 0x63 0x62 shift: 0x2a 0x36
CHARACTERS [9] scan 0x00: -AC-L "a" "A" "^A" "^A" ca c7 "^A" "^A" scan 0x07: -AC-L "x" "X" "^X" "^X" 01/b4 01/ce "^X" "^X" scan 0x0a: ---S- "<" ">" scan 0x13: -ACS- "2" "@" "^@" "^@" b2 b3 "^@" "^@" scan 0x24: R---- "^M" "^C" scan 0x3e: ----- [F4] scan 0x4a: ----- [page up] scan 0x60: ----- {seq#3} scan 0x68: not-bound
For each record, the hexadecimal value of the hardware scan code is printed, followed by a list of modifier flag combinations and the actual characters generated by this scan code with and without modifiers applied.
The modifier flags field is composed of a combination of single letter representations of the various modifier types. The letters stand for:
L - alpha-lock S - shift C - control A - alternate R - carriage-return
As a special case, the alpha-lock flag also implies the shift flag, so these two flags never appear together in the same record.
The combination of modifier flags determines the meaning and number of fields which follow. The first field after the modifier flags always represents the character that will be generated if no modifier keys are depressed. The remaining fields represent characters generated by the various modifier combinations. The order of the fields follows this general pattern:
- The character generated by this scan code when no modifiers are in effect is listed first.
- If the `L' or `S' flag is active, then the shifted character generated by this scan code is listed next.
- If the `C' flag is active, then the control-character generated by this scan code is listed next. Furthermore, if the `L' or `S' flag is also active, then the shifted control-character is listed after that.
- If the `A' flag is active, then the alternate-character generated by this scan code is listed next. Furthermore, if the `L' or `S' flag is active, then the shifted alternate-character is listed after that. If the `C' flag is also active, then the alternate-control-character is listed next. Finally, if the `C' and `L' or `C' and `S' flags are also active, then the shifted alternate-control-character is listed.
The `R' flag does not actually refer to a modifier key. Instead, it is used to distinguish the scan code which is given the special pseudo-designation of carriage return key. Typically, this mask appears solo and only the two fields for control-M and control-C follow. This flag may be a throwback to an earlier time or may be specially interpreted by the low-level keyboard driver, but its purpose is otherwise enigmatic.
Recalling the example from above, the following fields can be identified:
scan 0x00: -AC-L "a" "A" "^A" "^A" ca c7 "^A" "^A"
- Lower-case `a' is generated when no modifiers are active.
·- Upper-case `A' is generated when shift or alpha-lock are active.
- Control-A is generated when control is active.
- Control-A is generated when control and shift are active.
·- The character represented by the hexadecimal code 0xca is generated when alternate is active.
- The character represented by 0xc7 is generated when alternate and shift (or alpha-lock) are active.
- Control-A is generated when alternate and control are active.
- Control-A is generated when alternate, control and shift (or alpha-lock) are active.
The notation used to represent a particular generated character varies.
- Printable ASCII characters are quoted, as in "x" or "X".
- Control-characters are quoted and prefixed with `^', as in "^X".
·- Characters with values greater than 127 (0x7f) are displayed as hexadecimal values without the `0x' prefix.
- Characters in a non-ASCII character set (such as `Symbol') are displayed as two hexadecimal numbers separated by a slash, as in `01/4a'. The first number is the character set's identification code (such as `01' for the `Symbol' set), and the second number is the value of the generated character.
- Non-printing special function characters are displayed with the function's common name enclosed in brackets, as in `[page up]' or `[F4]'.
- If the binding represents a key sequence rather than a single character, then the sequence's identification number is enclosed in braces, as in `{seq#3}'.
Recalling a few examples from above, the following interpretations can be made:
scan 0x07: -AC-L "x" "X" "^X" "^X" 01/b4 01/ce "^X" "^X" scan 0x3e: ----- [F4] scan 0x4a: ----- [page up] scan 0x60: ----- {seq#3}
- "x" and "X" are printable ASCII characters.
·- "^X" is a control-character.
·- `01/b4' and `01/ce' represent the character codes 0xb4 and 0xce in the `Symbol' character set.
- Scan code 0x3e generates function-key `F4', and scan code 0x4a generates function-key `page up'.
- Scan code 0x60 is bound to key sequence #3.
Finally, if a scan code is not bound to any characters, then it is annotated with the label `not-bound', as with example scan code 0x68 from above.
Each mapping may contain zero or more key sequence records. The title `SEQUENCES' is printed along with the count of sequence records which follow. For example:
SEQUENCES [3] sequence 0: "f" "o" "o" sequence 1: {alternate} "b" "a" "r" {unmodify} sequence 2: [home] "b" "a" "z"
The notation used to represent the sequence of generated characters is identical to the notation already described in the Characters section above, with the exception that modifier actions may be interposed between generated characters. Such modifier actions are represented by the modifier's name enclosed in braces. The special name `{unmodify}' indicates the release of the modifier keys.
Thus, the sequences in the above example can be interpreted as follows:
- Sequence #0 generates `foo'.
·- Sequence #1 invokes the alternate modifier, generates `bar', and then releases alternate.
- Sequence #2 invokes the home key and then generates `baz'. In a text editor, this would probably result in `baz' being prepended to the line of text on which the cursor resides.
Each mapping may contain zero or more special-key records which associate hardware scan codes with such special purpose functions. The title `SPECIALS' is printed along with the count of records which follow. For each record, the special function's name is printed along with a list of scan codes, in hexadecimal format, which are bound to that function. For example:
SPECIALS [6] alpha-lock: 0x39 brightness-down: 0x79 brightness-up: 0x74 power: 0x7f sound-down: 0x77 sound-up: 0x73
/System/Library/Keyboards
/Network/Library/Keyboards
/Local/Library/Keyboards
/Library/Keyboards
Repositories for .keymapping and .keyboard files for MacOS/X, Darwin, and MacOS/X Server.
/NextLibrary/Keyboards
/LocalLibrary/Keyboards
Repositories for .keymapping and .keyboard files for OpenStep and NextStep.
The following diagnostic messages have significance only when trying to print .keymapping files mentioned on the command-line.
The following diagnostic messages have significance only when trying to print the currently active key mapping when no .keymapping files have been mentioned on the command-line.
The following diagnostic messages have significance only when using dumpkeymap on a non-Apple/NeXT platform.
The implementation of dumpkeymap is based upon information gathered on September 3, 1997 by Eric Sunshine <[email protected]> and Paul S. McCarthy <[email protected]> during an effort to reverse engineer the format of the NeXT .keymapping file.
Version 4 -- 1 December 2000