Using the keyboard in animation programs

When you use a KeyListener in Java, you have to decide whether you are using key codes or key characters. And then you have to be consistent with this throughout your program.

This is the same for HSA2 and Swing. In this document, we'll look at how to do it in HSA2

Choose one of these two

Key CharactersKey Codes
reads every character that can be typed on a keyboard reads every key that can be pressed on a keyboard
Distinguishes between 'A' and 'a' Cannot distinguish between 'A' and 'a'
(It's exactly the same key being pressed)
Cannot detect any special keys Can detect function keys, cursor keys, shift keys, numberpad keys, etc
Easy to use:
if (gc.getKeyChar() == 'p') {...}
unless you need to check both cases:
if (gc.getKeyChar() == 'p' || gc.getKeyChar() =='P') { //pause game
A little bit harder to use.
You have to know the number for the up arrow key
if (gc.getKeyCode() == 38) { //up arrow pressed
or use a built in constant
if (gc.getKeyCode() == KeyEvent.VK_UP) { //up arrow pressed
but the normal keys have the value of the uppercase letter:
if (gc.getKeyCode() == 'Q') { // Q key pressed

Common Problems with Keypresses

Pressing the key results in multiple keypresses being triggered

See the sample program below

Motion is not smooth as there is a delay caused by the OS

-- this does not seem to happen in HSA2 like it does in normal Swing graphics. I wonder why?

Sample program to illustrate keyboard input

Copy and paste the code into Eclipse. I'm not going to colour code it here


import java.awt.Color;
import java.awt.Rectangle;
import hsa2.GraphicsConsole;
public class Keyboard1 {

	public static void main(String[] args) {
		new Keyboard1();

	}
	
	GraphicsConsole gc = new GraphicsConsole(700,500);
	Rectangle paddle = new Rectangle(300,450,80,10);
	Rectangle r1 = new Rectangle(100,100,50,160);
	
	final static int PADDLEMOVE = 5; //number of pixels that the paddle will move with each key press
	
	boolean trigger = false;
	
	Keyboard1() {
		gc.setBackgroundColor(Color.BLACK);
		gc.clear();
		gc.setLocationRelativeTo(null);
		//gc.setTitle("Click on the Green Rectangle");
		
		
		while(true) {
			/********** display keycodes in the TITLE *********/
			// it's a quick and clever way to find them
			gc.setTitle("The keycode for the current key is " + gc.getKeyCode());
			
			
			
			/*****************************************************
			 * Move the paddle using keys
			 * ***************************************************
			 * PROBLEMS:
			 * 1. Notice that the paddle should only move 5 pixels but it moves a LOT more
			 * 2. Operating system delay
			 * 3. No way to move diagonally by holding two keys down at the same time
			 * ***************************************************/
			if (gc.getKeyChar() == 'a') {
				if (paddle.x > 0) paddle.x -= PADDLEMOVE;
			}
			if (gc.getKeyChar() == 'd') {
				if (paddle.x < 690) paddle.x += PADDLEMOVE;  //FIXME: ERROR: DO NOT USE MAGIC NUMBERS
			}
			if (gc.getKeyChar() == 'w') {
				if (paddle.y > 0) paddle.y -= PADDLEMOVE;
			}
			if (gc.getKeyChar() == 's') {
				if (paddle.y < 490) paddle.y += PADDLEMOVE;
			}
			
			
			
			/****************************************************
			 * 1. Problem 1.  FAIL.
			 * 	  NO. THIS DOES NOT SOLVE THE PROBLEM OF MULTIPLE INPUTS WITH ONE PRESS OF A KEY!!!
			 * 
			 * 2. Problem 2.  SUCCESS (but not noticable on my computer)
			 * 
			 * 3. Problem 3: SUCCESS 
			 *******************************************************/
			if (gc.isKeyDown(37)) {	//isKeyDown uses keyCodes. Left arrow
				if (paddle.x > 0) paddle.x -= PADDLEMOVE;
			}
			if (gc.isKeyDown(39)) { //right
				if (paddle.x < 690) paddle.x += PADDLEMOVE;
			}
			if (gc.isKeyDown(38)) {	//up
				if (paddle.y > 0) paddle.y -= PADDLEMOVE;
			}
			if (gc.isKeyDown(40)) {	//down
				if (paddle.y < 490) paddle.y += PADDLEMOVE;
			}

			
			
			
			
			/******************************************************************
			 * How to allow something to be done only once upon a keypress:
			 * 'H' will make the block half the height
			 ******************************************************************/
			if (gc.isKeyDown('H')) {
				if (!trigger) {		//if the trigger is ready
					trigger = true;	//the trigger has already been pulled. It needs to be reset
					r1.height = r1.height /2;
				}
			}
			
			if (! gc.isKeyDown('H')) {	//when you let go of the H key
				trigger = false;	//reset the trigger.				
			}
			
			
			/********** Do all drawing together ***********/
			synchronized(gc) {
				gc.clear();
				gc.setColor(Color.GRAY.darker().darker().darker().darker());
				
				for (int i=0; i< 700; i += 10) {
					gc.drawLine(i, 0, i, 500);
				}
				gc.setColor(Color.GREEN);
				gc.fillRect(r1.x, r1.y, r1.width, r1.height);
				gc.setColor(Color.YELLOW);
				gc.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
				gc.drawString("The gray lines are 10 pixels apart", 20,20);
				gc.drawString("Each keypress should move the paddle " + PADDLEMOVE + " pixels.", 20,40);
			}
			gc.sleep(5);
			
		} //end of while loop
		
	}
}