Mouse Events and Listener Registration
Input focus decides which component receives keyboard events: exactly one element holds it at a time, and all keyboard events go there.
Why Keyboard Input Needs a Focus Rule
When you click a button with the mouse, the event belongs to the component under the cursor. Keyboard input does not work that way. Pressing a key does not depend on where the pointer is, so a graphical user interface needs a different rule for choosing which component receives the key. That rule is called input focus. This article follows the keyboard side of event handling, because the source material for this topic traces key events in detail, and it uses the same listener registration pattern that mouse events rely on.
As you read, keep one question in mind: when a key is pressed, which component was holding focus at that moment? The key itself matters, but a keystroke only reaches a program through the component that holds focus. Several of the bugs you will meet later come from forgetting this step.
Which Component Gets the Key Press
At any moment, exactly one interface element on the screen holds input focus, and every keyboard event is directed to it. If that element is a Java component, the keystroke becomes a KeyEvent object and is delivered to any listener object that is listening for key events on that component. Several components can be on screen at once, but only one of them receives the keys. Moving focus to another component changes the receiver, and the next key press goes to the new holder.
The diagram shows the rule in its simplest form. The question you should ask about any keyboard bug is not only which key was pressed, but which component held focus when it was pressed. If the listener is attached to a component that does not hold focus, it does not see that key press.
Three Roles: Event, Listener, and Registration
A keyboard event has to pass through three roles before a program can respond to it. The first role is the KeyEvent class, which describes the event itself. The second role is the listener. An object that wants to respond must implement the KeyListener interface, which requires three methods: keyPressed, keyReleased, and keyTyped. The third role is registration. The listener must be attached to the component that will generate the events, using a call written as component.addKeyListener(listener). The component is the one that holds input focus when the keys are pressed. The component and the listener can be the same object.
- The class implements
KeyListener, so it must provide all three methods. addKeyListener(this)performs the registration: the text field is the component, and this object is the listener.- The field must hold input focus for these methods to receive key events from it.
keyPressedchecks the key code against a named constant.keyTypedreads the character that was typed.
Notice where the event parameter appears. Each of the three methods receives a KeyEvent named evt, and the methods differ in what they are expected to read from it. That difference is the subject of the next sections. If you forget the registration call, the methods are never invoked for that component, even though they are written correctly.
How One Key Press Fires Events
For a single key that is pressed and released, the usual order in Java is keyPressed first, then keyTyped, then keyReleased. The key goes down, a character is produced, and the key comes back up. The timeline below shows that order for one press-and-release of a letter.
This one-line sequence hides a point that matters for counting. The keyPressed and keyReleased events belong to physical keys, and the keyTyped event belongs to the character. A single letter press produces one of each only in the simple case. When a key is held down, the key-based events can repeat, which is why one physical action can generate more than one event of the same kind.
keyPressed, keyReleased, and keyTyped Answer Different Questions
The three methods answer three different questions, and choosing the right one depends on what you need to know. keyPressed and keyReleased are tied to physical keys: they tell you that a particular key went down or came up. keyTyped is tied to the character produced, and it may come from several key presses. This is why keyTyped is the right place to ask which character appeared, while keyPressed and keyReleased are the right places to notice that a key such as Shift has changed state.
| Method | Tied to | Answers the question | Example |
|---|---|---|---|
| keyPressed | A physical key | Which key went down? | Shift going down |
| keyReleased | A physical key | Which key came back up? | Shift coming back up |
| keyTyped | The character produced | Which character appeared? | The letter A appearing |
Each KeyListener method answers a different question about the same keystroke.
A useful way to remember the split: a key-based method tells you about hardware-level movement, and the typed method tells you about text. Pressing Shift does not type a character at all, so Shift appears in keyPressed and keyReleased but never in keyTyped.
Finding the Key Code and the Character
Every key has an integer code, and the parameter evt carries the code of the key that was pressed or released. You get it by calling evt.getKeyCode(). You do not need to memorize a table of numbers, because KeyEvent provides a named constant for each key, so a test for the Shift key reads naturally as code == KeyEvent.VK_SHIFT. The arrow keys follow the same pattern with the constants KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP, and KeyEvent.VK_DOWN. The VK prefix stands for Virtual Keyboard. Different keyboards send different raw codes, but Java translates them into its own virtual codes, so the same constants work across keyboards and platforms without modification.
A key code tells you which key moved, but it does not tell you which character appeared on the screen. For that question, use the keyTyped method and call evt.getKeyChar() inside it. The method returns a value of type char representing the character that was typed. Because the value is a char, you can compare it with character literals or store it as a single character.
| Call | Returns | Where it belongs | Typical use |
|---|---|---|---|
| evt.getKeyCode() | An integer key code | keyPressed or keyReleased | Compare with KeyEvent.VK_SHIFT or KeyEvent.VK_LEFT to identify the physical key |
| evt.getKeyChar() | A char value | keyTyped | Read the character that appeared, such as the letter A |
getKeyCode() identifies the key; getKeyChar() identifies the character.
Predicting the Count for an Uppercase A
What do you think happens?
Hold Shift, press A, then release both. How many keyPressed, keyReleased, and keyTyped events does the listener receive?
Reveal answer
Two keyPressed events, two keyReleased events, and one keyTyped event.
Shift and A each go down and come back up, which gives two keyPressed and two keyReleased events. Only the letter A produces a character, so there is one keyTyped event. Shift contributes to the key-based counts but adds nothing to the typed count.
The counts make the three-method split concrete. If your program counted keyTyped events to decide how many keys were touched, it would report one event where two physical keys moved. Counting keyPressed events answers the physical question, and counting keyTyped events answers the character question.
Where a Handler Goes Wrong
Suppose a program is supposed to react when Shift goes down, but the reaction never happens. The diagnosis follows the same two checks every time: which event type arrived, and which value the handler read from it. The worked example below walks through one such case.
public void keyTyped(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_SHIFT) {
System.out.println("Shift pressed");
}
}The Shift check sits in keyTyped, which fires only for produced characters. Pressing Shift never produces a character, so the branch is never taken.
public void keyPressed(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_SHIFT) {
System.out.println("Shift pressed");
}
}The Shift check sits in keyPressed, which fires when the Shift key goes down. The check now receives the event type that carries the key code.
Finding Why a Shift Check Never Runs
A listener is registered with the focused text field. The keyTyped method contains a check for KeyEvent.VK_SHIFT, and the programmer reports that the message never appears when Shift is pressed.
- 1Identify the event type
Shift is a physical key that goes down, so the relevant event is
keyPressed.keyTypedis only delivered when a character is produced, and pressing Shift produces none. - 2Identify the value being read
The check calls
evt.getKeyCode()and compares it toKeyEvent.VK_SHIFT. That is the correct value for identifying a key, so the value is not the problem. - 3Locate the wrong branch
The branch is in
keyTyped. Because Shift never reacheskeyTyped, the if statement is never true for Shift, and the program takes the path that does nothing. - 4Apply the correction
Move the same check into
keyPressed, which receives the Shift key going down. The value read is unchanged, and only the method that receives the event is different.
The bug is in the event type, not the key code. The check that compares getKeyCode() with VK_SHIFT belongs in keyPressed or keyReleased.
Mistakes Beginners Make with Focus and Events
Common mistake Expecting one event per keystroke
What it looks likeHolding Shift, pressing A, and releasing both is expected to produce a single event.
Why it failsEach physical key produces its own
keyPressedandkeyReleasedevents, and the character produceskeyTypedseparately.Do this insteadExpect two keyPressed, two keyReleased, and one keyTyped for that action.
Common mistake Checking Shift inside keyTyped
What it looks likeif (evt.getKeyCode() == KeyEvent.VK_SHIFT) placed in keyTyped.Why it failsShift does not type a character, so
keyTypednever fires for it.Do this insteadPlace the Shift check in keyPressed or keyReleased.
Common mistake Using getKeyChar() to identify a modifier
Why it failsgetKeyChar()returns the character that was typed, which is the wrong question for a key such as Shift.Do this insteadUse getKeyCode() with a named constant such as KeyEvent.VK_SHIFT.
Common mistake Forgetting that focus decides the receiver
What it looks likeA listener is registered with one text field, but the user is typing in another field that holds focus.
Why it failsOnly the component holding focus receives keyboard events, so the listener on the unfocused field sees nothing.
Do this insteadCheck which component holds focus when the key is pressed, and register the listener with that component.
Common mistake Writing the three KeyListener methods but skipping the addKeyListener registration call
Practice: Checking an Arrow Key Handler
A student writes a keyTyped method that checks evt.getKeyCode() == KeyEvent.VK_LEFT to move a shape left. The shape never moves. Identify the event type and value that are wrong, and state which method should hold the check.
Hints
- Ask whether the left arrow key produces a character that
keyTypedwould report. - The value read,
getKeyCode(), is the right kind of value for identifying a key, so focus on the method. keyPressedandkeyReleasedare the methods tied to physical keys going down and coming up.
Key Takeaways
- Input focus gives keyboard events to exactly one component at a time, so the component holding focus at the moment of the key press is the one that matters.
keyPressedandkeyReleasedare tied to physical keys, whilekeyTypedis tied to the character produced and can result from several key presses.evt.getKeyCode()with constants such asKeyEvent.VK_SHIFT identifies keys, andevt.getKeyChar()insidekeyTypedreturns the typed character as a char.- A single physical action can produce several events: an uppercase A typed with Shift yields two
keyPressed, twokeyReleased, and onekeyTyped. - When a handler misbehaves, check the event type that arrived and the value the handler reads; a check for a modifier such as Shift belongs in
keyPressed, notkeyTyped.