From: jt@fuw.edu.pl (Jerzy Tarasiuk)
Subject: Re: Non-buffered Keyboard Input
Organization: Warsaw University Physics Dept.
Date: Tue, 29 Sep 1992 14:32:33 GMT

>>>>> On Mon, 28 Sep 92 15:08:44 GMT, bmc@mayo.edu (Bruce Cameron, Med Sci 1-14, 4-3288) said:
Bruce> I am looking for a way to avoid buffered keyboard input, the application
Bruce> I am developing needs to be able to do the following:
Bruce> 	1) register a key press
Bruce> 	2) tell what key was pressed
Bruce> 	3) register when the key was released
Bruce> All without buffering.
Bruce> Does anyone have any suggestions as to how to do this in C/C++,  or
Bruce> am I going to have to get into assembly? If I have to get into assembly,
Bruce> any suggested alogrythms?

I suppose need write at least part of program in assembly because it
requires servicing interrupts. It is possible to service interrupts in
C but C uses more stack space. If want write interrupt service in C,
must declare the procedure as interrupt, do not use any non-static
variables in it or call any other procedures. Can use setjmp/longjmp
to switch stack (suppose it uses few words only).

Interrupt to be serviced: IRQ1, usually INT 9. Algorythms:
- On XT can read port 0x60 as many times as need and clear
 IRQ by: { int q=inp(0x61); outp(0x61,q | 0x80); outp(0x61,q); }.
- On AT reading of port 0x60 clears IRQ and allows keyboard to send
 next scan code, but the scan code read from port 0x60 may be error
 info making necessary to send response to keyboard before it can send
 next scan code. For this case, BIOS sends command 0xAD to port 0x64
 to disable keyboard and then reads scan code from port 0x60, and if
 it requires some processing BIOS does it, otherwise BIOS sends 0xAE
 to port 0x64 to enable keyboard. I would advice: send command 0xAD,
 read port 0x60, if value read is scan code then send command 0xAE
 and process it, otherwise jump to BIOS code (I don't know how to do
 it in C without use much more stack).
 I used assembly program and called BIOS always:
  if(AT) send_cmd(0xAD);
  scan_code=inp(0x60);
  switch(scan_code){
   ...
  };
  <<call BIOS>>
  <<final processing>>
 Sending command to port 0x64: while(inp(0x64)&2); outp(0x64,cmd);
- on both XT and AT need send Interrupt Acknowledge to Interrupt
 Controller: outp(0x20,0x61); when interrupt service is done.
 Be sure to disable interrupts before doing it! 
 Note if BIOS is called it send Interrupt Acknowledge and enables
 keyboard, to protect program against re-entry from next interrupt
 before service is done need mask keyboard interrupt:
 outp(0x21,inp(0x21)|2); <do all processing> outp(0x21,inp(0x21)&0xFD);
 (of course need disable interrupts before the last outp).
- the value read from port 0x60 is scan code which identifies key
 pressed or released. Key released gives scan code as when pressed
 + 0x80. Some keys on new keyboards can cause sequence of scan codes.
 I didn't want to put all translation tables in my program and this
 was reason to use BIOS to do the translation (but my program had set
 shift status before calling BIOS to make it put key code in buffer,
 I needed to detect Caps/Num/Scoll-Lock to get correct display on
 keyboard LEDs - on these codes BIOS sends shift info to keyboard).
 Next problem is auto-repeat feature: keyboard sends scan code few
 times in second while key is hold (but pressing another key and
 releasing it stops auto-repeat of first key). Be aware of it in your
 program (BIOS must remember it received codes of toggle keys).
Newsgroups: alt.msdos.programmer