> ### Section 6.5
> Keyboard Events

> IN JAVA, EVENTS are associated with GUI components. When the user presses a button on the mouse, the event that is generated is associated with the component that contains the mouse cursor. What about keyboard events? When the user presses a key, what component is associated with the key event that is generated?

> A GUI uses the idea of input focus to determine the component associated with keyboard events. At any given time, exactly one interface element on the screen has the input focus, and that is where all keyboard events are directed. If the interface element happens to be a Java component, then the information about the keyboard event becomes a Java object of type `KeyEvent`, and it is delivered to any listener objects that are listening for `KeyEvents` associated with that component. The necessity of managing input focus adds an extra twist to working with keyboard events.

> It's a good idea to give the user some visual feedback about which component has the input focus. For example, if the component is the typing area of a word-processor, the feedback is usually in the form of a blinking text cursor. Another common visual clue is to draw a brightly colored border around the edge of a component when it has the input focus, as I do in the sample applet later on this page.

> A component that wants to have the input focus can call the method `requestFocus()`, which is defined in the `Component` class. Calling this method does not absolutely guarantee that the component will actually get the input focus. Several components might request the focus; only one will get it. This method should only be used in certain circumstances in any case, since it can be a rude surprise to the user to have the focus suddenly pulled away from a component that the user is working with. In a typical user interface, the user can choose to give the focus to a component by clicking on that component with the mouse. And pressing the tab key will often move the focus from one component to another.

> Some components do not automatically receive the input focus when the user clicks on them. To solve this problem, a program has to register a mouse listener with the component to detect user clicks. In response to a user click, the `mousePressed()` method should call `requestFocus()` for the component. This is true, in particular, for the components that are used as drawing surfaces in the examples in this chapter. These components are defined as subclasses of `JPanel`, and JPanel objects do not receive the input focus automatically. If you want to be able to use the keyboard to interact with a JPanel named `drawingSurface`, you have to register a listener to listen for mouse events on the `drawingSurface` and call `drawingSurface.requestFocus()` in the `mousePressed()` method of the listener object.

> Here is a sample applet that processes keyboard events. If the applet has the input focus, the arrow keys can be used to move the colored square. Furthermore, pressing the 'R', 'G', 'B', or 'K' key will set the color of the square to red, green, blue, or black. When the applet has the input focus, the border of the applet is a bright cyan (blue-green) color. When the applet does not have the focus, the border is gray, and a message, "Click to activate," is displayed. When the user clicks on an unfocused applet, it requests the input focus. (In some browsers, you also have to leave the mouse positioned inside the applet, in order for it to have the input focus.) The complete source code for this applet is in the file KeyboardAndFocusDemo.java. I will discuss some aspects of it below. After reading this section, you should be able to understand the source code in its entirety.

> (Applet "KeyboardAndFocusDemo" would be displayed here
> if Java were available.)

> In Java, keyboard event objects belong to a class called `KeyEvent`. An object that needs to listen for `KeyEvents` must implement the interface named `KeyListener`. Furthermore, the object must be registered with a component by calling the component's `addKeyListener()` method. The registration is done with the command "`component.addKeyListener(listener);`" where `listener` is the object that is to listen for key events, and `component` is the object that will generate the key events (when it has the input focus). It is possible for `component` and `listener` to be the same object. All this is, of course, directly analogous to what you learned about mouse events in the previous section. The `KeyListener` interface defines the following methods, which must be included in any class that implements `KeyListener`:

>                public void keyPressed(KeyEvent evt);
>                public void keyReleased(KeyEvent evt);
>                public void keyTyped(KeyEvent evt);

