| 1 | package com.rox.input; | |
| 2 | ||
| 3 | import java.awt.event.KeyAdapter; | |
| 4 | import java.awt.event.KeyEvent; | |
| 5 | import java.util.Map; | |
| 6 | ||
| 7 | /** | |
| 8 | * A {@link Controller} driven by real keyboard input via a configurable AWT keycode→{@link Button} | |
| 9 | * mapping. Register on a video output's key listener (e.g. {@code SwingVideoOutput.addKeyListener}) to | |
| 10 | * receive key events. | |
| 11 | * | |
| 12 | * {@code keyPressed}/{@code keyReleased} run on the EDT, while {@link #isPressed} is polled from the | |
| 13 | * emulation's clock thread - a single {@code volatile int} bitmask is enough to make that safe (the EDT | |
| 14 | * is the sole writer, the clock thread the sole reader, so no read-modify-write race is possible). | |
| 15 | */ | |
| 16 | public class KeyboardController extends KeyAdapter implements Controller { | |
| 17 | private final Map<Integer, Button> keyBindings; | |
| 18 | private volatile int pressedMask; | |
| 19 | ||
| 20 | public KeyboardController(final Map<Integer, Button> keyBindings){ | |
| 21 | this.keyBindings = keyBindings; | |
| 22 | } | |
| 23 | ||
| 24 | @Override | |
| 25 | public void keyPressed(final KeyEvent e){ | |
| 26 | final Button button = keyBindings.get(e.getKeyCode()); | |
| 27 |
1
1. keyPressed : negated conditional → KILLED |
if (button != null){ |
| 28 |
2
1. keyPressed : Replaced bitwise OR with AND → KILLED 2. keyPressed : Replaced Shift Left with Shift Right → KILLED |
pressedMask |= 1 << button.ordinal(); |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | @Override | |
| 33 | public void keyReleased(final KeyEvent e){ | |
| 34 | final Button button = keyBindings.get(e.getKeyCode()); | |
| 35 |
1
1. keyReleased : negated conditional → KILLED |
if (button != null){ |
| 36 |
3
1. keyReleased : Replaced XOR with AND → KILLED 2. keyReleased : Replaced bitwise AND with OR → KILLED 3. keyReleased : Replaced Shift Left with Shift Right → KILLED |
pressedMask &= ~(1 << button.ordinal()); |
| 37 | } | |
| 38 | } | |
| 39 | ||
| 40 | @Override | |
| 41 | public boolean isPressed(final Button button){ | |
| 42 |
4
1. isPressed : Replaced Shift Left with Shift Right → KILLED 2. isPressed : Replaced bitwise AND with OR → KILLED 3. isPressed : negated conditional → KILLED 4. isPressed : replaced boolean return with true for com/rox/input/KeyboardController::isPressed → KILLED |
return (pressedMask & (1 << button.ordinal())) != 0; |
| 43 | } | |
| 44 | } | |
Mutations | ||
| 27 |
1.1 |
|
| 28 |
1.1 2.2 |
|
| 35 |
1.1 |
|
| 36 |
1.1 2.2 3.3 |
|
| 42 |
1.1 2.2 3.3 4.4 |