Tutorial 15.1: Interaction - Keyboard

Keyboard

The keyPressed variable is like the mousePressed variable, it is a Boolean value that indicates whether any key on the keyboard is currently being pressed.

We can easily test this variable with a conditional state to draw to the canvas differently depending on whether a key is currently being pressed.

  • Show Code
/** @peep sketch */
 
color lightBlue = color(66, 168, 237);
color darkBlue = color(0, 102, 153);
color orange = color(204, 102, 0);
 
void setup() {
  size(200, 200);
  strokeWeight(4);
}
 
void draw() {
  background(204);
  if (keyPressed == true) {
    fill(orange);
  } else {
    fill(lightBlue);
  }
  ellipse(width/2, height/2, 80, 80);
}

Rather than changing the drawing code directly, as in the above sketch, we can also use a conditional test on keyPressed to change the value of a variable, which will indirectly change the drawing. In the example sketch below, the value for angle is increased whenever a key is pressed. Like the above sketch, this one doesn't care which key is pressed.

  • Show Code
/** @peep sketch */
float angle = 0;
 
void setup() {
  size(200, 200);
  rectMode(CENTER);
  strokeWeight(4);
}
 
void draw() {
  background(204);
  if (keyPressed == true) {
    angle += PI/180;
  }
  translate(width/2, height/2);
  rotate(angle);
  rect(0, 0, 80, 80); // draw a rectangle
}

Develop a sketch that draws differently depending on whether a key (any key) is currently being pressed. You might want to take one of your earliest sketches, e.g., from Drawing with Code, and draw a variation on it when a key is pressed, e.g., sad face / happy face.

The Value of a Key

The value of a key that has been pressed on the keyboard is stored in the key variable. Like mouseButton the value of key is actually the value of the most recently pressed key. In other words, key does not mean that the keyboard key is currently being pressed.

The value is stored as a number with the type char. The numerical value of each character on the keyboard was defined in the early days of computing as ASCII codes. More recent definitions are encoded in the Universal Character Set often referred to as Unicode. The ASCII values are still used as part of the UTF-8 standard that was defined to maintain backwards compatibility for Unicode.

NOTE: In Processing on the desktop the value is stored as a char and while Processing.js also has a char type it doesn't support the printing of this value in the same way. In Processing on the Desktop we can use the value of key directly to println() to the console or to the canvas with text(). Unfortunately, if we try this in Processing.js, JavaScript will print out the ASCII number, not the character, so if we want to display the character that has been pressed we must use a function of String that knows how to convert the ASCII character code: String.fromCharCode(key).

The following sketch shows how we can draw to the canvas the value of the key variable.

  • Show Code
/* @pjs font="/media/css/Chunkfive-webfont.ttf"; */
/** @peep sketch */
PFont font;
 
void setup() {
  size(200, 200);
  font = createFont("/media/css/Chunkfive-webfont.ttf", 144);
  textFont(font);
  textAlign(CENTER, CENTER);
}
 
void draw() {
  background(0);
  String letter = String.fromCharCode(key);
  text(letter, width/2, height/2 + 36);
}

