Today I was trying out JavaFX 2.0 beta which is soon to be released as final. I tried to make a small game where you can fly around a small plane. This is not to hard, you just take the image of a plane taken from the top and make it rotate by listening to key events for left and right and of course a key event to make it go forward.

But when I made a KeyPressedEventHandler I noticed that it would only handle one key at a time. But for a game you need multiple keys handled simultaneously. For instance turning a plane to the left (Key.LEFT) while throttling (Key.UP). When multiple keys are pressed at the same time the KeyPressedEvent is triggered for all keys but only an event for the last pressed key will be triggered continuously. Luckily I found out that the KeyReleasedEvent is always triggered. This gave me the idea to buffer all the pressed keys, and remove each key from the buffer when a release of the given key was done.

The code below creates a new event handler which buffers the pressed keys in a EnumSet.
– A key is added to the set when the KeyPressedEvent is triggered.
– A key is removed from the set when the KeyReleasedEvent is triggered.

import java.util.EnumSet;
import java.util.Set;
import javafx.event.EventHandler;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

/**
 *
 * @author Paul
 */
public class MultiplePressedKeysEventHandler implements EventHandler<KeyEvent> {
    
    private final Set<KeyCode> buffer = EnumSet.noneOf(KeyCode.class);
    private final MultiKeyEvent multiKeyEvent = new MultiKeyEvent();
    
    private final MultiKeyEventHandler multiKeyEventHandler;
    
    public MultiplePressedKeysEventHandler(final MultiKeyEventHandler handler) {
        this.multiKeyEventHandler = handler;
    }
    
    public void handle(final KeyEvent event) {
        final KeyCode code = event.getCode();
       
        if (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
            buffer.add(code);
            multiKeyEventHandler.handle(multiKeyEvent);
        } else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
            buffer.remove(code);
        }
        event.consume();
    }
    
    public interface MultiKeyEventHandler {
        void handle(final MultiKeyEvent event);
    }
    
    public class MultiKeyEvent {
        public boolean isPressed(final KeyCode key) {
            return buffer.contains(key);
        }
    }
}

This is an example how to use the new MultiplePressedKeysEventHandler. Notice that you will have to add this event handler to both the “setOnKeyPressed” and “setOnKeyReleased” method.

The MultiKeyEvent gives you access to a method “isPressed” which you can use to check if the given key is pressed.

 private void initKeyEventHandler() {
        final MultiplePressedKeysEventHandler keyHandler = 
          new MultiplePressedKeysEventHandler(new MultiKeyEventHandler() {

            public void handle(MultiKeyEvent ke) {

                if (ke.isPressed(KeyCode.POWER) || ke.isPressed(KeyCode.X)) {
                    Platform.exit();
                }
                if (ke.isPressed(KeyCode.LEFT)  || ke.isPressed(KeyCode.A)) {
                    rotation -= 2d;
                }
                if (ke.isPressed(KeyCode.RIGHT) || ke.isPressed(KeyCode.D)) {
                    rotation += 2d;
                }

                if (ke.isPressed(KeyCode.UP) || ke.isPressed(KeyCode.W)) {
                    speed += 0.1d;
                }
                if (ke.isPressed(KeyCode.DOWN) || ke.isPressed(KeyCode.S)) {
                    speed -= 0.1d;
                }
            }
        });
        
        imageView.setFocusTraversable(true);
        imageView.setOnKeyPressed(keyHandler);
        imageView.setOnKeyReleased(keyHandler);
    }

This piece of code has some rough edges and can be improved in many ways. I hope it gave you an idea or direction how to solve the given problem.