Toby Opferman http://www.opferman.net programming@opferman.net Using The Keyboard Using the keyboard is the MOST common input for the PC and other computers. Although, even with GUI's as the mouse is slowly replacing the keyboard you still need the keyboard to type (Unless you get Voice Recognition). It seems trivial to have a tutorial on something as easy to use as the keyboard, but this is not just about calling 'getch()' or 'scanf'. I will explain how to use the keyboard more effiently. There are a number of ways to get input from the keyboard in DOS and we will go over a few of them. One of them is INT 16h - the BIOS Keyboard interrupt. XOR AH, AH INT 16h ; This is Equal to getch() in C This will wait for the user to type in a single key. and return it in AX. AH = ScanCode, AL = ASCII Code MOV AH, 1 INT 16h ; This is the same as kbhit() in C JZ NO_KEY This will set the 0 flag if no key is in the buffer, and if there is one, it will return the key in AX same as Function 00h in the first example, EXCPT, it will NOT remove it from the keyboard buffer. You MUST call a function such as the first to remove it from the buffer, or else your buffer will reach it's maximum fill and the keyboard will just beep. You may want to use DOS to read in characters. DOS's interrupt is INT 21h. MOV AH, 1 INT 21h AL = Character Read And there are a few others that you can look up if you are interested but they all read a character in. Some read with echo and some read with out echo. Echo means the character read in is displayed on the screen at the same time, like getche() in C. But, one of the more useful functions of INT 21h is MOV AH, 0Ch INT 21h Clear Keyboar Buffer. If your buffer gets full, just call this interrupt to clear it. OR, clear the keyboard buffer manually as we will see how to do a little bit later in this tutor. Another way is to read the keyboard ports. Ports 60h-64h The BEST thing you could possibly do with the ports is hook interrupt 9h. Everytime a key is pressed, INT 9h is called. Everytime a key is release INT 9h is called. INT 9h is the software for the hardware interrupt of the keyboard. KeyList db 128 DUP(0) The Above creates an array of 128 bytes that will represent the Key Scan Codes KeyList[ScanCode] Will get you the status of the key (C Syntax) 0 = Not Pressed 1 = Pressed Temp dw 0 Press db 0 INT9HANDLER PROC PUSHA ; Save Registers & Enable Interrupts STI IN AL, 0x60 ; Get Key XOR AH, AH MOV Temp, AX ; Put Scan Code in Temp IN AL, 0x61 OR AL, 0x82 ; Set Bits to Reset KB Flip Flop OUT 0x61, AL AND AL, 0x7F ; Finish the Reset OUT 0x61, AL MOV AL, 0x20 ; Tell PIC Enable Interrupts OUT 0x20, AL XOR AL, AL MOV Press, AL ; Set Press = 0, Meaning a Unpress Code CMP Temp, 128 JL SHORT UnpressCode INC AX MOV Press, AL ; Set Press = 1, Meaning a Press Code JMP DONE UnpressCode: MOV AX, 128 SUB Temp, AX ; Set Temp to ScanCode < 128 DONE: MOV BX, Temp ; Get Index to ScanCode Array MOV SI, Offset KeyList MOV DS:[SI+BX], Press ; Set Key To Press or UnPress POPA IRET ; End Interrupt Handler ENDP INT9HANDLER The Above Interrupt will service keyboard presses. It will set a list of keys to Pressed (1) or Not Pressed (0) According to their scan code. This is one of the fastest, if not the fastest way to detect keys on the keyboard. As soon as they are pressed, this ISR is serviced. In your code, all you have to do is poll your hot keys with a simple test or cmp and continue processing. No waiting, no lagtime interrupts, just the check of a memory location. Remeber, the scan codes are raw and do not apply to any shift state. You will have to read the Keyboard Status Flags to find out the shift state of a key. Flag1 0040:0017h BIT Meaning If Set to 1 7 INSert Active 6 Caps Lock Active 5 Num Lock Active 4 Scroll Lock Active 3 Either ALT Pressed 2 Either CNTRL Pressed 1 Left Shift Pressed 0 Right Shift Pressed Flag2 0040:0018h BIT Meaning If Set to 1 7 INSert Pressed 6 Caps Lock Pressed 5 Num Lock Pressed 4 Scroll Lock Pressed 3 Pause State Active 2 Sys Req Pressed 1 Left Alt Pressed 0 Left Cntrl Pressed To Get Both Bytes: MOV AX, 40h ; BIOS Segment PUSH DS ; Save Data Seg MOV DS, AX ; Set BIOS Segment MOV DI, 17h ; Offset 17h & 18h MOV AX, [DI] ; Read Word POP DS ; Restore And finally, how to manipulate the keyboard buffer manually. The Keyboard buffer is at Segment 0040h The Start of the buffer is at 80h, 1Ah is pointing to the First Character (Or Next Character) in the buffer and 1Ch is pointing to the next free slot. To Clear the buffer do the following The Keyboard buffer is at 1Eh (16 Bytes Circular) Standard, but you can change that by changing the values in the keyboard pointers at 80h, 81h, 1Ah and 1Ch. To Clear the Keyboard Buffer, just do this: .186 PUSH 40h POP DS ; Set Segment MOV DI, 80h MOV BX, [DI] ; Get First Memory Location MOV DI, 1Ah MOV [DI], BX ; Set 1Ah To First Location MOV DI, 1Ch MOV [DI], BX ; Set 1Ch To First Location After all is well, you can just check the value of 1ah vs 1ch. Once the values are differnt, get the value at 1ah and get the value pointed to by that value and you have the ascii value. Then just set 1ch and 1ah equal to each other again using 80h or setting 1ch equal to 1ah. Here is an example: GETKEY: MOV SI, 1Ah ; Pointer to first/next key MOV DI, 1Ch ; Pointer to next free locatoin MOV BX, [SI] ; Get Address CMP BX, [DI] ; Compare Values JE SHORT GETKEY ; If Equal, no keys ; Key In Buffer MOV AL, [BX] ; Get key MOV [DI], BX ; Clear buffer JMP SHORT GETKEY ; Do it Again Even though the above is an endless loop, you get the idea. NOTE: For more information on any of the interrupts/ports used in this Tutor, get an interrupt/port list such as Ralf Brown's Interrupt List off the web or buy a book.