Skip to content

Instantly share code, notes, and snippets.

@mcgivrer
Last active April 2, 2021 23:17
Show Gist options
  • Save mcgivrer/34641df0df83c023e9983157b61be8b8 to your computer and use it in GitHub Desktop.
Save mcgivrer/34641df0df83c023e9983157b61be8b8 to your computer and use it in GitHub Desktop.
A Simple InputHandler with action vs. key mapping, mainly for gaming purpose
/**
* The <code>InputHandler</code> is implementing the <code>KeyListener</code> to
* be the keyboard manager. It is mapping some <code>keyEvent</code> code to
* possible <code>ACTIONS</code>.
* <ul>
* <li>the <code>keyMapping</code> are the map containing the mapping between
* some KeyCode to <code>ACTIONS</code> values,</li>
* <li>the internal <code>keys</code> map contains all keys status as boolean
* values,</li>
* <li>the <code>actions</code> contains all Action events produced.</li>
* </ul>
*
* To use this <code>InputHandler</code>, you must implments the
* <code>GameActionListener</code> in your using class and the specific
* <code>action(ACTIONS)</code> method to use the action handling. you can also
* use the <code>getAction(ACTIONS)</code> as an asynchronous access to the
* actions map.
*
*
*
* @author Frédéric Delorme <frederic.delorme@gmail.com>
* @since 2020
*/
public static class InputHandler implements KeyListener {
public interface GameActionListener extends KeyListener {
public void action(ACTIONS action);
}
public enum ACTIONS {
UP, LEFT, RIGHT, DOWN, FIRE1, FIRE2, FIRE3, FIRE4, LT_FIRE, LB_FIRE, RT_FIRE, RB_FIRE, START, HOME, POWER
}
/*
* Internal key current status buffer
*/
private final boolean[] keys = new boolean[65536];
/*
* Internal key previous sttaus buffer
*/
private final boolean[] previousKeys = new boolean[65536];
private List<GameActionListener> listeners = new CopyOnWriteArrayList<>();
private Map<Integer, ACTIONS> keyMapping = new HashMap<>();
private Map<ACTIONS, Boolean> actions = new HashMap<>();
private boolean ctrl;
private boolean shift;
private boolean alt;
private boolean altGr;
DemoGame game;
/**
* Initialization of the InputHandler. Define a default Action mapping with
* basic keys. The map can be adapted or changed.
*
* @param dg
*/
public InputHandler(DemoGame dg) {
this.game = dg;
this.keyMapping.put(KeyEvent.VK_ENTER, ACTIONS.START);
this.keyMapping.put(KeyEvent.VK_HOME, ACTIONS.HOME);
this.keyMapping.put(KeyEvent.VK_SCROLL_LOCK, ACTIONS.POWER);
this.keyMapping.put(KeyEvent.VK_UP, ACTIONS.UP);
this.keyMapping.put(KeyEvent.VK_DOWN, ACTIONS.DOWN);
this.keyMapping.put(KeyEvent.VK_LEFT, ACTIONS.LEFT);
this.keyMapping.put(KeyEvent.VK_RIGHT, ACTIONS.RIGHT);
this.keyMapping.put(KeyEvent.VK_SPACE, ACTIONS.FIRE1);
this.keyMapping.put(KeyEvent.VK_Y, ACTIONS.FIRE2);
this.keyMapping.put(KeyEvent.VK_A, ACTIONS.FIRE3);
this.keyMapping.put(KeyEvent.VK_B, ACTIONS.FIRE4);
this.keyMapping.put(KeyEvent.VK_F1, ACTIONS.LT_FIRE);
this.keyMapping.put(KeyEvent.VK_F2, ACTIONS.LB_FIRE);
this.keyMapping.put(KeyEvent.VK_F3, ACTIONS.RT_FIRE);
this.keyMapping.put(KeyEvent.VK_F4, ACTIONS.RB_FIRE);
}
public void add(GameActionListener kl) {
listeners.add(kl);
}
public void remove(GameActionListener kl) {
listeners.remove(kl);
}
/**
* Define the new KeyMapping to map actions and keys.
*
* @param keyMapping
*/
public void setActionMap(Map<Integer, ACTIONS> keyMapping) {
this.keyMapping = keyMapping;
}
public void keyTyped(final KeyEvent e) {
listeners.forEach(kl -> {
kl.keyTyped(e);
});
}
public void keyPressed(final KeyEvent e) {
// capture current event
this.previousKeys[e.getKeyCode()] = this.keys[e.getKeyCode()];
this.keys[e.getKeyCode()] = true;
// get modifier's key status
this.shift = e.getModifiers() == SHIFT_DOWN_MASK;
this.ctrl = e.getModifiers() == CTRL_DOWN_MASK;
this.alt = e.getModifiers() == ALT_DOWN_MASK;
this.altGr = e.getModifiers() == ALT_GRAPH_DOWN_MASK;
// Convert Key pressed to action
if (keyMapping.containsKey(e.getKeyCode())) {
actions.put(keyMapping.get(e.getKeyCode()), true);
// Delegate action's event to registred listeners
listeners.forEach(kl -> {
kl.action(keyMapping.get(e.getKeyCode()));
});
}
// Delegate key's event to registred listeners
listeners.forEach(kl -> {
kl.keyPressed(e);
});
}
public void keyReleased(final KeyEvent e) {
// capture current event
this.previousKeys[e.getKeyCode()] = this.keys[e.getKeyCode()];
this.keys[e.getKeyCode()] = false;
// get modifier's key status
this.shift = e.getModifiers() == SHIFT_DOWN_MASK;
this.ctrl = e.getModifiers() == CTRL_DOWN_MASK;
this.alt = e.getModifiers() == ALT_DOWN_MASK;
this.altGr = e.getModifiers() == ALT_GRAPH_DOWN_MASK;
// Convert Key released to action
if (keyMapping.containsKey(e.getKeyCode())) {
actions.put(keyMapping.get(e.getKeyCode()), false);
}
// Delegate key's event to registred listeners
listeners.forEach(kl -> {
kl.keyReleased(e);
});
// Special Key for Debug mode capturing changes
if (e.getKeyCode() == KeyEvent.VK_D) {
game.debug = (game.debug > 5 ? 0 : game.debug + 1);
}
}
public boolean get(int key) {
return keys[key];
}
/**
* Return action status
*
* @return boolean value
*/
public boolean getAction(ACTIONS actionCode) {
return this.actions.containsKey(actionCode) ? this.actions.get(actionCode) : false;
}
public boolean getShift() {
return shift;
}
public boolean getCtrl() {
return ctrl;
}
public boolean getAlt() {
return alt;
}
public boolean getAltGr() {
return altGr;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment