Making sure that every key press makes gets recorded
There are lots of control keys in Aviator - I mean, the game even comes with its own little poster showing a picture of a keyboard with all the game keys marked. It perhaps isn't surprising, then, that the game contains its own key logging routine to ensure no key presses are lost in the excitement of flying a Spitfire.
Out of the box, the BBC Micro's operating system only supports a "two-key rollover". This means that it can handle up to two concurrent key presses, on top of the modifier keys like SHIFT and CTRL. This level of support is generally fine for typing, as you rarely intend to press more than two letter keys at the same time, but for a game like Aviator with different keys for elevator, rudder, aileron, throttle and plenty else, using the built-in routines would mean a lot of ignored key presses.
Let's look at Aviator's key logger and see how it keeps track of everything.
Aviator gets around the operating system's limitations by implementing its own keyboard-scanning routine in ScanKeyboard. This uses the operating system's OSBYTE command to scan the keyboard for a specific key, so when we want to check whether any of the flight keys are being pressed, we call this routine individually for each key we are interested in. This sidesteps the operating system's built-in limit, and allows us to support an arbitrary number of concurrent key presses.
Given this method of checking for individual keys, the UpdateKeyLogger routine manages the rest. This routine records each significant key press as a 16-bit number in the key logger table at (keyLoggerHi keyLoggerLo). The key logger table contains six entries, each of which corresponds with a key pair. The key pairs are as follows:
- L or < (elevator dive/pitch)
- A or + (rudder yaw left/right)
- S or D (aileron bank left/right)
- W or E (throttle down/up)
- U or B (undercarriage, brakes)
- F or SHIFT (flaps, fire)
The key logger works by scanning in turn for each of the first keys shown above (i.e. "L", "A", "S", "W", "U" or "F", whose internal key numbers are in the keyTable1 table). If a key is pressed, then the corresponding 16-bit value from the (keyTable1Hi keyTable1Lo) table is stored in the key logger at the relevant key's entry. Otherwise it scans for the second key (i.e. "<", "+", "D", "E", "B" or SHIFT, whose internal key numbers are in the keyTable2 table), and if that is pressed, then the corresponding 16-bit value from the (keyTable2Hi keyTable2Lo) table is stored in the key logger.
In this way all the main flight keys are checked, and in a way where we don't bother to check for a second key if the first in that pair is being pressed (so if we are pressing "S" and "D" at the same time, the logger will ignore the "D" key press and bank the plane to the left, for example).
Not only that, but the values that are inserted into the key logger are used by the UpdateFlightModel routine to directly affect the plane's orientation. The values are as follows:
- Elevator dive/pitch = -1 or 1
- Rudder yaw left/right = -1 or 1
- Aileron bank left/right = -1 or 1
- Throttle down/up = -15 or 15
- Undercarriage, brakes = 4 or 7
- Flaps, fire = 5 or 8
The numbers for the last two bullet points don't have a direct meaning - they just let the ProcessOtherKeys routine test for whether or not the keys are pressed - but the values in the first four directly affect the flight model. So, if we press "L" to pitch the plane down, then the first entry in the key logger will be set to -1, and this is the value that gets added to the elevatorPosition variable to move the elevators in the flight model. Similarly, the throttle keys change the thrust by 15 in either direction.
This opens up the intriguing possibility of being able to scale the effects of the flight controls differently by altering the entries that the key logger takes from (keyTable1Hi keyTable1Lo) and (keyTable2Hi keyTable2Lo). A turbo-charged, super-responsive Spitfire? That would an interesting experience...