Concepts / Mouse Events and Listener Registration

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.

  • Programming

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.

Component Alost focusComponent Bholds focusfocus moves to B
Exactly one component holds focus at a time. When focus moves from one component to another, the next key press is delivered to the new holder instead of the old one.

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.

java
Notes on the code
  • 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.
  • keyPressed checks the key code against a named constant.
  • keyTyped reads 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.

keyPressedkey goes downkeyTypedcharacter producedkeyReleasedkey comes back upthenthen
For one press and release of a letter key, keyPressed fires first, keyTyped fires next to report the character, and keyReleased fires last.

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.

MethodTied toAnswers the questionExample
keyPressedA physical keyWhich key went down?Shift going down
keyReleasedA physical keyWhich key came back up?Shift coming back up
keyTypedThe character producedWhich 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.

CallReturnsWhere it belongsTypical use
evt.getKeyCode()An integer key codekeyPressed or keyReleasedCompare with KeyEvent.VK_SHIFT or KeyEvent.VK_LEFT to identify the physical key
evt.getKeyChar()A char valuekeyTypedRead 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
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.

Before
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.

After
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.

Worked example

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.

  1. 1
    Identify the event type

    Shift is a physical key that goes down, so the relevant event is keyPressed. keyTyped is only delivered when a character is produced, and pressing Shift produces none.

  2. 2
    Identify the value being read

    The check calls evt.getKeyCode() and compares it to KeyEvent.VK_SHIFT. That is the correct value for identifying a key, so the value is not the problem.

  3. 3
    Locate the wrong branch

    The branch is in keyTyped. Because Shift never reaches keyTyped, the if statement is never true for Shift, and the program takes the path that does nothing.

  4. 4
    Apply 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.

Result

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 like

    Holding Shift, pressing A, and releasing both is expected to produce a single event.

    Why it fails

    Each physical key produces its own keyPressed and keyReleased events, and the character produces keyTyped separately.

    Do this instead

    Expect two keyPressed, two keyReleased, and one keyTyped for that action.

  • Common mistake

    Checking Shift inside keyTyped

    What it looks like
    if (evt.getKeyCode() == KeyEvent.VK_SHIFT) placed in keyTyped.
    Why it fails

    Shift does not type a character, so keyTyped never fires for it.

    Do this instead

    Place the Shift check in keyPressed or keyReleased.

  • Common mistake

    Using getKeyChar() to identify a modifier

    Why it fails

    getKeyChar() returns the character that was typed, which is the wrong question for a key such as Shift.

    Do this instead

    Use getKeyCode() with a named constant such as KeyEvent.VK_SHIFT.

  • Common mistake

    Forgetting that focus decides the receiver

    What it looks like

    A listener is registered with one text field, but the user is typing in another field that holds focus.

    Why it fails

    Only the component holding focus receives keyboard events, so the listener on the unfocused field sees nothing.

    Do this instead

    Check 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

EASY

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 keyTyped would report.
  • The value read, getKeyCode(), is the right kind of value for identifying a key, so focus on the method.
  • keyPressed and keyReleased are 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.
  • keyPressed and keyReleased are tied to physical keys, while keyTyped is tied to the character produced and can result from several key presses.
  • evt.getKeyCode() with constants such as KeyEvent.VK_SHIFT identifies keys, and evt.getKeyChar() inside keyTyped returns the typed character as a char.
  • A single physical action can produce several events: an uppercase A typed with Shift yields two keyPressed, two keyReleased, and one keyTyped.
  • 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, not keyTyped.