Next Previous Contents

## 9. Keyboard-internal scancodes

## 9.1 Three scancode sets

The usual PC keyboards are capable of producing three sets of scancodes. Writing 0xf0 followed by 1, 2 or 3 to port 0x60 will put the keyboard in scancode mode 1, 2 or 3. Writing 0xf0 followed by 0 queries the mode, resulting in a scancode byte 43, 41 or 3f from the keyboard.

Set 1 contains the values that the XT keyboard (with only one set of scancodes) produced, with extensions for new keys. Someone decided that another numbering was more logical and invented scancode Set 2. However, it was realized that new scancodes would break old programs, so the keyboard output was fed to a 8042 microprocessor on the motherboard that could translate Set 2 back into Set 1. Indeed a smart construction. This is the default today. Finally there is the PS/2 version, Set 3, more regular, but used by almost nobody.

(I wrote this long ago. Nowadays Linux 2.5 may try to use Set 3. Also certain HP machines, like the PS/2 version of the HP9000 workstation, have used Set 3.)

Sets 2 and 3 are designed to be translated by the 8042. Set 1 should not be translated.

Not all keyboards support all scancode sets. For example, my MyCom laptop only supports scancode Set 2, and its keyboard does not react at all when in mode 1 or 3.

## 9.2 Make and Break codes

The key press / key release is coded as follows:

For Set 1, if the make code of a key is c, the break code will be c+0x80. If the make code is e0 c, the break code will be e0 c+0x80. The Pause key has make code e1 1d 45 e1 9d c5 and does not generate a break code.

For Set 2, if the make code of a key is c, the break code will be f0 c. If the make code is e0 c, the break code will be e0 f0 c. The Pause key has the 8-byte make code e1 14 77 e1 f0 14 f0 77.

For Set 3, by default most keys do not generate a break code - only CapsLock, LShift, RShift, LCtrl and LAlt do. However, by default all non-traditional keys do generate a break code - thus, LWin, RWin, Menu do, and for example on the Microsoft Internet keyboard, so do Back, Forward, Stop, Mail, Search, Favorites, Web/Home, MyComputer, Calculator, Sleep. On my BTC keyboard, also the Macro key does.

In Scancode Mode 3 it is possible to enable or disable key repeat and the production of break codes either on a key-by-key basis or for all keys at once. And just like for Set 2, key release is indicated by a f0 prefix in those cases where it is indicated. There is nothing special with the Pause key in scancode mode 3.

## 9.3 Translation

The 8042 microprocessor translates the incoming byte stream produced by the keyboard, and turns an f0 prefix into an OR with 80 for the next byte. (Some implementations do this for the next byte that does not have this bit set already. A consequence is that in Set 3 the keys with Set-3 value 0x80 or more are broken in a peculiar way: hitting such a key and then some other key turns the make code for this last key into a break code. For example the Sleep key on a Microsoft Internet keyboard generates 54 / d4 for press/release. But pressing and releasing first Menu and then Sleep produces 8d 8d d4 d4 as translation of 8d f0 8d 54 f0 54. Other implementations are OK.)

Unless told not to translate, the keyboard controller translates keyboard scancodes into the scancodes it returns to the CPU using the following table (in hex):

| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 0a | 0b | 0c | 0d | 0e | 0f
00 | ff | 43 | 41 | 3f | 3d | 3b | 3c | 58 | 64 | 44 | 42 | 40 | 3e | 0f | 29 | 59
10 | 65 | 38 | 2a | 70 | 1d | 10 | 02 | 5a | 66 | 71 | 2c | 1f | 1e | 11 | 03 | 5b
20 | 67 | 2e | 2d | 20 | 12 | 05 | 04 | 5c | 68 | 39 | 2f | 21 | 14 | 13 | 06 | 5d
30 | 69 | 31 | 30 | 23 | 22 | 15 | 07 | 5e | 6a | 72 | 32 | 24 | 16 | 08 | 09 | 5f
40 | 6b | 33 | 25 | 17 | 18 | 0b | 0a | 60 | 6c | 34 | 35 | 26 | 27 | 19 | 0c | 61
50 | 6d | 73 | 28 | 74 | 1a | 0d | 62 | 6e | 3a | 36 | 1c | 1b | 75 | 2b | 63 | 76
60 | 55 | 56 | 77 | 78 | 79 | 7a | 0e | 7b | 7c | 4f | 7d | 4b | 47 | 7e | 7f | 6f
70 | 52 | 53 | 50 | 4c | 4d | 48 | 01 | 45 | 57 | 4e | 51 | 4a | 37 | 49 | 46 | 54
80 | 80? | 81 | 82 | 41 | 54 | 85 | 86 | 87 | 88 | 89 | 8a | 8b | 8c | 8d | 8e | 8f
90 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 9a | 9b | 9c | 9d | 9e | 9f
a0 | a0 | a1 | a2 | a3 | a4 | a5 | a6 | a7 | a8 | a9 | aa | ab | ac | ad | ae | af
b0 | b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | ba | bb | bc | bd | be | bf
c0 | c0 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | ca | cb | cc | cd | ce | cf
d0 | d0 | d1 | d2 | d3 | d4 | d5? | d6 | d7 | d8 | d9? | da? | db | dc | dd | de | df
e0 | e0 | e1 | e2 | e3 | e4 | e5 | e6 | e7 | e8 | e9 | ea | eb | ec | ed | ee | ef?
f0 | - | f1? | f2? | f3? | f4? | f5? | f6? | f7? | f8? | f9? | fa? | fb? | fc? | fd? | fe? | ff