We can use a conditional test on keyPressed and key to determine whether a particular key is being pressed. The sketch below will only update the angle variable when a capital "A" is pressed, i.e., through a "shift-A" key combination. (Depending on your browser, this may also work when CAPS LOCK is on.) The sketch does this with the following test:

    if ((keyPressed == true) && (key == 'A')) {
      // ...
    }

    Remember that && means that both tests (keyPressed == true) and (key == 'A') must be true. This means that a key must currently being pressed and the value of the key being pressed must be "A".

    • Show Code
    /** @peep sketch */
    float angle = 0;
     
    void setup() {
      size(200, 200);
      strokeWeight(4);
      rectMode(CENTER);
    }
     
    void draw() {
      background(204);
      if ((keyPressed == true) && (key == 'A')) {
        angle += PI/180;
      }
      translate(width/2, height/2);
      rotate(angle);
      rect(0, 0, 80, 80);
    }

    We can combine the test for a key being pressed and the value of the key being pressed in different ways. In particular, we can first check that a key is being pressed and then do something different depending on its value. For example the following code will rotate the square one way when "A" is pressed and the other direction when "a" is pressed.

    • Show Code
    /** @peep sketch */
    float angle = 0;
     
    void setup() {
      size(200, 200);
      strokeWeight(4);
      rectMode(CENTER);
    }
     
    void draw() {
      background(204);
      if (keyPressed == true) {
        if (key == 'A') {
          angle += PI/180;
        } else if (key == 'a') {
          angle -= PI/180;
        }
      }
      translate(width/2, height/2);
      rotate(angle);
      rect(0, 0, 80, 80);
    }

    We can extend the test on the key being pressed to easily move a character around a screen. Here's a little example that maintains position (x and y) and heading (angle) as a result of the "a", "s", "w" and "d" keys, which are often used in games.

    • Show Code
    /** @peep sketch */
    float angle = 0;
    float x = 0;
    float y = 0;
    float radius = 20;
     
    void setup() {
      size(200, 200);
      strokeWeight(2);
    }
     
    void draw() {
      background(204);
      if (keyPressed == true) {
        if (key == 'a') {
          angle -= PI/180;
        } else if (key == 'd') {
          angle += PI/180;
        } else if (key == 'w') {
          x += cos(angle);
          y += sin(angle);
        } else if (key == 's') {
          x -= cos(angle);
          y -= sin(angle);
        }
      }
      x = constrain(x, -(width/2 - radius), (width/2 - radius));
      y = constrain(y, -(height/2 - radius), (height/2 - radius));
      translate(width/2 + x, height/2 + y);
      rotate(angle);
      ellipse(0, 0, radius*2, radius*2);
      line(0, 0, radius, 0);
    }

    We can use logic in the above sketch to create a (not very good) keybard-driven drawing program.

    • Show Code
    /** @peep sketch */
    float angle = 0;
    float x = 0;
    float y = 0;
    float px, py;
     
    void setup() {
      size(300, 300);
      strokeWeight(2);
      background(204);
      x = width/2;
      y = height/2
      ellipse(x, y, 1, 1);
    }
     
    void draw() {
      px = x; py = y;
      if (keyPressed == true) {
        if (key == 'a') {
          angle -= PI/180;
        } else if (key == 'd') {
          angle += PI/180;
        } else if (key == 'w') {
          x += cos(angle);
          y += sin(angle);
        } else if (key == 's') {
          x -= cos(angle);
          y -= sin(angle);
        }
      }
      x = constrain(x, 0, width);
      y = constrain(y, 0, height);
      line(px, py, x, y);
    }

    Coded Keys

    Some keys on a standard keyboard don't produce printable characters, e.g., the cursor keys. To handle these keys in a Processing.js sketch we need to first test whether the current value of key is "coded", i.e., a special character, and if so, check the value of keyCode against a number of defined constants. These constants are UP, DOWN, LEFT, RIGHT for the arrow keys and ALT, CONTROL, SHIFT, BACKSPACE, TAB, ENTER, RETURN, ESC, and DELETE.

    The following sketch reacts to the following keys: LEFT (turn left), RIGHT (turn right), SHIFT (move forward) and CONTROL (move back).

    • Show Code
    /** @peep sketch */
    float angle = 0;
    float x = 0;
    float y = 0;
    float radius = 20;
     
    void setup() {
      size(200, 200);
      strokeWeight(2);
    }
     
    void draw() {
      background(204);
      if (keyPressed == true) {
        if (key == CODED) {
          if (keyCode == LEFT) {
            angle -= PI/180;
          } else if (keyCode == RIGHT) {
            angle += PI/180;
          } else if (keyCode == SHIFT) {
            x += cos(angle);
            y += sin(angle);
          } else if (keyCode == CONTROL) {
            x -= cos(angle);
            y -= sin(angle);
          }
        } 
      }
      x = constrain(x, -(width/2 - radius), (width/2 - radius));
      y = constrain(y, -(height/2 - radius), (height/2 - radius));
      translate(width/2 + x, height/2 + y);
      rotate(angle);
      ellipse(0, 0, radius*2, radius*2);
      line(0, 0, radius, 0);
    }

    Confusingly, there are some keys on the keyboard that aren't printable but do have ASCII codes. This means that some keys that we would expect to check keyCode for can actually be checked using just the key value. We just need to check the key value against some special values: BACKSPACE, TAB, ENTER, RETURN, ESC, and DELETE. (You should check both ENTER and RETURN to make sure your program will work for all platforms.)

    Experiment with the key and keyCode variables to control the appearance of a sketch.

    Comments

    Nobody has said anything yet.