Wout Mertens' Guide To Keyboard Programming v1.1 Complete

Download a ZIP of this document and it's accompanying source code.

    Table of Contents

    0	Legal Info
    0.1 Preface

    1	Overall Information
    1.1 Extended ASCII
    1.2 Special Functions

    2	DOS Interfacing
    2.1 Functions

    3	BIOS Interfacing
    3.1 Functions
    3.2 Keyboard Flags
    3.3 Keyboard Buffer

    4	Low-Level Interfacing
    4.1 Interfacing And Configuring
    4.2 Lay-Out
    4.3 Scancodes
    4.4 Int 9

    5	Tech Stuff

    A	Acknowledgments
    B	How To Contact Me
    C	The Answer To Life, The Universe And All The Rest
    D	History

    0. Legal Info

    This "Keyboard Guide" is (C) Copyright 1994 Wout Mertens.
    All rights reserved.


    This document and its accompanying	source code files are freeware,  not
    public domain.  They  may  be distributed  freely provided	that neither
    file is  modified, and  that they  are distributed	together along	with
    FILE_ID.DIZ in  their entirety,  including the  legal notice,  and that:
    If they are distributed by a third party vendor, no more than $5 U.S. is
    charged for the disk on which the archive, containing this document  and
    the accompanying  source code  files, is stored, except when distributed
    on CD-ROM.
    This legal information supersedes all previous notices.

    0.1. Preface

    I wrote this document because I needed info, and thought I could get it
    this way. Boy was I wrong! I ended up finding it all by myself. Anyway,
    I hope you can use it.  It is meant for people who know what interrupts
    are and that 0ah equals 10. Enjoy.

    Oh, almost forgot.	I didn't give this text any page formatting  (aside
    from spaces before and room after for ease of reading) because:

	- I read ALL my documents on-line
	- People have differing page sizes and then it would look like
	  shit for some people and too short for others.

    If you want to print this, well, go ahead and format it, BUT DON'T EVEN
    *THINK* OF SPREADING IT !!! (Except when you ask my permission)

    Everytime  you  see  something  like  d9h  or  65h,  it is a hexadecimal
    number. No trailing 0 was added for ease of typing.

    1. Overall Information

    On the IBM,  there are three  ways, all alike,  to access the  keyboard.
    Via the operating  system, via BIOS  or via low-level  access. Which way
    you use depends very much on  the application you are writing. Games  do
    not use DOS functions, for example. And a file-compressor is really  not
    interested wether  you are	actually pressing  'Y' or  not. Or how long.

    This is the way it works:

       Hardware  쳐컴컴컴컴컴컴 BIOS 컴컴컴컴컴컴컴컴   쳐컴 DOS 컴캑
			渼Keyboard Data쳐컴컴
       旼컴컴	 旼컴컴엿  旼컴컴컴커  旼컴컨컴컴컴컴   旼컴컴컴컴컴커
       쿸ey- 쳐爐큛nt 9쳅컴큝eyboard쳐컴퀯IOS keyboard쳐컴퀱OS keyboard
       쿫oard  읕컴컴   쿫uffer    쿯unctions       쿯unctions   
       읕컴컴 	   읕컴爐컴켸  읕컴컴켠컴컴컴   읕컴컴켠컴컴켸

			      Possible tap points

    The keyboard triggers  IRQ 1 (Interrupt  Request), also known  as int 9.
    Int 9 then translates the keyboard codes into ASCII, or when  necessary,
    extended ASCII, and places it into the keyboard buffer. Also, the  shift
    and lock states are saved in the BIOS Data Area (seg 40h). The  keyboard
    buffer is then  used by the  BIOS functions to  interface with programs.
    The DOS  functions use  the BIOS  keyboard functions  to interface	with
    programs as  well, but  on a  higher and  more protected  (Ctrl-Brk etc)

    1.1. Extended ASCII

    Extended ASCII is IBM's way  of letting non-ASCII keys be  recognized by
    programs. The BIOS will first send	0 and then the extended ASCII  code.

    Here is the table:
    튚ey Hex Dec튚ey	   Hex Dec튚ey	     Hex Dec튚ey      Hex Dec
    튔1   3B  59튥hift-F1   54	84튏trl-F1   5E   94튍lt-F1   68  104
    튔2   3C  60튥hift-F2   55	85튏trl-F2   5F   95튍lt-F2   69  105
    튔3   3D  61튥hift-F3   56	86튏trl-F3   60   96튍lt-F3   6A  106
    튔4   3E  62튥hift-F4   57	87튏trl-F4   61   97튍lt-F4   6B  107
    튔5   3F  63튥hift-F5   58	88튏trl-F5   62   98튍lt-F5   6C  108
    튔6   40  64튥hift-F6   59	89튏trl-F6   63   99튍lt-F6   6D  109
    튔7   41  65튥hift-F7   5A	90튏trl-F7   64  100튍lt-F7   6E  110
    튔8   42  66튥hift-F8   5B	91튏trl-F8   65  101튍lt-F8   6F  111
    튔9   43  67튥hift-F9   5C	92튏trl-F9   66  102튍lt-F9   70  112
    튔10  44  68튥hift-F10  5D	93튏trl-F10  67  103튍lt-F10  71  113
    튚ey   Hex Dec튚ey	 Hex  Dec튚ey	   Hex	Dec튚ey      Hex  Dec
    튍lt-A  1E	30튍lt-P  19   25튍lt-3     7A	122튲own      50   80
    튍lt-B  30	48튍lt-Q  10   16튍lt-4     7B	123튽eft      4B   75
    튍lt-C  2E	46튍lt-R  13   19튍lt-5     7C	124틆ight     4D   77
    튍lt-D  20	32튍lt-S  1F   31튍lt-6     7D	125틌p	      48   72
    튍lt-E  12	18튍lt-T  14   20튍lt-7     7E	126튓nd       4F   79
    튍lt-F  21	33튍lt-U  16   22튍lt-8     7F	127튗ome      47   71
    튍lt-G  22	34튍lt-V  2F   47튍lt-9     80	128튡gDn      51   81
    튍lt-H  23	35튍lt-W  11   17튍lt--     82	130튡gUp      49   73
    튍lt-I  17	23튍lt-X  2D   45튍lt-=     83	131		     
    튍lt-J  24	36튍lt-Y  15   21		   ^left     73  115
    튍lt-K  25	37튍lt-Z  2C   44튞UL	    03	  3^right    74  116
    튍lt-L  26	38		 튥hift-Tab 0F	 15^End      75  117
    튍lt-M  32	50튍lt-0  81  129튘ns	    52	 82^Home     77  119
    튍lt-N  31	49튍lt-1  78  120튒el	    53	 83^PgDn     76  118
    튍lt-O  18	24튍lt-2  79  121^PrtSc    72	114^PgUp     84  132
	    101-key Keyboard Extensions Supported by BIOS 
    튚ey      Hex  Dec튚ey	     Hex Dec튚ey	   Hex	Dec
    튔11       85  133튍lt-Bksp      0E   14튍lt - K /	    A4	164
    튔12       86  134튍lt-Enter     1C   28튍lt - K *	    37	 55
    튥hft-F11  87  135튍lt-Esc	     01    1튍lt - K -	    4A	 74
    튥hft-F12  88  136튍lt-Tab	     A5  165튍lt - K +	    4E	 78
    튏trl-F11  89  137튏trl-Tab      94  148튍lt - K Enter  A6	166
    튏trl-F12  8A  138 		    			   
    튍lt-F11   8B  139튍lt-up	     98  152튏trl- K /	    95	149
    튍lt-F12   8C  140튍lt-down      A0  160튏trl- K *	    96	150
    튍lt-[     1A   26튍lt-left      9B  155튏trl- K -	    8E	142
    튍lt-]     1B   27튍lt-right     9D  157튏trl- K +	    90	144
    튍lt-;     27   39 		    			   
    튍lt-'     28   40튍lt-Delete    A3  163튏trl- K Up [8] 8D	141
    튍lt-`     29   41튍lt-End	     9F  159튏trl- K Cn [5] 8F	143
    튍lt-\     2B   43튍lt-Home      97  151튏trl- K Dw [2] 91	145
    튍lt-,     33   51튍lt-Insert    A2  162튏trl- K Ins[0] 92	146
    튍lt-.     34   52튍lt-PageUp    99  153튏trl- K Del[.] 93	147
    튍lt-/     35   53튍lt-PageDown  A1  161			   
    K indicates a key on the numeric keypad (when not in NumLock mode)

    1.2. Special Functions

    There are a few functions and interrupts invoked by int 9:

    int 5   - Print Screen Handler

    int 15h
    fns 4fh - Check Scancode
	      (See int 9)

	85h - System Request
	      Normally IRET

    int 23h - Ctrl-Break handler

    Feel free to revector any of them.

    2. DOS Interfacing

    One of the ways to use the keyboard is to let DOS handle it.

	- The keyboard lay-out is unimportant
	- You can even do strings
	- The user doesn't actually have to type

	- You don't  know if you  are actually accessing  the keyboard (like
	  in "Really format drive C: ? Y/N" :-)
	- The functions are quite slow

    2.1. Functions

    DOS provides a set of 7 functions to handle the keyboard:

    01h Keyboard Input
    06h Console I/O
    07h No Echo Unfiltered Input
    08h No Echo Filtered Input
    0Ah Buffered Input
    0Bh Input Status
    0Ch Clear Keyboard Buffer & Input

    They all expect the keyboard to be	file handle 0. If you want to  let a
    program think  you are  typing something,  you can	replace this  handle
    with  a  file  containing  the  keystrokes	it  must  read. This is what
    happens when you  'pipe' something in  DOS. (Don't forget  to change the
    handle back to the old one!)

    This also means you can use:

    3Fh Read bytes from handle

    Fn 01h: Keyboard Input
    Expects: AH  01h

    Returns: AL  Character fetched from the Standard Input

    Description: Reads	(waits	for)  a  character from  the Standard  Input
		 Device.   Echoes  that  character  to	the  Standard Output
		 Device.  If Ctrl-Break is detected, INT 23h is executed.

    Notes:	 Extended ASCII keystrokes  (ie, F1-F12, PgUp,	cursor, etc)
		 will require two  calls to this  function.  The  first call
		 will  return  AL=0.   The  second  will  return AL with the
		 extended ASCII code.

    Fn 06h: Console I/O
    Expects: AH  06h
	     DL  0 to 0FEh  Character to send to the Standard Output
		 0FFh	    Request for input from the Standard Input

    Returns: ZF  Clear (NZ) if character is ready \ on input requests
	     AL  Character read, if ZF is clear   / (when DL=0FFh)

    Description: If DL	is 0FFh,  this performs  a "no	wait" console input,
		 returning  the  Zero  Flag  (ZF)  set	(ZR)  if there is no
		 character  ready.   If  a  character  is  ready, returns ZF
		 cleared (NZ) with the character that was read in AL.

		 If DL	is anything  but 0FFh,	DL is  sent to	the Standard

    Notes:	 Does not  check for  Ctrl-Break.   Call twice	for Extended

    Fn 07h: No Echo Unfiltered Console Input
    Expects: AH  07h

    Returns: AL  Character fetched from the Standard Input

    Description: Reads	(waits	for)  a  character  from  the Standard Input
		 Device, returning that character in AL.

		 Unfiltered: Does not detect Ctrl-Break, backspace, etc.

    Notes:	 Call twice for Extended ASCII character input.
		 Use Fn 0Bh to check status  (if you don't want to wait  for
		 a key).

    Fn 08h: No Echo Console Input
    Expects: AH  08h

    Returns: AL  Character fetched from the Standard Input

    Description: Reads	(waits	for)  a  character  from  the Standard Input
		 Device, returning that character in AL.

		 If Ctrl-Break is detected, INT 23h is executed.

    Notes:	 Call twice for Extended ASCII character input.

    Fn 0Ah: Buffered String Input
    Expects: AH  0Ah
	     DS:DX Address of an input buffer (see below)

    Returns:	 Buffer contains input terminated with CR (ASCII 13h)

    Description: On entry, the buffer at DS:DX must be set up as:
		 쿺ax ?  ?   ?   ?   ?   ?	 max is maximum acceptable
		 읕컴좔컴좔컴좔컴좔컴좔컴     input (range: 1 to 254)
		 On exit, the buffer is filled:
		 旼컴쩡컴쩡컴쩡컴쩡컴쩡컴쩡    len is actual length of
		 쿺ax쿹en T   E   X   T   0Dh	 input, less the termina-
		 읕컴좔컴좔컴좔컴좔컴좔컴     ting CR (eg, 4).

		 Characters are  read from  the Standard  Input up  to a  CR
		 (ASCII  13)  or  up  to  the  value  of max-1.  If max-1 is
		 reached, the console bell rings (beeps) for each  character
		 until Enter (CR) is read.

		 The second  byte of  the buffer  is filled  with the actual
		 length of the	input, less the  terminating CR.   The final
		 character in the buffer is always CR (which is not  counted
		 in the length byte).

		 The characters  in the  buffer (including  the len)  before
		 the call are used as a "template" and the DOS editing	keys
		 are in effect:  [Esc]	displays "\" and restarts the  edit,
		 [F3] displays	to the	end of	the template,  [F5] displays
		 "@"  and  stores  the	current  line  as the template, etc.
		 Most Extended ASCII keystrokes are ignored.

		 If  Ctrl-Break  is  detected,	INT  23h is executed and the
		 buffer is left unchanged.

    Fn 0Bh: Check Input Status
    Expects: AH  0Bh

    Returns: AL  0FFh if a character is available from the Standard Input
		 0    if no character is available

    Description: Checks the status of the Standard Input.

		 If Ctrl-Break is detected, INT 23h is executed.

    Notes:	 Use before Fns  01h, 07h and  08h to avoid  having DOS wait
		 for a key.

		 This  is  a  simple,  non-destructive	way  to  check	 for
		 Ctrl-Break  during  long  calculations  or other processing
		 that does not	normally look for  input.  It  lets the user
		 abort from such a sequence.

    Fn 0Ch: Clear & Input
    Expects: AH  0Ch
	     AL  DOS input function number (01h, 06h, 07h, 08h, or 0Ah)

    Returns: none

    Description: Clears the  Standard Input  type-ahead buffer	then invokes
		 the DOS input	function specified by  AL.  This  forces the
		 system to wait for a character to be typed.

		 These values are allowed for AL:
		    01h Keyboard Input
		    06h Console I/O
		    07h No Echo Unfiltered Input
		    08h No Echo Filtered Input
		    0Ah Buffered Input

    In addition to these functions, it	is also possible to read a  selected
    amount  of	characters  from  the  keyboard,  using  DOS's	File  Handle
    functions, as the Keyboard, aka Standard Input, has a pre-set handle  of

    Fn 3Fh: Read from keyboard via Handle
    Expects: AH  3Fh
	     BX  0000h - Handle for Standard Input (Keyboard)
	     DS:DX Address of buffer to receive data
	     CX  Number of bytes to read

    Returns: AX  Error code if CF is set to CY
	     AX  Number of bytes actually read

    Description: CX bytes of  data are read from  the keyboard. The data  is
		 placed into the caller's buffer pointed to by DS:DX.

    Notes:	 It  is  handy	to  use  this  function  for reading default
		 handles such as  the Standard I/O  handles, instead of  the
		 buffered input or character-by-character input functions.

		 When you read from a  device, AX returns the length  of the
		 line up to and including the termination CR (ASCII 13h).

    3. BIOS Interfacing

	- You get to know all the statusses and such
	- It's a tad bit faster than DOS
	- You can only read the keyboard
	- It's easier than the really hardcore low level, and the keys
	  are translated

	- It is still to slow for games or demos
	- You don't have bulk access, like strings

    The BIOS has 3 different ways of reading (parts of) the keyboard:
	- functions
	- keyboard flags
	- keyboard buffer

    This part describes all of them.

    3.1. Functions

    These functions can be accessed through int 16h.

    Fn 00h: Read (wait for) next keystroke
    Expects: AH  0

    Returns: AL  ASCII	character (if  AL=0, AH  is an Extended  ASCII	key-
	     AH  Scan Code or Extended ASCII keystroke

    Fn 01h: Check if a keystroke is ready (and preview it if so)
    Expects: AH  1

    Returns: ZF  ZR or 1 if no key is ready
	     ZF  NZ or 0 if a key is ready.
	     AX  is  set  as  for  Fn  00h  (but  the keystroke has not been
		 removed from the queue).

    Fn 02h: Read the shift-key status
    Expects: AH  2

    Returns: AL  shift key and 'lock' status as in 83-keyboard flags

    Description: Determine which shift keys are currently being pressed  and
		 whether the keyboard is in NumLock state, etc.

    Fn 03h Set keyboard typeamatic rate and delay. (11/15/85 BIOS)
    Expects: AH  3
	     AL  05h (eg, AX = 0305h)
	     BL  Typeamatic Rate
		 0: 30 keys/sec  10: 10
		 1: 26.7	 13: 9
		 2: 24		 16: 7.5
		 4: 20		 20: 5
		 8: 15		 31: 2
	     BH  Delay: 0=250ms 1=500ms 2=750ms 3=1 second)

    Returns: none

    Description: when a key is pressed, the keyboard will wait during Delay
		 before it starts repeating at Typematic Rate.

    Fn 05h Place a keystroke into the keyboard buffer. (11/15/85 BIOS)
    Expects: AH  5
	     CL  ASCII character.
	     CH  Scan Code  byte (or 0 if you don't care)

    Returns: AL  Status: 0=success; 1=buffer full

    Fn 10h Read (wait for) a keystroke; 101-keyboard only (11/15/85 BIOS)
    Expects: AH  10h

    Returns: AL  ASCII	character  (if	AL=0,  AH is an  Extended ASCII key-
	     AH  Scan Code or Extended ASCII keystroke

    Fn 11h Preview keystroke; same as 01; 101-keyboard only (11/15/85 BIOS)
    Expects: AH  11h

    Returns: ZF  ZR or 1 if no key is ready
	     ZF  NZ or 0 if a key is ready.
	     AX  set as for Fn 10 but keystroke is still in the buffer.

    12h Read shift-key status; same as 02; 101-keyboard only (11/15/85 BIOS)
    Expects: AH  12H
    Returns: AL  shift key and 'lock' status as in 101-keyboard flags

    3.2. Keyboard Flags

    The keyboard flags are found in the BIOS Data Area: segment 40h.

    17h: 83-keyboard flags	0=Off, 1=On
    bit 0: Right shift
	1: Left shift
	2: Ctrl, either side
	3: Alt, either side
	4: Scroll Lock
	5: Num Lock
	6: Caps Lock
	7: Insert state

    Do NOT just change one of these and then hope the keyboard follows.  The
    LEDs will definitely get out of sync.

    18h: 101-keyboard flags	0=Off, 1=On
    bit 0		   : Left ctrl
	1쳐At keyb. only   : Left Alt
	2		   : Sys Req
	3: Pause state
	4: Scroll Lock	   
	5: Num Lock	   쳐Being pressed
	6: Caps Lock	   
	7: Insert	   

    Do NOT just change one of these and then hope the keyboard follows.  The
    LEDs will definitely get out of sync.

    19h: Pseudokey value
    This is the  accumulating value of	the key being  made with Alt+numeric
    keypad.  Normally 0

    71h: Ctrl-break flag	0=Off, 1=On
    bit 7: Ctrl-Break was pressed. Never gets reset, unless you do.

    96h: AT only - keyboard ?	0=Off, 1=On
    bit 4: 101/102 keyboard is attached

    97h: AT only - lock LEDs	0=Off, 1=On
    bit 0: ScrollLock 
	1: NumLock    쳐 keyboard LED is turned on
	2: CapsLock   

    Do NOT just change one of these and then hope the keyboard	follows.
    The LEDs will definitely get out of sync.

    3.3. Keyboard Buffer

    The keyboard  buffer is  a circular  data area.  This means  that when a
    pointer in the  buffer gets one  larger than the  buffer, it is  wrapped
    around to the beginning.

    The keyboard buffer is fed	by int 9 and function  5 of int 16h.   It is
    found at the BIOS data segment, 40h. It is pointed to by 4 variables  in
    the BDA:  The  head (1ah), the tail  (1ch), the Beginning (80h)  and the
    End (82h). They are all words, pointing at locations in the BDA.

    The latter	two are  only available  on ATs  and PSs.  They are  used to
    enlarge the keyboard buffer  by mapping it to  another spot in the	BIOS
    data area.	Normally, that spot is 32 bytes long starting from 1eh.

    The head is  the pointer to  the next word.  The tail is  the pointer to
    the next available word.  Each code is two bytes, the scan code and  the
    ASCII value.

    The buffer is empty if  the Head = the Tail  and it is full if  the Tail
    is two smaller than the Head, both counted circularly.  This means	that
    the storage space equals (length buffer/2)-1.

    4. Low-Level Interfacing

	- Fast
	- Complete control

	- Hard to code
	- Totally NO functions at all. It's Handyman work here...

    The interfacing is split in two items:
	- Just changing something, such as the LED's
	- Reading out codes: int 9

    4.1. Interfacing And Configuring

    The computer and  the AT or  MF II interface  through I/O ports  60h and
    64h, controlled  by a  programmable Intel  8042 (old  ATs), 8741 or 8742
    (newer, allow two  input devices (like  the PS/2 mouse))  microprocessor
    or compatible,  which allows  typematic rate  programming, LEDs lighting
    and some other stuff. It also  has a +-20 byte output buffer  for smooth
    operation and long scancodes.

    The  old  XT  keyboard  has  a  8048,  which  is  in essence just a very
    primitive one-way serial interface, so all used is port 61h, to  disable
    and reenable the keyboard on every scancode.

    Port 60h: Input & output
    Read: Scancodes and keyboarddata
    This port gives the following output codes:

	00h: Keyboard error, too many keys are being pressed at once
	aah: Basic Assurance Test (BAT) end
	abh 41h: The result of requesting keyboard ID on a MF II keyboard
	eeh: The result of the echo command
	fah: ACK(noledge). Sent by every command, except eeh and feh
	fch: BAT failed
	feh: Resend your data please
	ffh: Keyboard error

    All the rest are make (press) and break (release) codes of the keys.

    Write: Command data
    This is the  place where command  data has to  be sent.   If the command
    consists of two bytes, you must  wait until the outputbuffer is sent  to
    the keyboard.   Check on  it via  bit 1  of port  64h. When  you send  a
    command, the outputbuffer is cleared,  so pending results may not  come.
    During transmission of a two-byte command, the keyboard stops  scanning.
    When you  send something  out of  range or	so, the  keyboard will react
    with feh  (resend).   All commands,  except echo  (eeh) and resend (feh)
    result in ACK (fah) to be sent.


    edh: Set keyboard LEDs
	 Send a second byte with:

	     bit 0 = Scroll Lock	0=Off 1=On
		 1 = Num Lock
		 2 = Caps Lock
	      rest = 0

	 Do make an effort to keep the BIOS keyboard flags in sync.

    eeh: Great fun. Send it, and get 0eeh right back! :-]

    f0h: Select scancode set.

	     0: return current set number: 1:'C', 2:'A', 3:'?'
	     1: set scancode set no 1
	     2: set scancode set no 2 -> standard
	     3: set scancode set no 3

    f2h: Identify keyboard
	     XT: nothing (that is, time-out error :-) (see port 64h)
	     AT: ACK
	     MF II: ACK abh 41h

    f3h: Typematic rate programming
	 Send a second byte with:

	     bit 0 -> 4: rate. Timings:

	     0: 30 keys/sec   10: 10
	     1: 26.7	      13: 9
	     2: 24	      16: 7.5
	     4: 20	      20: 5
	     8: 15	      31: 2

	     bit 5 & 6: pause before repeat:

	     0: 250 ms
	     1: 500
	     2: 750
	     4: 1000

	     bit 7: Always 0

    The next  three are  doubtfull, since  one of  my sources say they don't
    exist and another says they do. I leave it up to you :)

    f4h: Enable keyboard. It clears its buffer and starts scanning.
    f5h: Reset keyboard, disable scanning
    f6h: Reset keyboard, enable scanning

    feh: Resend last transmission. I really don't know what it does, since
	 it sends something incomprehesible.

    ffh: Internal diagnostics: Sends aah if successfull.  Warning! The
	 keyboard reacts with ACK and then you have to set the data and
	 clock pins high, DURING AT LEAST 500 SECONDS!. Do this via the
	 outputport (see 64h). After that, the BAT (Basic Assurance Test)
	 starts. This sends aah on success and fch on failure.

    Example: Set the keyboard LEDs

	  in  al, 64h					 \It would be good
	  and al, 02h	;Test if command buffer is empty |to put this in a
	  jnz start					 /macro...

	  mov al, edh
	  out 60h, al	;Write outputport

	  in  al, 64h
	  and al, 02h	;Test if command came through
	  jnz wait

	  mov al, 0111b
	  out 60h, al	;Set all LED's to ON.

    Port 61h
    This  port	is  used  to  acknoledge  the  receival  of  a	scancode, by
    disabling the keyboard  and immediately reenabling	it. This also  means
    that  you  can  read  a  scancode  as  many times as you like, until you
    acknoledge the receival.

    bit 0 -> 5: Nothing to do with keyboard, but with the Programmable
		Peripheral Interface (PPI) -> save them!
    bit 6: Hold keyboard clock low -> Keyboard can't send any data.
    bit 7: 0=Enable keyboard; 1=Disable keyboard


	  in  al, 61h
	  mov ah, al	;Save keyboard status
	  or  al, 80h	;Disable
	  out 61h, al
	  mov al, ah	;Enable (If it was disabled at first, you wouldn't
	  out 61h, al	; be doing this anyway :-)

    Port 64h: Interface: data and control
    Read: Statusport
	bit 0: 1: Keyboard data is in buffer
	       0: Output buffer empty -> use it to check for results
	    1: 1: User data is in buffer
	       0: Command buffer is empty -> time to send a command
	    2: 1: Selftest successful
	       0: Reset (?)
	    3: 1: 64h was last accessed port
	       0: 60h was last accessed port
	    4: 1: Keyboard enabled
	       0: Keyboard locked
	    5: PS/2: Mouse interface
	    6: 1: Time-out error occurred: Keyboard or PS/2 mouse didn't
		  react. Use the Resend command to retry fetching the data
		  byte. This could happen when trying to get a XT keyboard
		  to do something :).
	    7: 1: Last transmission had a parity error

    Write: Control register
    This is the control room  of the keyboard interface. If  additional data
    is required,  send it  to port  60h after  writing the  command to	64h.
    Also, check 61h bit 2 before sending anything.


    aah: Keyboard self test. Sends 55h if successfull.

    abh: Test interface. Sends:

	     00h: No error
	     01h: Clock low
	     02h: Clock high
	     03h: Data low
	     04h: Data high
	     ffh: Total Error

    adh: Deactivate keyboard

    aeh: Activate keyboard

    c0h: Read inputport. This is some highly specialized stuff and I wonder
	 why I am typing this. Ok. The inputport is that what the keyboard
	 is sending and some more. Layout:

	     bit 0: Keyboard data in pin
		 1: PS/2 mouse in pin
		 2->5: reserved
		 6: Wether you have a color or mono screen
		 7: 1: Keyboard not locked
		    0: Keyboard locked

	 When you issue this command, the inputport is put on the
	 outputbuffer, so you have the great priviledge of reading it at
	 port 60h.

    c1h: Puts the low nibble of the input port over bits 4-7 of the
	 statusport, so you can read them out continuously. This lasts
	 until bit 2 of the statusport gets set, meaning you are sending
	 data to the keyboard.

    c2h: Ditto, but it puts the high nibble over bits 0-3 of the
	 statusport. Lifespan is the same.

    d0h: Puts the outputport on the buffer. Layout:

	     bit 0: 1: Reset processor
		 1: 1: A20 gate enable
		 2: PS/2 mouse data out
		 3: PS/2 mouse clock signal
		 4: 1: Output buffer full
		 5: 1: Output buffer PS/2 mouse full
		 6: Keyboard clock signal
		 7: Keyboard data out

	 Bit 0 and 1 are quite important for high memory and
	 286-extended-memory access.

    d1h: Write the following data byte to the outputport

    d2h: Write the following data byte to the keyboardbuffer. This is VERY
	 handy for TSRs that need to read codes that start with e0h. This
	 way, they don't have to pass through the e0h, unless they know for
	 sure it isn't their code, which results in correct functioning
	 shift keys etc. At least, if it does what I think it
	 does... [UNTESTED]

    d3h: Ditto, for PS/2 mouse.

    d4h: Write byte to PS/2 mouse.

    e0h: Reads the keyboards testinputs, T0 and T1. T0 goes to bit 0 and T1
	 to bit 1 of the byte that is put on the outputbuffer.

    fxh: I think it sends x to the low nibble of the output port. It does
	 reset my computer when I send feh, but that doesn't mean anything
	 :-). The official explanation says that it keeps the corresponding
	 bits in the output port low for 6ms...

    Example: Send something to the outputport

	  in  al, 64h					\It would be good
	  and al, 02h	;Test if command buffer is empty|to put this in a
	  jnz start					/macro...

	  mov al, d1h
	  out 64h, al	;Write outputport

	  in  al, 64h
	  and al, 02h	;Test if command came through
	  jnz wait

	  mov al, 01h
	  out 60h, al

    4.2. Lay-Out

    The keyboard first	consisted of 83  keys, which is now known as  the XT
    keyboard.	Then  came  along  the	AT-keyboard,  which  has  84 keys, a
    slightly different layout and an extra SysReq key. The next keyboard  is
    the MF II keyboard.  This one has  101 or 102 keys, and this is the  one
    this section will be babbling about.

    The keycaps  change, but	the  most popular  settings are  QWERTY  and
    AZERTY.  Also popular is the Dvorak lay-out, made	 by  what's-his-name
    Dvorak, who made  the lay-out so  that both hands  did not have  to move
    that much, resulting in fast (up  to double) typing speed.	This  is it,
    should  you be  interested	(slight  modifications	by  me,  because  it
    actually requires a 12x4 keyboard):

	    101 - key			      102 - key

    ~ ! @ # $ % ^ & * ( ) [ +	       ! @ # $ % ^ & * ( ) [ +
    ` 1 2 3 4 5 6 7 8 9 0 ] =	       1 2 3 4 5 6 7 8 9 0 ] =

      " , . P Y F G C R L ? { | 	" , . P Y F G C R L ? {
      ' , . p y f g c r l / } \ 	' , . p y f g c r l / }

      A O E U I D H T N S _ <		A O E U I D H T N S _ ~
      a o e u i d h t n s - >		a o e u i d h t n s - `

      : Q J K X B M W V Z	      > : Q J K X B M W V Z
      ; q j k x b m w v z	      < ; q j k x b m w v z

    The key lay-out is as follows: (The numbers are internal to the

    US-English Keyboard: 101 keys
    10납12131415납16171819납20212223납242526 <컴 Add 100 to the
    읕켸읕컨컴좔컨컴牡컴좔컨컴좔켸읕컨컴좔컨컴牡컴좔컨컴     keycodes on
							      this line
    1 2 3 4 5 6 7 8 910111213 15납758085납9095100105
    30 3132333435363738394041 43  	 9297102106
    쳐컴좔쩝컫좔쩝컫좔쩝컫좔쩝컫좔쩝컫좔쩝컴컴   旼커	 쳐컵컴탠컴탠컴
     44  46474849505152535455  57    83	 9398103   
    58  60  	 61	     62  64납798489납 99  104108
    읕컴 읕컴좔컴컴컴컴컴컴컴컴컴컴좔컴 읕컴牡컴좔컨컴牡컴컴컨컴컨컴켸

    This has the extra 29 key, or \

    Other Countries: 102 keys
    10납12131415납16171819납20212223납242526 <컴 Add 100 to the
    읕켸읕컨컴좔컨컴牡컴좔컨컴좔켸읕컨컴좔컨컴牡컴좔컨컴     keycodes on
							      this line
    1 2 3 4 5 6 7 8 910111213 15납758085납9095100105
    쳐컨쩡좌컨쩡좌컨쩡좌컨쩡좌컨쩡좌컨쩡좌컨 냅컴좔컨컴矛컴탠컵컴캑   
    30 313233343536373839404142  	 9297102106
    쳐컫좔쩝컫좔쩝컫좔쩝컫좔쩝컫좔쩝컫좔쩝컴좔   旼커	 쳐컵컴탠컴탠컴
    444546474849505152535455  57    83	 9398103   
    58  60  	 61	     62  64납798489납 99  104108
    읕컴 읕컴좔컴컴컴컴컴컴컴컴컴컴좔컴 읕컴牡컴좔컨컴牡컴컴컨컴컨컴켸

    This  has  the  extra  42  and  45	keys.  Their characters change from
    country to country.

    4.3. Scancodes

    The AT-keyboard has 3 separate scancode settings:	 One as we know  it,
    (83 key-mapping, and added codes have an extra e0h added), one  (almost)
    sequential and one with ONE byte codes! Problem with the latter is	that
    only  for  lshift,	caps,  lctrl  and  lalt breakcodes are sent :-(. The
    keyboard starts up in  set 2, the set  can be changed via  port 64h (see

    In set 1 and  2, there are special	codes, namely e0h and  e1h. They are
    used for keys that	have  the same function.   An example:	1dh  for the
    left control  key and  e0h 1dh  for the  right one.   This is  done  for
    lowlevel compatibility with XT programs.  Notice that the only time  e1h
    is used, is when it represents  a temporary control key, which also  has
    a e0h version.

    e0h  2ah  is  a  temporary	shift  function, used by for example PrtScr,
    which is  in reality  shift-numkeypad-*, like  on the  XT keyboard.  See
    below for further information.

    The code will be sent as shown  further.  The codes listed are the	make
    codes. They are sent when a  key is pressed. Upon release, the  keyboard
    sends a break  code. It is	the make code,	but ORed with  80h. The only
    exception to this are the codes e0h and e1h, which remain the same.   So
    for example  pressing and  releasing the  right ctrl  key would give e0h
    1dh and e0h 9dh. I only give the codes for set 2 because the rest  would
    be too much work  and stupid. If you  want them, look them	up yourself.
    Modify any of the accompanying source codes or so...

      Only on US-English keyboards
    瓢 Only on other country versions

    Scancodes are in hex.

    Key  Scan  Key  Scan  Key  Scan  Key  Scan	Key  Scan  Key	Scan
    no.  code  no.  code  no.  code  no.  code	no.  code  no.	code
    1	29   19  12	 36  23   53  33   86  쿮0 51106 4e
    2	02   20  13	 37  24   54  34   89  쿮0 4d108 쿮0 1c
    3	03   21  14	 38  25   55  35   90  45   110 01
    4	04   22  15	 39  26   57  36   91  47   112 3b
    5	05   23  16	 40  27   58  1d   92  4b   113 3c
    6	06   24  17	 41  28   60  38   93  4f   114 3d
    7	07   25  18	 42瓢2b   61  39   95  쿮0 35115 3e
    8	08   26  19	 43  1c   62  쿮0 3896  48   116 3f
    9	09   27  1a	 44  2a   64  쿮0 1d97  4c   117 40
    10	0a   28  1b	 45瓢56   75  쿮0 5298  50   118 41
    11	0b   29 2b	 46  2c   76  쿮0 5399  52   119 42
    12	0c   30  3a	 47  2d   79  쿮0 4b100 37   120 43
    13	0d   31  1e	 48  2e   80  쿮0 47101 49   121 44
    15	0e   32  1f	 49  2f   81  쿮0 4f102 4d   122 57
    16	0f   33  20	 50  30   83  쿮0 48103 51   123 58
    17	10   34  21	 51  31   84  쿮0 50104 53   124 (*)
    18	11   35  22	 52  32   85  쿮0 49105 4a   125 46
							  126 (*)

    Key 124, AKA PrtScr/SysRq, is both. When pressed normally, it will	send
    (hex) e0 2a e0  37. This is in  fact a special shift-*,  or the original
    place of that code on the XT keyboard.

    Used in conjuction with:

    Normal: e0 2a e0 37
    Shift : e0 37
    Ctrl  : e0 37
    Alt   : e0 54

    Key 126: Pause/Break. On the  XT keyboard, this used to  be ctrl-NumLock
    and ctrl-ScrollLock. Now guess the	codes...   Very special  is that the
    break codes are sent immediately after  the make codes. I think that  is
    because the codes have odd length.

    Normal: e1 1d 45   (e0 1d is already used by rightctrl)
    Ctrl  : e0 46      (46 is the code for ScrollLock...)

    4.4. Int 9

    When a key is pressed or released, or when the 8042 sends an ACK or  NAK
    the keyboard triggers  IRQ1, or int  9.  This  can be masked  by setting
    bit 1 on port 21h, the  interrupt controller.  Int 9 gets  the scancode,
    translates it and puts it in the keyboard buffer.

    BEWARE: When a scancode consists of more than 1 byte,  it should be read
    ------  one byte per call. (Took me quite long to find out...)

    Int 9 will	first call int	15h, subfunction 4fh,  with the scancode  in
    al.   If  the  scancode  is  legitimate,  the  carry flag is set, and al
    contains the  scancode.   If not,  the carry  flag is  reset, and  int 9
    stops.   (The  carries  are  picked  so  that  if  int 9 thinks the BIOS
    supports the call and it doesn't, the carry is set by the BIOS, and  the
    scancode can always be used). This allows the keyboard to be  redefined,
    by	taking	over  the  function  and  replacing scancodes.

    If you want to take over int  9, you must remember to let the  interrupt
    controller	know when  you are  finished, by  writing 20h  to port	20h,
    since this is a  hardware interrupt.  You  should also disable and	then
    reenable the keyboard (see port 61h), so the keyboard knows you got  the
    code. The codes come in one byte per IRQ, so save e0hs.

    The key will be translated by int 9, with the following special cases:

	User is pressing too many keys at once: beep or something

    aah, bah 41h, eeh, fah, feh:
	Ignore it. Someone is playing with port 60h

    fch, ffh:
	Ditto, but now you know the keyboard is screwed up :)

    e0h 2ah:
	Well. If you let the keyboard decide what the NumLock state is
	(nothing to do with the LED), use it to see how the code must be
	translated (e0h 2ah: NumLock is on). Else, ignore. (Most Smart)

    Ctrl-NumLock or Pause:
	Place system in a tight wait loop until next key pressed. It  would
	be friendly to allow hardware IRQ's... (clock, comms etc) (I think)

	Clear keyboard buffer  (=Equal Head and  Tail), place word  0000h in
	buffer, invoke int 23h, and set flag at 0040h:0071h (bit 7=1).

	Invoke int 5

	redirect CON to PRN. (Teletype mode)
	Never used it, perhaps never will. Doesn't work on my keyboard
	driver... (DOS) Don't know how to stop it.  Perhaps rehitting
	Ctrl-PrtScr... This is from hearsay.

	Invoke int 15 subfunction 85h. al->0 when pressed, 1 when released.

	Reboot. Here's a sample of how to reboot:

	mov ah,0Dh		     ; Disk Reset
	int 21h 		     ; causes SmartDrv 4.x to write cache
	mov ax, 40h		     ; set up segment addressing
	mov ds,ax
	or  byte ptr ds:[17h],0Ch    ; equivalent of pressing CTRL+ALT
	mov ax,4F53h		     ; Issue a "DEL" (53h = DEL scan code)
	int 15h 		     ; EMM386 sees this & shuts down
	mov word ptr ds:[72h],1234h  ; Set REBOOT flag to Warm-Boot (0=cold)
	db 0EAh,0h,0h,0FFh,0FFh      ; JMP FFFF:0000

	Of course, the int 15h call should already have been done by the
	handler. It is also used by other caches to flush.

	Temporarily reverse the NumLock state, e.g. 8 becomes arrow up and
	vice versa.

	Make the pseudokey in BDA byte 19h until the alt is released, then
	put it in the keyboard buffer. How? Well, everytime an extra number
	comes in, multiply BDA:19h with 10 and add the new number.

    Alt release:
	See above. Just making sure it is implemented ;-)

	Send bytes 1 through 27

    Foreign keyboards:
	Some keys are accents, to be placed on the next key.

    Right alt:
	Some keys have three keys on it. To access them, the right alt is
	pressed. So remember to send the right ASCII code...

	Switch numkeypad on/off and light/switch off LED

	Translate normal letters to caps or vice versa and light/switch off
	LED. A nice touch would be to have a distinction between CapsLock
	and Ctrl-CapsLock. The former would shift alfabetic
	keys only and the latter all keys...

	Light/sw. off LED

    Int  9  also  has  to  adjust  the	BDA  flags  and  keyboard buffer. In
    addition, the driver should warn when the keyboard buffer is full.

    5. Tech Stuff

	Bidirectional,	serial	synchronous.  The  keyboard communicates via
	clock and data line with the system. The data comes in 11 bit
	packets, namely start-data-parity-stop. Parity is uneven.
			 =1   8bit  1bit   =0
	Also, see further.

    Data Format:
	Data transfer to and from the keyboard in IBM-compatible format:
	AT-, PS/2-mode: Idle state - "Data & Clock" high.
	PC mode:	Idle state - "Data" low, "Clock" high.

    Data Output:
	Open drain.

    Keyboard Sequence:

    Automatic repeat function:
	All  keys  have  auto  repeat.	 Delay	and  repeat  sequence can be
	modified through the system, but  is fixed for PC-mode. (10Hz  after

    Keyboard Self-diagnostic test:
	After  "Power-On"  or  upon  request,  the  keyboard  carries  out a
	self-diagnostic test. After positive  test, the keyboard sends	AAh.
	Any other is a failure.

    Pin assignment:
	  ___			 1 Clock
	 /524\			 2 Data
	|3   1|커		 3 Not used
	 \__/	쿬hassis gnd	 4 Gnd
		-		 5 +5V (This is the place to tap from :-)

	PS/2 adaptor:		 1 Data
	  _ _			 2 Not used
	 /5U6\			 3 Gnd
	|3   4|커		 4 +5V
	 \1_2/	쿬hassis gnd	 5 Clock
		-		 6 Not used

    The PC-XT keyboard communication protocol
    Below is a drawing of the timing of the data, send to the PC. The  upper
    line shows	the clock  line, the  lower the  data line.  The text  above
    indicates the position of the start, data and stop bits (clocked on  the
    negative edge of the clock line).

    Start    1	   2	 3     4     5	   6	 7     8     Stop
    컴커  旼커	旼커  旼커  旼커  旼커	旼커  旼커  旼커  旼커	旼컴
    clk읕켸  읕켸  읕켸  읕켸  읕켸  읕켸  읕켸  읕켸  읕켸  읕켸
    컴컴컴컴쩡컴컴쩡컴컴쩡컴컴쩡컴컴쩡컴컴쩡컴컴쩡컴컴쩡컴커	  旼
    dta     읕컴컴좔컴컴좔컴컴좔컴컴좔컴컴좔컴컴좔컴컴좔컴컨컴컴컴

    The communication abides to the following rules:

	- On power up or reset, the PC pulls the clock line (normally  high)
	  low for at  least 20 ms.  When it is	released (goes high  again),
	  the keyboard should send the code  0AAh to the PC to indicate  its

	- The data is clocked in  on the negative edge of the  clock signal.
	  The  clock  line  must  normally  be	high,  the  data line can be
	  anything between transmissions. The  clock line is delayed  two PC
	  clock cycles	in the	PC, so	data changes  and the negative clock
	  edge may take  place at the  same time. It  is safer, however,  to
	  build in a bigger delay.

	- A transmission starts with  a start bit (high). Then	follow eight
	  data bits, of witch bit 7 (MSB) indicates the release of the	key.
	  After that  normally follows	a stop	bit (low),  but that  may be
	  left out. In fact, due  to the shift register hardware  inside the
	  PC, any number  of stop bits	could be send,	as long as  they are
	  low.	 Not 100%  hardware compatibles,  however, may	get confused

	- After a transmission, the PC	pulls the data line low until  it is
	  ready processing the data.  The keyboard should wait	with sending
	  any more data until the PC releases the data line again.

    A. Acknowledgments

    This  text	was  made  by  Wout  Mertens,  with the help of Tech Help of
    Flambeaux software, the tech spex of Cherry and some texts I found.

    Information on the PC-XT keyboard communication protocol and the
    kbfunc.c file by Gertjan Klein (Floating somewhere in cyberspace).

    Cherry is the registered trademark of Cherry Microschalter Gmbh etc.
    IBM is the registered trademark of the IBM corporation
    Mertens is the registered trademark of the Mertens Family ;-)

    Improved copyright notice, thanks & greetings to:
	Emil Gilliam (Floating in cyberspace as well)
	Kip Cooley at the Diamond Bar BBS (909) 923-1031 (1:218/101).
	Ian Remmler at the DownTown BBS (210) 625-4479 (1:387/1001).

    B. How To Contact Me

    Please let me know	if something is inaccurate or missing etc.  Also,  I
    would like	some  feedback on  the quality	and usability  of this text.
    (Keeps me	writing...) If you think this text is very usefull, you  can
    always send me a nice postcard from where you live to thank me... I will
    then try to notify you when a new version arrives.

    I am usually  reachable through the  Fido 80XXX echo,  but you can	also
    reach me at the following addresses:

	Fido 2:292/805.1
	SBC  14:1900/457
	DGI  68:320/1.3
	CDN  94:810/1104
	CIN  112:913/101.4

	SnailMail: Wout Mertens
		   Jozef de Bomstr 62
		   2018 Antwerp
		   Belgium - Europe

    C. The Answer To Life, The Universe And All The Rest


    PS: Could anyone tell me the Question?

    (With thanks to Douglas Adams :-)

    D. History

    20 feb 94: release of v1.0
    5  apr 94: changed info on rebooting in int 9
	       added info about XT protocol, by Gertjan Klein
	       added C program to interface with keyboard, by Gertjan Klein
	       removed a bug in the copyright: Emil Gilliam was not to be
	       held liable :-):-):-)
	       removed some general typing errors
    9  apr 94: removed bug in keyboard buffer info: Head and Tail do not
	       point to a location relative to Beginning, but instead
	       directly to the keyboardbuffer
    23 may 94: v1.1