Avoiding key-repeat delay problems

If you have written OPL programs that involve being able to move things around by holding a key down (for example, moving a spaceship left and right in a space-invaders game) you may have run into problems with keyboard repeat.

The problem is summarised as follows... When a key is pressed and held down, the first key event occurs immediately. However, there is a delay before the following key events, so that when a user is typing they don't find their text kkeeeeepppsss ddooiiinnggg tthhiiiissss all the time. Great for typing, but not so good for space invaders. Additionally, the key-repeat speed can be set differently between computers. If someone has a really low repeat speed, it'll take them longer to move or rotate their ship, making the game harder (or even impossible) to play.

This can be seen in action by running the KeyRepeat.opo program in the zip file below. This is a very simple "etch-a-sketch" type program, where the cursor keys move your dot around the screen and Esc quits (I've not added any other functionality for the sake of a simple example). When you hold down a cursor key, the dot moves only a single pixel and then pauses; then it will continue to move -- normally fairly slowly.

Zip icon KeyrepeatTest.zip

There is an alternative way of getting the user's keypresses however. As well as the standard key events returned from the GetEvent32 functions, a system event is fired every time a key is pressed down, and every time a key is released too. Using these events it is possible to monitor which keys are being pressed and process them in a standard execution loop, ignoring completely the standard keypress events.

The two events required have values $406 (key pressed down) and $407 (key released). The third element of the event array contains a key-code for the key that has been pressed or released, and the fourth contains modifier information (Shift, Ctrl, Fn). For standard alpha-numeric keypresses you will receive ASCII values in event&(3) (all upper-case for alpha keypresses), but please note that non-alphanumeric keypresses return completely different values to those received by normal key-press events.

The second example program in the zip file, KeyDown.opo, shows this method in operation. Four global flags are defined (up%, down%, left%, right%) and when the appropriate cursor key events are received, the flags are set to 1 (on key down events) or 0 (on key up events). The main loop then moves the point in the appropriate direction for each flag that is set to true.

Running this program should show the differences immediately. There is no delay when a key is pressed and the movement is much faster. This also removes any dependancy on the user's key-repeat delay and repeat speed.

Note that you may well find this method produces movement that is very much faster than you require in your programs. If this is the case, a time-stamp approach to movement will need to be adopted (using the functions in Date.opx) to determine how much time has passed since you last processed movement. This should also result in identical movement speeds on all platforms (even the emulator), regardless of processor speed.

If you have any comments or suggestions regarding this article, please don't hesitate to contact me.

This article is copyright © Adam Dawes, 2000.