The Keyboard¶
Let’s look at the keyboard

The Next can support a few different keyboards, but from our point of view they’re all the same. It doesn’t matter whether you’re using a 48k dead flesh keyboard, a 128k keyboard, a clone keyboard, PS2 or the official one on the retail machine. They all work the same. You can’t read the extra keys off the PS/2 keyboard, and it’s not possible to remap the keys.
Z88DK has its own keyboard routines, but they mostly deal with scancodes and ASCII. It’s possible to read the keyboard directly.
It is arranged in rows, with each row being split into two parts of 5 keys which are accessed through specific IO ports.
Port |
0 |
1 |
2 |
3 |
4 |
---|---|---|---|---|---|
0xFEFE |
Shift |
z |
x |
c |
v |
0xFDFE |
a |
s |
d |
f |
g |
0xFBFE |
q |
w |
e |
r |
t |
0xF7FE |
1 |
2 |
3 |
4 |
5 |
0xEFFE |
0 |
9 |
8 |
7 |
6 |
0xDFFE |
p |
o |
i |
u |
y |
0xBFFE |
Enter |
l |
k |
j |
h |
0x7FFE |
Space |
Sym |
m |
n |
b |
Bits are set to 0 for a key being pressed and 1 if the key is not pressed. Multiple key presses can be read together.
What I have done is use z80_inp()
to read each port in turn, storing the data into an array of bytes
// Get all the key states
void keyboard_update_state()
{
swap_buffers(); // Keep the previous state
// Now get the new state
current_buffer[0] = z80_inp(KEYBOARD_PORT_ROW_1a);
current_buffer[1] = z80_inp(KEYBOARD_PORT_ROW_1b);
current_buffer[2] = z80_inp(KEYBOARD_PORT_ROW_2a);
current_buffer[3] = z80_inp(KEYBOARD_PORT_ROW_2b);
current_buffer[4] = z80_inp(KEYBOARD_PORT_ROW_3a);
current_buffer[5] = z80_inp(KEYBOARD_PORT_ROW_3b);
current_buffer[6] = z80_inp(KEYBOARD_PORT_ROW_4a);
current_buffer[7] = z80_inp(KEYBOARD_PORT_ROW_4b);
}
Then I have a list of defines for each key on the keyboard to index into those arrays The values are the index within the array for that key, based on its position within the table above, combined with an index for which row it is on.
// These masks encode the buffer and bit position within that buffer
// First Row
#define KEY_1 0x01
#define KEY_2 0x02
#define KEY_3 0x04
#define KEY_4 0x08
#define KEY_5 0x0A
#define KEY_6 0x1A
#define KEY_7 0x18
#define KEY_8 0x14
#define KEY_9 0x12
#define KEY_0 0x11
Then there are two macros to extract the correct row array, and the correct bit from that array. This is done to turn key lookups into straight forward bitwise operations rather than conditional statements.
#define KEYBOARD_BUFFER_INDEX(x) (x & 0xF0) >> 4
#define KEYBOARD_BUFFER_BIT(x) (x & 0x0F)
To use this I have three functions to get the state of a key depending on what I want to find out
void keyboard_update_state();
inline bool_t keyboard_is_key_pressed(uint8_t key);
inline bool_t keyboard_is_key_released(uint8_t key);
inline bool_t keyboard_is_key_held(uint8_t key);