> Java makes a careful distinction between the keys that you press and the characters that you type. There are lots of keys on a keyboard: letter keys, number keys, modifier keys such as Control and Shift, arrow keys, page up and page down keys, keypad keys, function keys. In many cases, pressing a key does not type a character. On the other hand, typing a character sometimes involves pressing several keys. For example, to type an uppercase 'A', you have to press the Shift key and then press the A key before releasing the Shift key. On my Macintosh computer, I can type an accented e, é, by holding down the Option key, pressing the E key, releasing the Option key, and pressing E again. Only one character was typed, but I had to perform three key-presses and I had to release a key at the right time. In Java, there are three types of `KeyEvent`. The types correspond to pressing a key, releasing a key, and typing a character. The `keyPressed` method is called when the user presses a key, the `keyReleased` method is called when the user releases a key, and the `keyTyped` method is called when the user types a character. Note that one user action, such as pressing the E key, can be responsible for two events, a `keyPressed` event and a `keyTyped` event. Typing an upper case 'A' could generate two `keyPressed`, two `keyReleased`, and one `keyTyped` event.

> Usually, it is better to think in terms of two separate streams of events, one consisting of `keyPressed` and `keyReleased` events and the other consisting of `keyTyped` events. For some applications, you want to monitor the first stream; for other applications, you want to monitor the second one. Of course, the information in the `keyTyped` stream could be extracted from the `keyPressed/keyReleased` stream, but it would be difficult (and also system-dependent to some extent). Some user actions, such as pressing the Shift key, can only be detected as `keyPressed` events. I have a solitaire game on my computer that hilites every card that can be moved, when I hold down the Shift key. You could do something like that in Java by hiliting the cards when the Shift key is pressed and removing the hilite when the Shift key is released.

> There is one more complication. Usually, when you hold down a key on the keyboard, that key will auto-repeat. This means that it will generate multiple `keyPressed` events, as long as it is held down. It can also generate multiple `keyTyped` events. For the most part, this will not affect your programming, but you should not expect every `keyPressed` event to have a corresponding `keyReleased` event.

