Skip to content

Commit

Permalink
Rework the events of the Keyboard.
Browse files Browse the repository at this point in the history
- Use explicit functional interfaces instead of java default interfaces.
- Allow to remove listeners.
- Use collections for all listeners.
  • Loading branch information
Steffen Wilke committed Jan 6, 2020
1 parent 1c41e83 commit 537b5d7
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 75 deletions.
98 changes: 73 additions & 25 deletions src/de/gurkenlabs/litiengine/input/IKeyboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,103 @@

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.function.Consumer;
import java.util.EventListener;

import de.gurkenlabs.litiengine.IUpdateable;

public interface IKeyboard extends IUpdateable {
public interface IKeyboard {

public void consumeAlt(boolean consume);

public String getText(KeyEvent e);

public boolean isPressed(int keyCode);

public void onKeyPressed(int keyCode, Consumer<KeyEvent> consumer);
public void onKeyPressed(int keyCode, KeyPressedListener consumer);

public void removeKeyPressedListener(int keyCode, KeyPressedListener listener);

public void onKeyReleased(int keyCode, KeyReleasedListener consumer);

public void removeKeyReleasedListener(int keyCode, KeyReleasedListener listener);

public void onKeyTyped(int keyCode, KeyTypedListener consumer);

public void onKeyReleased(int keyCode, Consumer<KeyEvent> consumer);
public void removeKeyTypedListener(int keyCode, KeyTypedListener listener);

public void onKeyTyped(int keyCode, Consumer<KeyEvent> consumer);
public void onKeyPressed(KeyPressedListener consumer);

public void onKeyPressed(Consumer<KeyEvent> consumer);
public void removeKeyPressedListener(KeyPressedListener listener);

public void onKeyReleased(Consumer<KeyEvent> consumer);
public void onKeyReleased(KeyReleasedListener consumer);

public void onKeyTyped(Consumer<KeyEvent> consumer);
public void removeKeyReleasedListener(KeyReleasedListener listener);

public void onKeyTyped(KeyTypedListener consumer);

public void removeKeyTypedListener(KeyTypedListener listener);

/**
* Removes all registered event consumers from the Keyboard instance. This <b>does not affect</b> registered <code>KeyListener</code> instances.
*
* @see #onKeyPressed(Consumer)
* @see #onKeyPressed(int, Consumer)
* @see #onKeyReleased(Consumer)
* @see #onKeyReleased(int, Consumer)
* @see #onKeyTyped(Consumer)
* @see #onKeyTyped(int, Consumer)
* @see #onKeyPressed(KeyPressedListener)
* @see #onKeyPressed(int, KeyPressedListener)
* @see #onKeyReleased(KeyReleasedListener)
* @see #onKeyReleased(int, KeyReleasedListener)
* @see #onKeyTyped(KeyTypedListener)
* @see #onKeyTyped(int, KeyTypedListener)
*/
public void clearEventConsumers();
public void clearExplicitListeners();

/**
* Register for key events.
*
* @param observer
* the observer
* @param listener
* The listener to add.
*/
public void addKeyListener(KeyListener observer);
public void addKeyListener(KeyListener listener);

/**
* Unregister from key down events.
* Unregister the specified listener from key events.
*
* @param observer
* the observer
* @param listener
* The listener to remove.
*/
public void removeKeyListener(KeyListener observer);
public void removeKeyListener(KeyListener listener);

@FunctionalInterface
public interface KeyPressedListener extends EventListener {
/**
* Invoked when a key has been pressed.
* See the class description for {@link KeyEvent} for a definition of
* a key pressed event.
*
* @param event
* The key event.
*/
void keyPressed(KeyEvent event);
}

@FunctionalInterface
public interface KeyReleasedListener extends EventListener {
/**
* Invoked when a key has been released.
* See the class description for {@link KeyEvent} for a definition of
* a key released event.
*
* @param event
* The key event.
*/
void keyReleased(KeyEvent event);
}

@FunctionalInterface
public interface KeyTypedListener extends EventListener {
/**
* Invoked when a key has been typed.
* See the class description for {@link KeyEvent} for a definition of
* a key typed event.
*
* @param event
* The key event.
*/
void keyTyped(KeyEvent event);
}
}
139 changes: 89 additions & 50 deletions src/de/gurkenlabs/litiengine/input/Keyboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,28 @@

import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;

import de.gurkenlabs.litiengine.Game;
import de.gurkenlabs.litiengine.IUpdateable;

public class Keyboard implements KeyEventDispatcher, IKeyboard {
public class Keyboard implements KeyEventDispatcher, IKeyboard, IUpdateable {
private final Collection<KeyListener> keyListeners = ConcurrentHashMap.newKeySet();
private final Map<Integer, Collection<Consumer<KeyEvent>>> keySpecificPressedConsumer = new ConcurrentHashMap<>();
private final Map<Integer, Collection<Consumer<KeyEvent>>> keySpecificReleasedConsumer = new ConcurrentHashMap<>();
private final Map<Integer, Collection<Consumer<KeyEvent>>> keySpecificTypedConsumer = new ConcurrentHashMap<>();
private final Collection<Consumer<KeyEvent>> keyPressedConsumer = ConcurrentHashMap.newKeySet();
private final Collection<Consumer<KeyEvent>> keyReleasedConsumer = ConcurrentHashMap.newKeySet();
private final Collection<Consumer<KeyEvent>> keyTypedConsumer = ConcurrentHashMap.newKeySet();
private final Map<Integer, Collection<KeyPressedListener>> keySpecificPressedListener = new ConcurrentHashMap<>();
private final Map<Integer, Collection<KeyReleasedListener>> keySpecificReleasedListener = new ConcurrentHashMap<>();
private final Map<Integer, Collection<KeyTypedListener>> keySpecificTypedListener = new ConcurrentHashMap<>();
private final Collection<KeyPressedListener> keyPressedListener = ConcurrentHashMap.newKeySet();
private final Collection<KeyReleasedListener> keyReleasedListener = ConcurrentHashMap.newKeySet();
private final Collection<KeyTypedListener> keyTypedListener = ConcurrentHashMap.newKeySet();

private final List<KeyEvent> pressedKeys = new CopyOnWriteArrayList<>();
private final List<KeyEvent> releasedKeys = new CopyOnWriteArrayList<>();
private final List<KeyEvent> typedKeys = new CopyOnWriteArrayList<>();
private final Collection<KeyEvent> pressedKeys = ConcurrentHashMap.newKeySet();
private final Collection<KeyEvent> releasedKeys = ConcurrentHashMap.newKeySet();
private final Collection<KeyEvent> typedKeys = ConcurrentHashMap.newKeySet();

private boolean consumeAlt;

Expand Down Expand Up @@ -90,45 +87,87 @@ public boolean isPressed(final int keyCode) {
}

@Override
public void onKeyPressed(final int keyCode, final Consumer<KeyEvent> consumer) {
this.keySpecificPressedConsumer.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(consumer);
public void onKeyPressed(final int keyCode, final KeyPressedListener listener) {
this.keySpecificPressedListener.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(listener);
}

@Override
public void onKeyReleased(final int keyCode, final Consumer<KeyEvent> consumer) {
this.keySpecificReleasedConsumer.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(consumer);
public void removeKeyPressedListener(int keyCode, KeyPressedListener listener) {
if (!this.keySpecificPressedListener.containsKey(keyCode)) {
return;
}

this.keySpecificPressedListener.get(keyCode).remove(listener);
}

@Override
public void onKeyTyped(final int keyCode, final Consumer<KeyEvent> consumer) {
this.keySpecificTypedConsumer.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(consumer);
public void onKeyReleased(final int keyCode, final KeyReleasedListener listener) {
this.keySpecificReleasedListener.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(listener);
}

@Override
public void onKeyPressed(Consumer<KeyEvent> consumer) {
this.keyPressedConsumer.add(consumer);
public void removeKeyReleasedListener(int keyCode, KeyReleasedListener listener) {
if (!this.keySpecificReleasedListener.containsKey(keyCode)) {
return;
}

this.keySpecificReleasedListener.get(keyCode).remove(listener);
}

@Override
public void onKeyTyped(final int keyCode, final KeyTypedListener listener) {
this.keySpecificTypedListener.computeIfAbsent(keyCode, ConcurrentHashMap::newKeySet).add(listener);
}

@Override
public void removeKeyTypedListener(int keyCode, KeyTypedListener listener) {
if (!this.keySpecificTypedListener.containsKey(keyCode)) {
return;
}

this.keySpecificTypedListener.get(keyCode).remove(listener);
}

@Override
public void onKeyReleased(Consumer<KeyEvent> consumer) {
this.keyReleasedConsumer.add(consumer);
public void onKeyPressed(KeyPressedListener listener) {
this.keyPressedListener.add(listener);
}

@Override
public void onKeyTyped(Consumer<KeyEvent> consumer) {
this.keyTypedConsumer.add(consumer);
public void removeKeyPressedListener(KeyPressedListener listener) {
this.keyPressedListener.remove(listener);
}

@Override
public void clearEventConsumers() {
this.keyPressedConsumer.clear();
this.keySpecificPressedConsumer.clear();

this.keyReleasedConsumer.clear();
this.keySpecificReleasedConsumer.clear();

this.keyTypedConsumer.clear();
this.keySpecificTypedConsumer.clear();
public void onKeyReleased(KeyReleasedListener listener) {
this.keyReleasedListener.add(listener);
}

@Override
public void removeKeyReleasedListener(KeyReleasedListener listener) {
this.keyReleasedListener.remove(listener);
}

@Override
public void onKeyTyped(KeyTypedListener listener) {
this.keyTypedListener.add(listener);
}

@Override
public void removeKeyTypedListener(KeyTypedListener listener) {
this.keyTypedListener.remove(listener);
}

@Override
public void clearExplicitListeners() {
this.keyPressedListener.clear();
this.keySpecificPressedListener.clear();

this.keyReleasedListener.clear();
this.keySpecificReleasedListener.clear();

this.keyTypedListener.clear();
this.keySpecificTypedListener.clear();
}

@Override
Expand Down Expand Up @@ -200,9 +239,9 @@ private void addTypedKey(final KeyEvent keyCode) {
private void executePressedKeys() {
// called at the rate of the updaterate
this.pressedKeys.forEach(key -> {
this.keySpecificPressedConsumer.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(consumer -> consumer.accept(key));
this.keySpecificPressedListener.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(listener -> listener.keyPressed(key));

this.keyPressedConsumer.forEach(consumer -> consumer.accept(key));
this.keyPressedListener.forEach(listener -> listener.keyPressed(key));
this.keyListeners.forEach(listener -> listener.keyPressed(key));
});
}
Expand All @@ -212,9 +251,9 @@ private void executePressedKeys() {
*/
private void executeReleasedKeys() {
this.releasedKeys.forEach(key -> {
this.keySpecificReleasedConsumer.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(consumer -> consumer.accept(key));
this.keySpecificReleasedListener.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(listener -> listener.keyReleased(key));

this.keyReleasedConsumer.forEach(consumer -> consumer.accept(key));
this.keyReleasedListener.forEach(listener -> listener.keyReleased(key));
this.keyListeners.forEach(listener -> listener.keyReleased(key));
});

Expand All @@ -226,9 +265,9 @@ private void executeReleasedKeys() {
*/
private void executeTypedKeys() {
this.typedKeys.forEach(key -> {
this.keySpecificTypedConsumer.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(consumer -> consumer.accept(key));
this.keySpecificTypedListener.getOrDefault(key.getKeyCode(), Collections.emptySet()).forEach(listener -> listener.keyTyped(key));

this.keyTypedConsumer.forEach(consumer -> consumer.accept(key));
this.keyTypedListener.forEach(listener -> listener.keyTyped(key));
this.keyListeners.forEach(listener -> listener.keyTyped(key));
});

Expand All @@ -251,8 +290,8 @@ private void removePressedKey(final KeyEvent keyCode) {
}

private static String getNormalText(KeyEvent e) {
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
return "ß";
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
return "ß";
}

switch (e.getKeyCode()) {
Expand Down Expand Up @@ -305,28 +344,28 @@ private static String getNormalText(KeyEvent e) {
}

private static String getAltText(KeyEvent e) {
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
return "\\";
}
switch (e.getKeyCode()) {
case KeyEvent.VK_0:
return "}";
case KeyEvent.VK_2:
return "²";
return "²";
case KeyEvent.VK_3:
return "³";
return "³";
case KeyEvent.VK_7:
return "{";
case KeyEvent.VK_8:
return "[";
case KeyEvent.VK_9:
return "]";
case KeyEvent.VK_E:
return "";
return "€";
case KeyEvent.VK_Q:
return "@";
case KeyEvent.VK_M:
return "µ";
return "µ";
case KeyEvent.VK_PLUS:
return "~";
default:
Expand All @@ -335,7 +374,7 @@ private static String getAltText(KeyEvent e) {
}

private static String getShiftText(KeyEvent e) {
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
if (e.getExtendedKeyCode() == KeyEvent.getExtendedKeyCodeForChar('ß')) {
return "?";
}

Expand All @@ -347,7 +386,7 @@ private static String getShiftText(KeyEvent e) {
case KeyEvent.VK_2:
return "\"";
case KeyEvent.VK_3:
return "§";
return "§";
case KeyEvent.VK_4:
return "$";
case KeyEvent.VK_5:
Expand Down

0 comments on commit 537b5d7

Please sign in to comment.