Direct Input routines from Joe Pemberton

Ok today let's play a bit with the getkd.z80 file from Joe Pemberton.

The code is very small and very easy to understand but my code reviews are destined to all kind of programmers.
So this review is for newbies ! :D
Let's go !

;GETKD/GETKDH ; Direct Input Routines for the 83/83+ ; ; By Joe Pemberton ( ; ;GetKD will return b with the following bits reset (if the keys are down): ;bit 0 - down ;bit 1 - left ;bit 2 - right ;bit 3 - up ;bit 4 - 2nd ;bit 5 - mode ;bit 6 - clear ;bit 7 - enter ; ; GetKDH will do the same, but it will not repeat on 2nd, mode, clear or enter (i.e. ; if you press enter you must release it before GetKDH will detect it again) The arrow ; keys will always repeat. ; ; ;============= key equates for getkd(h) ============= KDB_DOWN = 0 KD_DOWN = %11111110 KDB_LEFT = 1 KD_LEFT = %11111101 KDB_RIGHT = 2 KD_RIGHT = %11111011 KDB_UP = 3 KD_UP = %11110111 KDB_2ND = 4 KD_2ND = %11101111 KDB_MODE = 5 KD_MODE = %11011111 KDB_CLEAR = 6 KD_CLEAR = %10111111 KDB_ENTER = 7 KD_ENTER = %01111111 KD_MASK = %11110000 ;do not repeat keys for bits 4-7 ;change this mask to make different keys repeat

This part is only equates, Joe simply defines that KDB_DOWN will be equal to 0, KD_DOWN will be equal to 254 etc...
So when he use later on of these string (the left operand), it's replaced by the value (the right operand).
Before we continue, I need to explain a bit what's direct input and how it works.

Direct input consists in testing the keyboard using ports instead of calling a getkey routine (which stops until a key is pressed).
Direct input is very fast, and do not stop your program. You need to use this for games (do you imagine stoping a game until the player press a key...? RPG is ok for that, mario or doom isn't :p).
How it works? You need to send a value to a port to select which key group you want to scan.
Then read the port and if a key is pressed (or two keys, or three... That's another reason to use direct input...) you will have one or more zeros in your result.
Please check the values of KD_DOWN, KD_RIGHT, KD_UP etc... Do you notice something particular?
The zero simply moves from the bit 0 to bit 1, then bit 2 etc...

Ok now we need to talk about repeat keys...
When you use direct input, you will probably read multiple times that a key is pressed because the direct input process will be executed several times diring the period you press the key.
To detect only a keypress (press then release), you need to simply lock when you press and unlock when you release. So you will have only one signal when you press a key.
I'm sure I wasn't clear at all so we will simply look at the code and I hope you will understand easily :D
getkdh: call getkd ld hl,getkdflag ld a,b ld c,b or (hl) ld b,a ld a,c cpl and KD_MASK ld (hl),a ei halt ;to mimic _getcsc ret getkd: ld a,$ff ld b,a out (1),a ld a,$fe out (1),a in a,(1) and b ld b,a ;bits 0,1,2,3 are the arrows ld a,$ff out (1),a ld a,$fd out (1),a in a,(1) ;catch enter/clear keypress or %10111110 ;only get enter/clear keypress rrca ;enter keypress is in bit 7, clear in bit 5 bit 5,a jr nz,getkd2 xor %01100000 getkd2: and b ld b,a ;bit 7 is the enter key ld a,$ff out (1),a ld a,$bf out (1),a in a,(1) rra or %11001111 ;only get 2nd/mode and b ld b,a ret getkdflag: .db 0

Ok we have 2 routines here. The getkdh and getkd.
The first one will simply call the second as soon as it enters.
In getkd, I see that Joe sends FF value to the port 1 (keyboard) to reset it.
Then he sends FE value to the port 1 to select the key group (arrows...).
Then it re-reset the port and send the value FD to scan another group (clear, enter, etc...).
There are also some commands to organize result in a, then finally Joe does the same job with 2nd/Mode.
So he reset the port, sends BF to select a key group and read the keys.
At this point, three key group have been read and only some keys are represented in the a register.
There's always a tiny thing we forget, the repeat key issue.
This is the job of getkdh, which seems to acts as a kind of a switch.