A reference for the first half of this table is the book by Gary J Konzak PC 8042 Controller, ISBN 0-929392-21-3. (Report by `vojtech@suse.cz`.)

A way to check this table is: (i) put the keyboard in untranslated modes 1, 2, 3 and look at the resulting values, and (ii) put the keyboard in translated scancode modes 1, 2, 3. Now compare the values. The entries with question marks were not checked in this way.

Note that the range 01-7f of this table is 1-1. In the second half of the table, translated and untranslated values are equal in all known cases, with the two exceptions 83 and 84.

One asks the controller to transmit untranslated scancodes by writing a keyboard controller command with bit 5 set and bit 6 cleared. E.g., use the command byte 45 to get translated codes, and 24 to get untranslated codes that do not cause interrupts.

### Effects of translation

### Origin of strange scan code set values

The keyboard command f0 with argument 1, 2 or 3 sets the current scancode set, and this same command with argument 0 asks for the current scancode set. The reply is 43, 41 or 3f for sets 1, 2, 3. Why? Because in reality the reply is 1, 2 or 3, and that is what one sees when translation is off. But translation turns these into 43, 41, 3f.

### Keyboard IDs

Keyboards do report an ID as a reply to the command f2. (An XT keyboard does not reply, an AT keyboard only replies with an ACK.) An MF2 AT keyboard reports ID ab 83. Translation turns this into ab 41.

Many short keyboards, like IBM ThinkPads, and Spacesaver keyboards, send ab 84 untranslated, which becomes ab 54 translated. (The netbsd source has a misunderstanding here, and seems to associate the 54 and 84 to the ThinkPad model - cf. the defines KEYB_R_MF2ID2TP75X, KEYB_R_MF2ID2TP76X.)

Several 122-key keyboards are reported to send ab 86. Here translated and untranslated values coincide. (Reports mention "122-Key Enhanced Keyboard", "standard 122-key keyboard", "122 Key Mainframe Interactive (MFI) Keyboard".)

David Monro reports ab 85 for a NCD N-97 keyboard. Tim Clarke reports ab 85 for the "122-Key Host Connect(ed) Keyboard".

He also reports Also, when playing with my KVM problems Belkin gave me a 105-key Windows keyboard which Id.s itself as 18ABh.

Linux 2.5.25 kernel source has 0xaca1 for a "NCD Sun layout keyboard". It also mentions 0xab02 and 0xab7f, but these arise as (mistaken) back translations from ab 41 and ab 54.

Ralph Brown's Interrupt list mentions "old Japanese 'G', 'P', 'A' keyboards", with keyboard IDs ab 90, ab 91, ab 92. Here translated and untranslated versions coincide. ID ab 90 was also mentioned above.

## 9.4 Correspondence

For the traditional keys the correspondence is fairly clear: above we saw the translation table, and Set 1 equals translated Set 2, and Set 3 equals Set 2 in most cases where Set 2 has a single (non-escaped) scancode, and in any case the correspondence is constant (and given below).

On the other hand, modern keyboards have all kinds of multimedia and other additional keys, and what happens for them is completely random, and varies from keyboard to keyboard.

Let us look at an example.

The Microsoft Internet keyboard has keys Search, Favorites, Stop, Forward, Back, My Computer, Mail, Web / Home, Calculator with translated Set 3 scancodes 65, 66, 68, 69, 6a, 6b, 6c, 97, 99, respectively, and translated Set 2 scancodes e0 xx, with xx = 65, 66, 68, 69, 6a, 6b, 6c, 32, 21.

