3.6 KEYBOARD CONTROLS

 

 

INTRODUCTION

 

Programs become especially interactive when the user can control the program execution by using keys on the keyboard. Although keystrokes are actually events that always occur independently of the program, they can be captured also through querying functions.

PROGRAMMING CONCEPTS: Boolean data type, game state, animation

 

 

KEYBOARD CONTROLS

 

The command getKeyCodeWait() will stop the program until you press a key. Then, the function provides you with the corresponding key code as a return value. With the exception of certain special keys, each key has its own numerical code.

You can figure out the key codes using a simple test program. The numerical codes are written in the console window.
from gpanel import *
makeGPanel(0, 10, 0, 10)

text(1, 5, "Press any key.")
while True:
    key = getKeyCodeWait()
    print(key)
 


Highlight program code (Ctrl+C copy, Ctrl+V paste)

 

 

MEMO

 

You can use the command getKeyCodeWait() for keyboard inputs. The computer waits until you press a key and then returns the key code.

However, you have to remember that the GPanel window must be active. In other words, it must be in focus. If the window loses focus, you have to click somewhere inside it in order to activate it again. Only the currently active window receives keyboard events.

 

 

CONTROLLING FIGURES

 

You can move graphic objects using the keyboard. The program controls the green circle with the cursor keys, moving it left, right, up, or down. In a so-called event loop

the program waits for a key press and then processes the obtained key code in a nested if-else structure.

Since the drawing of the circle is used over and over again, it makes sense that you would pack the code into its own function drawCircle() that can be called multiple times, in compliance with the structured programming paradigm.
 

 

from gpanel import *

KEY_LEFT = 37
KEY_RIGHT = 39
KEY_UP = 38
KEY_DOWN = 40

def drawCircle():
    move(x, y)
    setColor("green")
    fillCircle(5)
    setColor("black")
    circle(5)
    
makeGPanel(0, 100, 0, 100)
text("Move the circle with the arrow keys.")
x = 50
y = 50
step = 2
drawCircle()
 
while True:
    key = getKeyCodeWait()
    if key == KEY_LEFT:
        x -= step
        drawCircle()
    elif key == KEY_RIGHT:
        x += step
        drawCircle()
    elif key == KEY_UP:
        y += step
        drawCircle()
    elif key == KEY_DOWN:
        y -= step
        drawCircle()        
Highlight program code (Ctrl+C copy, Ctrl+V paste)

 

 

MEMO

 

To make the program more readable, you can introduce constants for the keyboard codes of the arrow keys. So that they are especially noticeable, constants should be placed in the program header and written in capital letters.

 

 

NON-BLOCKING KEYBOARD QUERIES

 

As you are probably aware, the keyboard is often used to control the game play in computer games. In this case you can of course not use the blocking function getKeyCodeWait() because it would pause the game. Rather, you need a function that will deliver the information if a key has been pressed, but that also immediately returns.

In case you indeed pressed a key, you process this event, otherwise the game will continue on normally.

 

 

You want the speed of a ball moving back and forth to get slower with the letter key 's' (for slow) and get faster with 'f' (for fast), but only up to a certain maximum value. You need to again focus your attention on the event loop, which is where everything essential happens. In it, kbhit() periodically queries, whether a key was hit or not. If this is the case, kbhit() returns True and you can get the key code by using getKeyCode().

from gpanel import *
import time

KEY_S = 83
KEY_F = 70

makeGPanel(0, 600, 0, 600)
title("Key 'f': faster, 's': slower")

enableRepaint(False)
x = 300
y = 300
v = 10
vmax = 50
isAhead = True

while True:
    startTime = time.clock()

    if kbhit():
        key = getKeyCode()
        if key == KEY_F:
            if v < vmax:
              v += 1
        elif key == KEY_S:
            if v > 0:
              v -= 1
    
    clear()
    setColor("black")
    text(10, 10, "Speed: " + str(v))
    if isAhead:
        x = x + v
    else:
        x = x - v
    move(x, y)
    setColor("red")
    fillCircle(20)
    repaint()
    if x > 600 or x < 0:
        isAhead = not isAhead
    while (time.clock() - startTime)  < 0.010:
        delay(1)
Highlight program code (Ctrl+C copy, Ctrl+V paste)

 

 

MEMO

 

Since it is an animation, we again need to use an animation timer in order to obtain a run through the event loop that is as periodic as possible. The next game state is created in the loop and it is then displayed in the window screen with repaint().

kbhit() returns a truth value, which we refer to as a boolean. If a key was pressed since the last call, it returns True, otherwise False.
In order to move the ball to the right (forward), its x-coordinate must increase by v (the measure for speed) with each pass of the event loop. To move to the left, the coordinate v must decrease. We summarize a forward and backward movement as a game state which we save in the variable isAhead.

You can add a word to a second word in Python using the + character, for example "Hans" + "Peter" results in the word "HansPeter". However, if you want to add a number to a word, you first have to convert the number using the str() function.

 

 

EXERCISES

 

1.

Using the cursor keys UP, DOWN, LEFT and RIGHT draw a snake line of small red circles, which lie closely next to each other.

 
2.

As an extension, define the following buttons for color selection: after you press the letter key g, the circles should turn green, b should make them blue, and r red.


3.

Extend the above program with the ball moving back and forth so that the UP and DOWN cursor keys make the ball move up and down.