The keyboard and mouse are the only realistic devices for user input in a Java game, regardless of whether it’s a web-based applet or a standalone application. But even when considering a standard Windows-based game developed in DirectX or another library, the keyboard and mouse are by far the most common forms of user interaction in a game. This chapter covers the important subject of handling user input.
Here are the key topics you will learn in this chapter:
Listening for keyboard events
Testing keyboard input
Displaying key presses
Reading mouse motion
Detecting mouse buttons
Testing mouse input
Java provides an interesting way to interact with users through a series of listener methods. You tell Java that you would like to listen to keyboard input events, and then Java sends keyboard events to your own listener methods, at which point you can check the key codes to figure out which keys have been pressed or released. The way Java tells your program that a key has been pressed (or that the mouse has moved) is through an interface that your program uses—or rather, implements. Your program must use the implements
keyword to use an interface class. This is a type of class that just includes methods your program needs to use (or implement); the class doesn’t really have any functionality on its own. This type of class is called an interface because it represents a blueprint of the methods your program must use.
The KeyListener
interface listens for events generated by the keyboard and sends those events to the callback methods implemented in your program. These methods are called keyPressed, keyReleased,
and keyTyped,
and these three methods all have a single parameter called KeyEvent.
When writing a program to use the KeyListener,
you modify the class definition of your program using the implements
keyword:
public class KeyboardTest extends JFrame implements KeyListener
The interesting thing about the implements
feature of Java classes is that you can implement multiple interfaces in your program by separating the interface class names with commas.
You may recall seeing the implements
keyword used before with the Runnable
interface (which added threading support). When you need to add more than one interface class, you can separate them with commas.
Your program needs to then call the addKeyListener
method to initialize the keyboard listener so that key events will be sent to your program by the Java Runtime Environment. The sole parameter of this method is the instance of your program’s class, represented by the keyword this.
You use this
as a way to identify the current class in a block of code without referring to that class specifically by name. It is usually best to call addKeyListener(this)
in the init
method within your program. (Recall that the constructor method is automatically called when your program starts running.)
Next, you must implement the three keyboard events in your program to satisfy the KeyListener
interface:
public void keyPressed(KeyEvent e) public void keyReleased(KeyEvent e) public void keyTyped(KeyEvent e)
There are two ways to determine the key that has been pressed or released using the KeyEvent
parameter. If you want to determine the character code of a key, you can use the getKeyChar
method, which returns a char.
If you want to know whether a key has been pressed based on the key code instead of the character, you can use the getKeyCode
method instead. If your program is listening to the keyboard and you press the A key, then getKeyChar
will return “a” (or “A” if you are holding down Shift), while getKeyCode
will return a virtual key code called VK_A.
All of the virtual key codes are contained in a class called KeyEvent.
Table 8.1 shows a partial list of virtual key codes for the most commonly used keys for a game.
Table 8.1. Virtual Key Codes (Partial List)
Key Code | Description |
---|---|
| Left arrow |
| Right arrow |
| Up arrow |
| Down arrow |
| Numeric keys |
| Alphabetic keys |
| Function keys |
| Numeric keypad left |
| Numeric keypad right |
| Numeric keypad up |
| Numeric keypad down |
| Enter key |
| Backspace key |
| Tab key |
Let’s write a program to test keyboard input so you will have a complete example of how this works with Java code. I have highlighted the important code in bold. You can see the output of this program in Figure 8.1.
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class KeyboardTest extends JFrame implements KeyListener { int keyCode; char keyChar; public static void main(String[] args) { new KeyboardTest(); } public KeyboardTest() { super("Keyboard Test"); setSize(500,400); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addKeyListener(this); } public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.WHITE); g2d.fill(new Rectangle(0,0,500,400)); g2d.setColor(Color.BLACK); g2d.drawString("Press a key. . .", 20, 40); g2d.drawString("Key code: " + keyCode, 20, 60); g2d.drawString("Key char: " + keyChar, 20, 80); } public void keyPressed(KeyEvent e) { keyCode = e.getKeyCode(); keyChar = ' '; repaint(); } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { keyChar = e.getKeyChar(); repaint(); } }
This is the bare-minimum code you need to provide keyboard support to your Java programs, so you might want to jot down this page number for future reference (or save the code in a file that you can easily find).
A virtual key code is a platform-neutral value for a key. When you write code to work with a certain virtual key code (such as VK_LEFT
), you can be certain that the key will be detected on any platform (Windows, Linux, Mac, Solaris, and so on).
The constructor method is a special method in a JFrame application. The constructor is the first method that runs when an application starts up. There are several other events generated by JFrame, such as paint()
, that I will explain as we go along. The paint()
event, for instance, refreshes the graphics in the window, so this is often where programmers will write much of the code for a game.
Tapping into the mouse handler in Java is similar to the process of programming the keyboard, as you might have suspected. Java handles mouse input using events that are generated by the Java Runtime Environment (JRE) and passed to your program when you implement a mouse listener.
The Java Runtime Environment, or JRE, is a subset of the Java Development Kit (JDK) that is designed to allow you to have access to an essential set of classes that you can use to run Java programs. The JRE is also most commonly installed on end-user PCs when they want to run a Java program (including web applets). Both the JDK and JRE are included in the Java SE 6 download package.
The first step you must take to incorporate mouse event handling in your program is to call two functions that will tell the JRE to begin sending your program mouse events. Since we’ll be dealing with two interfaces for the mouse, you must initialize both mouse handlers. This is similar to the function you learned about for initializing the keyboard handler. You put these functions in the constructor method so that they are sure to be called when the program starts up. You’ll recall from the keyboard section earlier in this chapter that the this
keyword represents the current program; in more technical terms, this
represents the primary object that was created based on the class definition in your program.
An object is not a class; it is the result of a class. Think of a class as a blueprint for a product, and an object as the product itself that has been constructed.
addMouseListener(this); addMouseMotionListener(this);
Java provides an interface class for mouse motion and button press events that is similar to the keyboard interface. The MouseListener
class is an abstract class that provides your program with an interface, or blueprint, with five methods that you must implement in your program (regardless of whether you will use all of them):
public void mouseClicked(MouseEvent e)
public void mouseEntered(MouseEvent e)
public void mouseExited(MouseEvent e)
public void mousePressed(MouseEvent e)
public void mouseReleased(MouseEvent e)
The MouseListener
interface keeps track of the mouse buttons, the mouse position in the window, and the mouse location when the mouse cursor moves into and out of the window.
There is another, completely different interface class for mouse movement. You can read the mouse’s position during a button or enter/leave event with a MouseListener,
but receiving events for actual mouse motion on the window requires another interface. To receive events for the mouse’s movement across the window, you must use the MouseMotionListener
interface. There are two events in this interface:
public void mouseDragged(MouseEvent e)
public void mouseMoved(MouseEvent e)
Some of these events report when a mouse button is clicked, pressed, or released. The only methods that do not deal with the mouse buttons are mouseEntered, mouseExited,
and mouseMoved,
all of which deal with the mouse’s position and motion, regardless of button status. The remaining events (mouseClicked, mousePressed, mouseReleased,
and mouseDragged)
all have to do with the buttons.
As you might have noticed, all of these events have a single parameter called MouseEvent.
This parameter is actually a class, and the JRE fills it with information for each mouse event. You can look inside this class to get the mouse’s position and button values. For the mouse’s X and Y position values, you can use MouseEvent.getX()
and MouseEvent.getY().
The parameter is usually defined as (MouseEvent e),
so in actual practice you would use e.getX()
and e.getY()
to read the mouse’s current position.
Likewise, MouseEvent
tells you which button was pressed. Inside MouseEvent
is a method called getButton()
that will equal one of the following values depending on which button is being pressed:
BUTTON1
BUTTON2
BUTTON3
The getButton()
method is useful if you only care about detecting a single button press. If, for whatever reason, you need to know when two or three mouse buttons are being pressed at the same time, you can use a different method in the MouseEvent
class called getModifiers()
. This function will report multiple events in the MouseEvent
class, such as the following:
BUTTONI_MASK
BUTTON2_MASK
BUTTON3_MASK
There are many more masked values (that is, values that are bit-packed into a single variable) in the MouseEvent
class that you can examine using the getModifiers()
method. But if all you care about are the usual left-click and right-click events, you can make use of getButton().
I would like to show you a program called MouseTest that demonstrates all of the mouse events that you have just learned about. To build this program, you should create a new project called MouseTest, and then remove all of the automatically generated code to be replaced with the following code listing instead. This program uses the Graphics2D.drawString
method and a bunch of variables to display the status of all the mouse events individually. Figure 8.2 shows what the program output looks like. Note the important parts of the code listing in bold.
The first part of the program includes the class definition (with the needed interfaces following the implements
keyword) and variable declarations.
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MouseTest extends JFrame implements MouseListener, MouseMotionListener { //declare some mouse event variables int clickx, clicky; int pressx, pressy; int releasex, releasey; int enterx, entery; int exitx, exity; int dragx, dragy; int movex, movey; int mousebutton; public static void main(String[] args) { new MouseTest(); }
The constructor is the first method that gets run in an application, and in this case, it’s called public MouseTest().
So this is where you would initialize your game objects and variables, and this is also where you add the listeners for any input devices the program needs to use. If your program ever seems to be ignoring the keyboard or mouse, check this method to make sure you have added the appropriate listener.
public MouseTest() { super("Mouse Test"); setSize(500,400); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addMouseListener(this); addMouseMotionListener(this); }
The paint()
event method is called whenever the window needs to be refreshed. Since paint()
comes with a parameter (Graphics g),
we can use this object to draw onto the screen. In this program, I’ve used the Graphics.drawString()
method to display text on the window. This code is messy in print due to the line wrapping, but it looks nice in the source code file included with this chapter’s resource files (www.courseptr.com/downloads).
//redraw the window public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.WHITE); g2d.fill(new Rectangle(0,0,500,400)); g2d.setColor(Color.BLACK); g2d.drawString("Mouse clicked " + mousebutton + " at " + clickx + "," + clicky, 10, 40); g2d.drawString("Mouse entered at " + enterx + "," + entery,10,55); g2d.drawString("Mouse exited at " + exitx + "," + exity, 10, 70); g2d.drawString("Mouse pressed " + mousebutton + " at " + pressx + "," + pressy, 10, 85); g2d.drawString("Mouse released " + mousebutton + " at " + releasex + "," + releasey, 10, 100); g2d.drawString("Mouse dragged at " + dragx + "," + dragy, 10, 115); g2d.drawString("Mouse moved at " + movex + "," + movey, 10, 130); }
The next portion of code includes the checkButton()
method, which I have written to support the mouse event handler in the program. This checkButton()
method checks the current button that is being pressed and sets a variable (mousebutton)
to a value representing the pressed button.
//custom method called by mouse events to report button status private void checkButton(MouseEvent e) { //check the mouse buttons switch(e.getButton()) { case MouseEvent.BUTTON1: mousebutton = 1; break; case MouseEvent.BUTTON2: mousebutton = 2; break; case MouseEvent.BUTTON3: mousebutton = 3; break; default: mousebutton = 0; } }
The mouseClicked()
event is part of the MouseListener
interface. When you implement this interface, you must include all of the mouse events defined in the interface, or the compiler will generate some errors about the missing events. This event is called whenever you click the mouse button on the window—in which case both a press and release has occurred. This event is not usually needed when you program mousePressed()
and mouseReleased()
yourself.
public void mouseClicked(MouseEvent e) { //save the mouse position values clickx = e.getX(); clicky = e.getY(); //get an update on buttons checkButton(e); //refresh the screen (call the paint event) repaint(); }
The next two mouse event methods, mouseEntered()
and mouseExited(),
are called whenever the mouse cursor enters or leaves the window. These events are not often needed in a game.
public void mouseEntered(MouseEvent e) { enterx = e.getX(); entery = e.getY(); repaint(); } public void mouseExited(MouseEvent e) { exitx = e.getX(); exity = e.getY(); repaint(); }
The mousePressed()
and mouseReleased()
event methods are called whenever you click and release the mouse button, respectively. When these events occur, you can get the current position of the mouse as well as the button being pressed or released.
public void mousePressed(MouseEvent e) { pressx = e.getX(); pressy = e.getY(); checkButton(e); repaint(); } public void mouseReleased(MouseEvent e) { releasex = e.getX(); releasey = e.getY(); checkButton(e); repaint(); }
The MouseMotionListener
interface defines the next two events—mouseDragged()
and mouseMoved
(). These events are helpful when you just want to know when the mouse is moving over the window (and when it is moving while the button is being held down).
public void mouseDragged(MouseEvent e) { dragx = e.getX(); dragy = e.getY(); repaint(); } public void mouseMoved(MouseEvent e) { movex = e.getX(); movey = e.getY(); repaint(); } }
This chapter explained how to tap into the keyboard and mouse listeners in order to add user input to your Java programs.
You learned how to detect key presses.
You learned about key codes and character values.
You learned how to read the mouse’s motion and buttons.
The following questions will help you to determine how well you have learned the subjects discussed in this chapter. The answers are provided in Appendix A, “Chapter Quiz Answers.”
Use the following exercises to test your grasp of the material covered in this chapter. Are you ready to put mouse and keyboard input to the test in a real game yet? These exercises will challenge your understanding of this chapter.
Modify the KeyboardTest program so that pressing numeric keys 1 to 9 will change the font size used to display the key code and character values. To do this, use the Graphics
class in the paint
event, which has a method called setFont
that you can implement like this:
g.setFont(new Font("Ariel", Font.NORMAL, value));
I will give you a hint: The key code for “1” is 49, so you can subtract 40 from the key code to arrive at a good font size.
Modify the MouseTest program so that a point is drawn whenever the user presses a mouse button. You can use the Graphics
class’ fillRect
method and the mouse position variables. (Just draw a rectangle with four corners that are one pixel apart.) If you are feeling confident with your new Java programming skills, try using the setColor
method to change the color of the points.
3.14.141.115