On the other hand, the IBM Rapid Access II keyboard has keys CD stop, CD play, Volume D, Volume U, CD back, CD fwd with translated Set 3 scancodes 69, 6a, 6b, 6c, 6d, 44, and translated Set 2 scancodes e0 xx, with xx = 20, 22, 21, 23, 24, 12.

Thus, different keyboards have different mappings between Set 2 and Set 3 codes.

## 9.5 Use

Can these other scancode sets be used? Probably not.

() Translated scancode Set 1 has weird codes that nobody wants to use.

(i) My MyCom laptop does not support scancode sets 1 and 3 at all.

(ii) Some laptops have special key combinations that bring one into a setup or configuration utility. It is impossible to do anything useful, or to get out of it again, when the scancode mode is not translated Set 2.

(iii) Many keyboards have bugs in scancode sets 1 and/or 3 but are fine in scancode Set 2. Vojtech Pavlik reports that his BTC keyboard has the same codes for the '1' and '2' keys in Set3, both having the code for '1'). On my BTC keyboard the key up value for Esc and 1 are both ff in scancode Set 1. My Safeway keyboard has untranslated Set 1 equal to translated Set 2, except for the multimedia keys, where untranslated Set 1 equals untranslated Set 2.

(iv) A big advantage of Set 3 is that each key generates a unique code so that one does not need to parse sequences. However, the BTC keyboard mentioned above generates e0 6f for its Macro key also in scancode mode 3. The Safeway keyboard mentioned above does not generate any codes for its multimedia keys in scancode mode 3.

(v) Some keyboard controllers cannot handle Set 3 values that are larger than 0x7f, and give peculiar results for e.g. the Windows keys in translated scancode mode 3. The result is that the following key is "eaten": the key down action turns into a key up.

(vi) The USB legacy support only supports translated Set 2.

(vii) The Microsoft Keyboard Scan Code Specification writes: In the very early days of Windows NT, an attempt was made to use the much more orthogonal Scan Code Set 3, but due to bugs in the implementation of this Scan Code Set on numerous OEM keyboards, the idea was abandoned. And also: Scan Code Set 3 is not used or required for operation of Microsoft operating systems.

(viii) Others also tried Set 3. The PS/2 version of the HP9000 workstation uses it. This is fine with HP's keyboards but causes some problems with foreign keyboards.

(ix) It is said that Hal Snyder of Mark Williams, Co remarked: "We find that about 10% of cheap no-name keyboards do not work in scan code set 3".

(x) These days Linux probes the keyboard, and may try to enable Set 3. This is good for learning a lot about strange keyboards. It is bad for having a stable system that just works.

## 9.6 A table

(USB codes in decimal, scancodes in hex.)

