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 !
; Direct Input Routines for the 83/83+
; By Joe Pemberton (firstname.lastname@example.org)
;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
halt ;to mimic _getcsc
getkd: ld a,$ff
ld b,a ;bits 0,1,2,3 are the arrows
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
ld b,a ;bit 7 is the enter key
or %11001111 ;only get 2nd/mode
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.