> Every key on the keyboard has an integer code number. (Actually, this is only true for keys that Java knows about. Many keyboards have extra keys that can't be used with Java.) When the `keyPressed` or `keyReleased` method is called, the parameter, `evt`, contains the code of the key that was pressed or released. The code can be obtained by calling the function `evt.getKeyCode()`. Rather than asking you to memorize a table of code numbers (which can be different for different platforms in any case), Java provides a named constant for each key. These constants are defined in the `KeyEvent` class. For example the constant for the shift key is `KeyEvent.VK_SHIFT`. If you want to test whether the key that the user pressed is the Shift key, you could say "`if (evt.getKeyCode() == KeyEvent.VK_SHIFT)`". The key codes for the four arrow keys are `KeyEvent.VK_LEFT`, `KeyEvent.VK_RIGHT`, `KeyEvent.VK_UP`, and `KeyEvent.VK_DOWN`. Other keys have similar codes. (The "VK" stands for "Virtual Keyboard". In reality, different keyboards use different key codes, but Java translates the actual codes from the keyboard into its own "virtual" codes. Your program only sees these virtual key codes, so it will work with various keyboards on various platforms without modification.)

> In the case of a `keyTyped` event, you want to know which character was typed. This information can be obtained from the parameter, `evt`, in the `keyTyped` method by calling the function `evt.getKeyChar()`. This function returns a value of type `char` representing the character that was typed.

> In the `KeyboardAndFocusDemo` applet, shown above, I use the `keyPressed` routine to respond when the user presses one of the arrow keys. The applet includes instance variables, `squareLeft` and `squareTop` that give the position of the upper left corner of the square. When the user presses one of the arrow keys, the `keyPressed` routine modifies the appropriate instance variable and calls `canvas.repaint()` to redraw the whole applet. ("`canvas`" is the name I use for the drawing surface component in this applet.) Note that the values of `squareLeft` and `squareRight` are restricted so that the square never moves outside the white area of the applet:

>        public void keyPressed(KeyEvent evt) {
>               // Called when the user has pressed a key, which can be
>               // a special key such as an arrow key.  If the key pressed
>               // was one of the arrow keys, move the square (but make sure
>               // that it doesn't move off the edge, allowing for a
>               // 3-pixel border all around the applet).  SQUARE_SIZE is
>               // a named constant that specifies the size of the square.
>               // squareLeft and squareRight give the position of the
>               // top-left corner of the square.

>           int key = evt.getKeyCode();  // Keyboard code for the pressed key.

>           if (key == KeyEvent.VK_LEFT) {  // left-arrow key; move square up
>              squareLeft -= 8;
>              if (squareLeft < 3)
>                 squareLeft = 3;
>              canvas.repaint();
>           }
>           else if (key == KeyEvent.VK_RIGHT) {  // right-arrow key; move right
>              squareLeft += 8;
>              if (squareLeft > getSize().width - 3 - SQUARE_SIZE)
>                 squareLeft = getSize().width - 3 - SQUARE_SIZE;
>              canvas.repaint();
>           }
>           else if (key == KeyEvent.VK_UP) {  // up-arrow key; move up
>              squareTop -= 8;
>              if (squareTop < 3)
>                 squareTop = 3;
>              canvas.repaint();
>           }
>           else if (key == KeyEvent.VK_DOWN) {  // down-arrow key; move down
>              squareTop += 8;
>              if (squareTop > getSize().height - 3 - SQUARE_SIZE)
>                 squareTop = getSize().height - 3 - SQUARE_SIZE;
>              canvas.repaint();
>           }

>        }  // end keyPressed()

> Color changes -- which happen when the user types the characters 'R', 'G', 'B', and 'K', or the lower case equivalents -- are handled in the `keyTyped` method. I won't include it here, since it is so similar to the `keyPressed` method. Finally, to complete the `KeyListener` interface, the `keyReleased` method must be defined. In the sample applet, the body of this method is empty since the applet does nothing to respond to `keyReleased` events.

> ### Focus Events

> If a component is to change its appearance when it has the input focus, it needs some way to know when it has the focus. In Java, objects are notified about changes of input focus by events of type `FocusEvent`. An object that wants to be notified of changes in focus can implement the `FocusListener` interface. This interface declares two methods:

>              public void focusGained(FocusEvent evt);
>              public void focusLost(FocusEvent evt);

> Furthermore, the `addFocusListener()` method must be used to set up a listener for the focus events. When a component gets the input focus, it calls the `focusGained()` method of any object that has been registered with that component as a `FocusListener`. When it loses the focus, it calls the listener's `focusLost()` method. Often, it is the component itself that listens for focus events.

> In my sample applet, there is a boolean-valued instance variable named `focussed`. This variable is `true` when the applet has the input focus and is false when the applet does not have focus. The applet implements the `FocusListener` interface and listens for focus events from the `canvas`. The `paintComponent()` method of the `canvas` looks at the value of `focussed` to decide what color the border should be. The value of `focussed` is set in the `focusGained()` and `focusLost()` methods. These methods call `canvas.repaint()` so that the drawing surface will be redrawn with the correct border color. The method definitions are very simple:

>           public void focusGained(FocusEvent evt) {
>                  // The canvas now has the input focus.
>              focussed = true;
>              canvas.repaint();  // redraw with cyan border
>           }

>           public void focusLost(FocusEvent evt) {
>                 // The canvas has now lost the input focus.
>              focussed = false;
>              canvas.repaint();  // redraw with gray border
>           }

> The other aspect of handling focus is to make sure that the `canvas` gets the focus when the user clicks on it. To do this, the applet implements the `MouseListener` interface and listens for mouse events on the `canvas`. It defines a `mousePressed` routine that asks that the input focus be given to the canvas:

>            public void mousePressed(MouseEvent evt) {
>               canvas.requestFocus();
>            }

> The other four methods of the `mouseListener` interface are defined to be empty. Note that the applet implements three listener interfaces, so the class definition begins:

>           public class KeyboardAndFocusDemo extends JApplet
>                            implements KeyListener, FocusListener, MouseListener

> The applet's `init()` method registers the applet to listen for all three types of events. To do this, the `init()` method includes the lines

>              canvas.addFocusListener(this);
>              canvas.addKeyListener(this);
>              canvas.addMouseListener(this);

> There are, of course, other ways to organize this applet. It would be possible, for example, to use the `canvas` object instead of the applet object to listen for events. Or anonymous classes could be used to define separate listening objects.

> ### State Machines

> The information stored in an object's instance variables is said to represent the state of that object. When one of the object's methods is called, the action taken by the object can depend on its state. (Or, in the terminology we have been using, the definition of the method can look at the instance variables to decide what to do.) Furthermore, the state can change. (That is, the definition of the method can assign new values to the instance variables.) In computer science, there is the idea of a state machine, which is just something that has a state and can change state in response to events or inputs. The response of a state machine to an event or input depends on what state it's in. An object is a kind of state machine. Sometimes, this point of view can be very useful in designing classes.

> The state machine point of view can be especially useful in the type of event-oriented programming that is required by graphical user interfaces. When designing an applet, you can ask yourself: What information about state do I need to keep track of? What events can change the state of the applet? How will my response to a given event depend on the current state? Should the appearance of the applet be changed to reflect a change in state? How should the `paintComponent()` method take the state into account? All this is an alternative to the top-down, step-wise-refinement style of program design, which does not apply to the overall design of an event-oriented program.

> In the `KeyboardAndFocusDemo` applet, shown above, the state of the applet is recorded in the instance variables `focussed`, `squareLeft`, and `squareTop`. These state variables are used in the `paintComponent()` method to decide how to draw the applet. They are set in the various event-handling methods.

> In the rest of this section, we'll look at another example, where the state of the applet plays an even bigger role. In this example, the user plays a simple arcade-style game by pressing the arrow keys. The example is based on one of my frameworks, called `KeyboardAnimationApplet2`. (See Section 3.7 for a discussion of frameworks and a sample framework that supports animation.) The game is written as an extension of the `KeyboardAnimationApplet2` class. It includes a method, `drawFrame()`, that draws one frame in the animation. It also defines `keyPressed` to respond when the user presses the arrow keys. The source code for the game is in the file SubKillerGame.java. You can also look at the source code in KeyboardAnimationApplet2.java, but it uses some advanced techniques that I haven't covered yet.

> You have to click on the game to activate it. The applet shows a black "submarine" moving back and forth erratically near the bottom. Near the top, there is a blue "boat". You can move this boat back and forth by pressing the left and right arrow keys. Attached to the boat is a red "depth charge." You can drop the depth charge by hitting the down arrow key. The objective is to blow up the submarine by hitting it with the depth charge. If the depth charge falls off the bottom of the screen, you get a new one. If the sub explodes, a new sub is created and you get a new depth charge. Try it! Make sure to hit the sub at least once, so you can see the explosion.

> (Applet "SubKillerGame" would be displayed here
> if Java were available.)

> Let's think about how this applet can be programmed. What constitutes the "state" of the applet? That is, what things change from time to time and affect the appearance or behavior of the applet? Of course, the state includes the positions of the boat, submarine, and depth charge, so I need instance variables to store the positions. Anything else, possibly less obvious? Well, sometimes the depth charge is falling, and sometimes it's not. That is a difference in state. Since there are two possibilities, I represent this aspect of the state with a boolean variable, `bombIsFalling`. Sometimes the submarine is moving left and sometimes it is moving right. The difference is represented by another boolean variable, `subIsMovingLeft`. Sometimes, the sub is exploding. This is also part of the state, but representing it requires a little more thought. While an explosion is in progress, the sub looks different in each frame, since the size of the explosion increases. Also, I need to know when the explosion is over so that I can go back to drawing the sub as usual. So, I use a variable, `explosionFrameNumber`, of type `int`, which tells how many frames have been drawn since the explosion started. I represent the fact that no explosion is happening by setting the value of `explosionFrameNumber` to zero. Alternatively, I could have used another boolean variable to keep track of whether or not an explosion is in progress.

> How and when do the values of these instance variables change? Some of them can change when the user presses certain keys. In the program, this is checked in the `keyPressed()` method. If the user presses the left or right arrow key, the position of the boat is changed. If the user presses the down arrow key, the depth charge changes from not-falling to falling. This is coded as follows:

>        public void keyPressed(KeyEvent evt) {

>            int code = evt.getKeyCode();  // which key was pressed

>            if (code == KeyEvent.VK_LEFT) {
>                    // Move the boat left.
>               boatCenterX -= 15;
>            }
>            else if (code == KeyEvent.VK_RIGHT) {
>                    // Move the boat right.
>               boatCenterX += 15;
>            }
>            else if (code == KeyEvent.VK_DOWN) {
>                    // Start the bomb falling, if it is not already falling.
>               if ( bombIsFalling == false )
>                  bombIsFalling = true;
>            }

>        } // end keyPressed()

> Note that it's not necessary to call `repaint()` when the state changes, since this applet is an animation that is constantly being redrawn anyway. Any changes in the state will become visible to the user as soon as the next frame is drawn. At some point in the program, I have to make sure that the user does not move the boat off the screen. I could have done this in `keyPressed()`, but I choose to check for this in another routine, just before drawing the boat.

> Other aspects of the state are changed in the `drawFrame()` routine. From the point of view of programming, this method is handling an event ("Hey, it's time to draw the next frame!"). It just happens to be an event that is generated by the `KeyboardAnimationApplet2` framework rather than by the user. In my applet, the `drawFrame()` routine calls three other methods that I wrote to organize the process of computing and drawing a new frame: `doBombFrame()`, `doBoatFrame()`, and `doSubFrame()`.

> Consider `doBombFrame()`. This routine draws the depth charge. What happens in this routine depends on the current state, and the routine can make changes to the state when it is executed. The state of the bomb can be falling or not-falling, as recorded in the variable, `bombIsFalling`. If `bombIsFalling` is false, then the bomb is simply drawn at the bottom of the boat. If `bombIsFalling` is true, the vertical coordinate of the bomb has to be increased by some amount to make the bomb move down a bit from one frame to the next. Several other things can also happen. If the bomb has fallen off the bottom of the applet -- something that we can test by looking at its vertical coordinate -- then `bombIsFalling` becomes false. This puts the bomb back at the boat in the next frame. Also, the bomb might hit the sub. This can be tested by comparing the locations of the bomb and the sub. If the bomb hits the sub, then the state changes in two ways: the bomb is no longer falling and the sub is exploding. These state changes are implemented by setting `bombIsFalling` to false and `explosionFrameNumber` to 1.

> Most interesting is the submarine. What happens with the submarine depends on whether it is exploding or not. If it is (that is, if `explosionFrameNumber > 0`), then yellow and red ovals are drawn at the sub's position. The sizes of these ovals depend on the value of `explosionFrameNumber`, so they grow with each frame of the explosion. After the ovals are drawn, the value of `explosionFrameNumber` is incremented. If its value has reached 14, it is reset to 0. This reflects a change of state: The sub is no longer exploding. It's important for you to understand what is happening here. There is no loop in the program to draw the stages of the explosion. Each frame is a new event and is drawn separately, based on values stored in instance variables. The state can change, which will make the next frame look different from the current one.

> In a frame where the sub is not exploding, it moves left or right. This is accomplished by adding or subtracting a small amount to the horizontal coordinate of the sub. Whether it moves left or right is determined by the value of the variable, `subIsMovingLeft`. It's interesting to consider how and when this variable changes value. If the sub reaches the left edge of the applet, `subIsMovingLeft` is set to `false` to make the sub start moving right. Similarly, if the sub reaches the right edge. But the sub can also reverse direction at random times. The way this is implemented is that in each frame, there is a small chance that the sub will reverse direction. This is done with the statement

>                  if ( Math.random() < 0.04 )
>                     sumIsMovingLeft = !subIsMovingLeft;

> Since `Math.random()` is between 0 and 1, the condition "`Math.random() < 0.04`" has a 4 in 100, or 1 in 25, chance of being true. In those frames where this conditions happens to evaluate to `true`, the sub reverses direction. (The value of the expression "`!subIsMovingLeft`" is `false` when `subIsMovingLeft` is `true`, and it is `true` when `subIsMovingLeft` is `false`, so it effectively reverses the value of `subIsMovingLeft`.)

> While it's not very sophisticated as arcade games go, the `SubKillerGame` applet does use some interesting programming. And it nicely illustrates how to apply state-machine thinking in event-oriented programming.

[ Next Section | Previous Section | Chapter Index | Main Index ]