# | USB | Set 1 | X(Set 1) | Set 2 | X(Set 2) | Set 3 | X(Set 3) | keycap
1 | 53 | 29 | 39 | 0e | 29 | 0e | 29 | ` ~
2 | 30 | 02 | 41 | 16 | 02 | 16 | 02 | 1 !
3 | 31 | 03 | 3f | 1e | 03 | 1e | 03 | 2 @
4 | 32 | 04 | 3d | 26 | 04 | 26 | 04 | 3 #
5 | 33 | 05 | 3b | 25 | 05 | 25 | 05 | 4 $
6 | 34 | 06 | 3c | 2e | 06 | 2e | 06 | 5 % E
7 | 35 | 07 | 58 | 36 | 07 | 36 | 07 | 6 ^
8 | 36 | 08 | 64 | 3d | 08 | 3d | 08 | 7 &
9 | 37 | 09 | 44 | 3e | 09 | 3e | 09 | 8 *
10 | 38 | 0a | 42 | 46 | 0a | 46 | 0a | 9 (
11 | 39 | 0b | 40 | 45 | 0b | 45 | 0b | 0 )
12 | 45 | 0c | 3e | 4e | 0c | 4e | 0c | - _
13 | 46 | 0d | 0f | 55 | 0d | 55 | 0d | = +
15 | 42 | 0e | 29 | 66 | 0e | 66 | 0e | Backspace
16 | 43 | 0f | 59 | 0d | 0f | 0d | 0f | Tab
17 | 20 | 10 | 65 | 15 | 10 | 15 | 10 | Q
18 | 26 | 11 | 38 | 1d | 11 | 1d | 11 | W
19 | 8 | 12 | 2a | 24 | 12 | 24 | 12 | E
20 | 21 | 13 | 70 | 2d | 13 | 2d | 13 | R
21 | 23 | 14 | 1d | 2c | 14 | 2c | 14 | T
22 | 28 | 15 | 10 | 35 | 15 | 35 | 15 | Y
23 | 24 | 16 | 02 | 3c | 16 | 3c | 16 | U
24 | 12 | 17 | 5a | 43 | 17 | 43 | 17 | I
25 | 18 | 18 | 66 | 44 | 18 | 44 | 18 | O
26 | 19 | 19 | 71 | 4d | 19 | 4d | 19 | P
27 | 47 | 1a | 2c | 54 | 1a | 54 | 1a | [ {
28 | 48 | 1b | 1f | 5b | 1b | 5b | 1b | ] }
29 | 49 | 2b | 21 | 5d | 2b | 5c | 75 | \ |
30 | 57 | 3a | 32 | 58 | 3a | 14 | 1d | CapsLock
31 | 4 | 1e | 03 | 1c | 1e | 1c | 1e | A
32 | 22 | 1f | 5b | 1b | 1f | 1b | 1f | S
33 | 7 | 20 | 67 | 23 | 20 | 23 | 20 | D
34 | 9 | 21 | 2e | 2b | 21 | 2b | 21 | F
35 | 10 | 22 | 2d | 34 | 22 | 34 | 22 | G
36 | 11 | 23 | 20 | 33 | 23 | 33 | 23 | H
37 | 13 | 24 | 12 | 3b | 24 | 3b | 24 | J
38 | 14 | 25 | 05 | 42 | 25 | 42 | 25 | K
39 | 15 | 26 | 04 | 4b | 26 | 4b | 26 | L
40 | 51 | 27 | 5c | 4c | 27 | 4c | 27 | ; :
41 | 52 | 28 | 68 | 52 | 28 | 52 | 28 | ' "
42 | 50 | 00 | ff | 00 | ff | 00 | ff | non-US-1
43 | 40 | 1c | 1e | 5a | 1c | 5a | 1c | Enter
44 | 225 | 2a | 2f | 12 | 2a | 12 | 2a | LShift
46 | 29 | 2c | 14 | 1a | 2c | 1a | 2c | Z
47 | 27 | 2d | 13 | 22 | 2d | 22 | 2d | X
48 | 6 | 2e | 06 | 21 | 2e | 21 | 2e | C
49 | 25 | 2f | 5d | 2a | 2f | 2a | 2f | V
50 | 5 | 30 | 69 | 32 | 30 | 32 | 30 | B
51 | 17 | 31 | 31 | 31 | 31 | 31 | 31 | N
52 | 16 | 32 | 30 | 3a | 32 | 3a | 32 | M
53 | 54 | 33 | 23 | 41 | 33 | 41 | 33 | , <
54 | 55 | 34 | 22 | 49 | 34 | 49 | 34 | . >
55 | 56 | 35 | 15 | 4a | 35 | 4a | 35 | / ?
57 | 229 | 36 | 07 | 59 | 36 | 59 | 36 | RShift
58 | 224 | 1d | 11 | 14 | 1d | 11 | 38 | LCtrl
60 | 226 | 38 | 6a | 11 | 38 | 19 | 71 | LAlt
61 | 44 | 39 | 72 | 29 | 39 | 29 | 39 | space
62 | 230 | e0-38 | e0-6a | e0-11 | e0-38 | 39 | 72 | RAlt
64 | 228 | e0-1d | e0-11 | e0-14 | e0-1d | 58 | 3a | RCtrl
75 | 73 | e0-52 | e0-28 | e0-70 | e0-52 | 67 | 7b | Insert
76 | 76 | e0-53 | e0-74 | e0-71 | e0-53 | 64 | 79 | Delete
80 | 74 | e0-47 | e0-60 | e0-6c | e0-47 | 6e | 7f | Home
81 | 77 | e0-4f | e0-61 | e0-69 | e0-4f | 65 | 7a | End
85 | 75 | e0-49 | e0-34 | e0-7d | e0-49 | 6f | 6f | PgUp
86 | 78 | e0-51 | e0-73 | e0-7a | e0-51 | 6d | 7e | PgDn
79 | 80 | e0-4b | e0-26 | e0-6b | e0-4b | 61 | 56 | Left
83 | 82 | e0-48 | e0-6c | e0-75 | e0-48 | 63 | 78 | Up
84 | 81 | e0-50 | e0-6d | e0-72 | e0-50 | 60 | 55 | Down
89 | 79 | e0-4d | e0-19 | e0-74 | e0-4d | 6a | 7d | Right
90 | 83 | 45 | 0b | 77 | 45 | 76 | 01 | NumLock
91 | 95 | 47 | 60 | 6c | 47 | 6c | 47 | KP-7 / Home
92 | 92 | 4b | 26 | 6b | 4b | 6b | 4b | KP-4 / Left
93 | 89 | 4f | 61 | 69 | 4f | 69 | 4f | KP-1 / End
95 | 84 | e0-35 | e0-15 | e0-4a | e0-35 | 77 | 45 | KP-/
96 | 96 | 48 | 6c | 75 | 48 | 75 | 48 | KP-8 / Up
97 | 93 | 4c | 27 | 73 | 4c | 73 | 4c | KP-5
98 | 90 | 50 | 6d | 72 | 50 | 72 | 50 | KP-2 / Down
99 | 98 | 52 | 28 | 70 | 52 | 70 | 52 | KP-0 / Ins
100 | 85 | 37 | 5e | 7c | 37 | 7e | 46 | KP-*
101 | 97 | 49 | 34 | 7d | 49 | 7d | 49 | KP-9 / PgUp
102 | 94 | 4d | 19 | 74 | 4d | 74 | 4d | KP-6 / Right
103 | 91 | 51 | 73 | 7a | 51 | 7a | 51 | KP-3 / PgDn
104 | 99 | 53 | 74 | 71 | 53 | 71 | 53 | KP-. / Del
105 | 86 | 4a | 35 | 7b | 4a | 84 | 54 | KP--
106 | 87 | 4e | 0c | 79 | 4e | 7c | 37 | KP-+
108 | 88 | e0-1c | e0-1e | e0-5a | e0-1c | 79 | 4e | KP-Enter
110 | 41 | 01 | 43 | 76 | 01 | 08 | 64 | Esc
112 | 58 | 3b | 24 | 05 | 3b | 07 | 58 | F1
113 | 59 | 3c | 16 | 06 | 3c | 0f | 59 | F2
114 | 60 | 3d | 08 | 04 | 3d | 17 | 5a | F3
115 | 61 | 3e | 09 | 0c | 3e | 1f | 5b | F4
116 | 62 | 3f | 5f | 03 | 3f | 27 | 5c | F5
117 | 63 | 40 | 6b | 0b | 40 | 2f | 5d | F6
118 | 64 | 41 | 33 | 83 | 41 | 37 | 5e | F7
119 | 65 | 42 | 25 | 0a | 42 | 3f | 5f | F8
120 | 66 | 43 | 17 | 01 | 43 | 47 | 60 | F9
121 | 67 | 44 | 18 | 09 | 44 | 4f | 61 | F10
122 | 68 | 57 | 6e | 78 | 57 | 56 | 62 | F11
123 | 69 | 58 | 3a | 07 | 58 | 5e | 63 | F12
124 | 70 | e0-37 | e0-5e | e0-7c | e0-37 | 57 | 6e | PrtScr
0 | 154 | 54 | 1a | 84 | 54 | 57 | 6e | Alt+SysRq
125 | 71 | 46 | 0a | 7e | 46 | 5f | 76 | ScrollLock
126 | 72 | e1-1d-45 | e1-11-0b | e1-14-77 | e1-1d-45 | 62 | 77 | Pause
0 | 0 | e0-46 | e0-0a | e0-7e | e0-46 | 62 | 77 | Ctrl+Break
0 | 227 | e0-5b | e0-1b | e0-1f | e0-5b | 8b | 8b | LWin (USB: LGUI)
0 | 231 | e0-5c | e0-75 | e0-27 | e0-5c | 8c | 8c | RWin (USB: RGUI)
0 | 0 | e0-5d | e0-2b | e0-2f | e0-5d | 8d | 8d | Menu
0 | 0 | e0-5f | e0-76 | e0-3f | e0-5f | 7f | 54 | Sleep
0 | 0 | e0-5e | e0-63 | e0-37 | e0-5e | 00 | ff | Power
0 | 0 | e0-63 | e0-78 | e0-5e | e0-63 | 00 | ff | Wake

## 9.7 Vendor extensions

Logitech uses an e2 prefix for the codes sent by a pointing device integrated on the keyboard.

Next Previous Contents