Skip to content

Commit

Permalink
WIP #12, etc.: duplicate + reserved keys, improve key event handling
Browse files Browse the repository at this point in the history
- Centralize key event dispatch.  The J3D window was stealing focus so
  while mouse events went to it (based on coordinates presumably), key
  events were not.  I made it not focusable and send key events out from
  UserInterfaceFrame (just to itself and to the sliders).
- Disallow overriding reserved keys
- Disallow duplicate key bindings
- Enforce that custom key bindings which override defaults also specify
  a new value for the overriden default key
- Document some of the above (still need reserved key documentation)
  • Loading branch information
jacobmaxfrank committed Jan 13, 2016
1 parent 0262dbc commit 35cd4b4
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 75 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ This is a Java client for [Artemis Space Bridge Simulator](http://artemis.eochu.

More information on specific functionality will be available as development progresses.

## Persistent Custom Presets
TODO: document me!

## Keybindings

### Power vs. Coolant
Expand All @@ -25,10 +28,20 @@ Valid system names are:

Keys must match a `VK_` key constant in [java.awt.KeyEvent](https://docs.oracle.com/javase/8/docs/api/java/awt/event/KeyEvent.html), without the `VK_` prefix. Example of some custom keybindings:

WARP_JUMP_DRIVE 1 F5
WARP_JUMP_DRIVE F6 F5
beams BACK_slash braceright
FORE_Shields H comMA

Keys may not be one of the following reserved (i.e. not re-bindable) keys:
BACK_SLASH (Debugging command)
SPACE (Reset energy and coolant settings)
0-9 (Apply preset)

Keys may conflict with a default binding (see defaults below) only if they also define an input for the system that the default binding belonged to. Setting the same value as a default is okay. For example:

TORPEDOES W A (A is the default for Primary Beam decrease)
BEAMS F1 F2 (Because we've defined a new key for Primary Beam decrease, it's okay)

This hasn't been tested on a keyboard using a character set other than the Western Latin standard.

### Defaults
Expand Down
5 changes: 2 additions & 3 deletions input.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
TORPEDOES F1 2
BeAMS Control ALT
IMPULSE MinUS eqUaLs
TORPEDOES F1 A
BEAMS F4 F5
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.brindyblitz.artemis.engconsole.config;

import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -15,6 +17,22 @@ public class ConfigurationLoader {

private static final String CONFIGURATION_FILE_PATH = new File(System.getProperty("user.dir"), "input.cfg").getPath();
private static final String PRESET_CONFIGURATION_FILE_PATH = new File(System.getProperty("user.dir"), "preset.cfg").getPath();

private static final int[] RESERVED_KEYS = new int[] {
KeyEvent.VK_BACK_SLASH,
KeyEvent.VK_SPACE,
KeyEvent.VK_ENTER,
KeyEvent.VK_0,
KeyEvent.VK_1,
KeyEvent.VK_2,
KeyEvent.VK_3,
KeyEvent.VK_4,
KeyEvent.VK_5,
KeyEvent.VK_6,
KeyEvent.VK_7,
KeyEvent.VK_8,
KeyEvent.VK_9,
};

public Map<ShipSystem, InputMapping> getInputConfiguration() {

Expand All @@ -26,6 +44,23 @@ public Map<ShipSystem, InputMapping> getInputConfiguration() {
if (mappings.containsKey(m.system)) {
throw new RuntimeException("Duplicate key mapping detected for system '" + m.system + "'.");
}

for (int reserved : RESERVED_KEYS) {
if (m.increaseKey == reserved) {
throw new RuntimeException("Key mapping using reserved key (" + m.increaseKeyStr + ") detected for system " + m.system);
} else if (m.decreaseKey == reserved) {
throw new RuntimeException("Key mapping using reserved key (" + m.decreaseKeyStr + ") detected for system " + m.system);
}
}

for (InputMapping existing : mappings.values()) {
if (m.increaseKey == existing.increaseKey || m.increaseKey == existing.decreaseKey) {
throw new RuntimeException("Duplicate key mapping detected (" + m.increaseKeyStr + ")");
} else if (m.decreaseKey == existing.increaseKey || m.decreaseKey == existing.decreaseKey) {
throw new RuntimeException("Duplicate key mapping detected (" + m.decreaseKeyStr + ")");
}
}

mappings.put(m.system, m);
}

Expand Down
111 changes: 71 additions & 40 deletions src/com/brindyblitz/artemis/engconsole/ui/InputManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

import net.dhleong.acl.enums.ShipSystem;

public class InputManager {
public Map<ShipSystem, InputMapping> mappings = new HashMap<ShipSystem, InputMapping>();
public abstract class InputManager {
public static Map<ShipSystem, InputMapping> mappings = new HashMap<ShipSystem, InputMapping>();
public static Map<ShipSystem, InputMapping> defaultMappings = new HashMap<ShipSystem, InputMapping>();

private static final boolean DBG_PRINT_MAPPINGS = false;

public InputManager() {
this.mappings = new ConfigurationLoader().getInputConfiguration();
public static void init() {
mappings = new ConfigurationLoader().getInputConfiguration();

if (DBG_PRINT_MAPPINGS && mappings.size() > 0) {
System.out.println("Custom key bindings loaded:");
Expand All @@ -24,48 +25,78 @@ public InputManager() {
}
}

generateDefaultMappings();
fillEmptyMappingsWithDefaults();
}

private void fillEmptyMappingsWithDefaults() {
private static void generateDefaultMappings() {
for (ShipSystem system : ShipSystem.values()) {
InputMapping mapping = this.mappings.get(system);
if (mapping == null) {
switch (system) {
case BEAMS:
mapping = new InputMapping(system, KeyEvent.VK_Q, KeyEvent.VK_A);
break;

case TORPEDOES:
mapping = new InputMapping(system, KeyEvent.VK_W, KeyEvent.VK_S);
break;

case SENSORS:
mapping = new InputMapping(system, KeyEvent.VK_E, KeyEvent.VK_D);
break;

case MANEUVERING:
mapping = new InputMapping(system, KeyEvent.VK_R, KeyEvent.VK_F);
break;

case IMPULSE:
mapping = new InputMapping(system, KeyEvent.VK_T, KeyEvent.VK_G);
break;

case WARP_JUMP_DRIVE:
mapping = new InputMapping(system, KeyEvent.VK_Y, KeyEvent.VK_H);
break;

case FORE_SHIELDS:
mapping = new InputMapping(system, KeyEvent.VK_U, KeyEvent.VK_J);
break;

case AFT_SHIELDS:
mapping = new InputMapping(system, KeyEvent.VK_I, KeyEvent.VK_K);
break;
InputMapping default_mapping;

switch (system) {
case BEAMS:
default_mapping = new InputMapping(system, KeyEvent.VK_Q, KeyEvent.VK_A);
break;

case TORPEDOES:
default_mapping = new InputMapping(system, KeyEvent.VK_W, KeyEvent.VK_S);
break;

case SENSORS:
default_mapping = new InputMapping(system, KeyEvent.VK_E, KeyEvent.VK_D);
break;

case MANEUVERING:
default_mapping = new InputMapping(system, KeyEvent.VK_R, KeyEvent.VK_F);
break;

case IMPULSE:
default_mapping = new InputMapping(system, KeyEvent.VK_T, KeyEvent.VK_G);
break;

case WARP_JUMP_DRIVE:
default_mapping = new InputMapping(system, KeyEvent.VK_Y, KeyEvent.VK_H);
break;

case FORE_SHIELDS:
default_mapping = new InputMapping(system, KeyEvent.VK_U, KeyEvent.VK_J);
break;

case AFT_SHIELDS:
default_mapping = new InputMapping(system, KeyEvent.VK_I, KeyEvent.VK_K);
break;

default:
throw new RuntimeException("Invalid ship system: " + system + "!");
}

defaultMappings.put(system, default_mapping);
}
}

private static void fillEmptyMappingsWithDefaults() {
for (ShipSystem system : ShipSystem.values()) {
InputMapping custom = mappings.get(system);
InputMapping default_mapping = defaultMappings.get(system);

for (InputMapping existing : mappings.values()) {
if (default_mapping.increaseKey == existing.increaseKey || default_mapping.increaseKey == existing.decreaseKey) {
if (custom != null) {
continue;
}

throw new RuntimeException("Increase key already bound (" + default_mapping.increaseKeyStr + ") for system " + default_mapping.system);
} else if (default_mapping.increaseKey == existing.increaseKey || default_mapping.decreaseKey == existing.decreaseKey) {
if (custom != null) {
continue;
}

throw new RuntimeException("Decrease key already bound (" + default_mapping.decreaseKeyStr + ") for system " + default_mapping.system);
}
}

this.mappings.put(system, mapping);
if (custom == null) {
mappings.put(system, default_mapping);
}
}
}
Expand Down
41 changes: 20 additions & 21 deletions src/com/brindyblitz/artemis/engconsole/ui/SystemSlider.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.List;
Expand All @@ -21,7 +20,7 @@
import net.dhleong.acl.enums.ShipSystem;
import net.dhleong.acl.world.Artemis;

public class SystemSlider extends JPanel implements KeyListener, MouseWheelListener {
public class SystemSlider extends JPanel implements MouseWheelListener {

private static final long serialVersionUID = 1L;
private EngineeringConsoleManager engineeringConsoleManager;
Expand Down Expand Up @@ -173,8 +172,8 @@ private void drawLabel(Graphics2D g) {
g.setColor(Color.WHITE);
g.setFont(LABEL_FONT);
g.drawString(this.label.toUpperCase(),
-SLIDER_BOTTOM + (SLIDER_HEIGHT / 2) - g.getFontMetrics().stringWidth(this.label.toUpperCase()) / 2,
SLIDER_WIDTH - (LABEL_FONT.getSize() - 6));
-SLIDER_BOTTOM + (SLIDER_HEIGHT / 2) - g.getFontMetrics().stringWidth(this.label.toUpperCase()) / 2,
SLIDER_WIDTH - (LABEL_FONT.getSize() - 6));
g.rotate(Math.PI / 2);
}

Expand Down Expand Up @@ -215,28 +214,19 @@ private Color getIntervalColor(IntervalType type) {
throw new RuntimeException("Unexpected Interval Type");
}

@Override
public void keyPressed(KeyEvent e) {
/***
* Only one Swing item seems to be able to receive keys at once probably due to the insane Java focus
* model (see https://docs.oracle.com/javase/7/docs/api/java/awt/doc-files/FocusSpec.html).
*
* As such, the UserInterfaceFrame redirects keys to relevant receivers that would normally implement
* KeyListener.
*/
public void handleKeyPress(KeyEvent e) {
if (e.getKeyCode() == this.inputMapping.increaseKey || e.getKeyCode() == this.inputMapping.decreaseKey) {
handleInput(e.getKeyCode() == this.inputMapping.increaseKey, e.isShiftDown());
}
}

private void handleInput(boolean positive, boolean shift_down) {
if (shift_down) {
this.engineeringConsoleManager.incrementSystemCoolantAllocated(this.system, positive ? COOLANT_INCREMENT : -COOLANT_INCREMENT);
} else {
this.engineeringConsoleManager.incrementSystemEnergyAllocated(this.system, positive ? ENERGY_INCREMENT : -ENERGY_INCREMENT);
}
this.repaint();
}

@Override
public void keyTyped(KeyEvent e) {}

@Override
public void keyReleased(KeyEvent e) {}

@Override
public void mouseWheelMoved(MouseWheelEvent e) {
long t = System.currentTimeMillis();
Expand All @@ -245,4 +235,13 @@ public void mouseWheelMoved(MouseWheelEvent e) {
this.lastScrollTime = t;
}
}

private void handleInput(boolean positive, boolean shift_down) {
if (shift_down) {
this.engineeringConsoleManager.incrementSystemCoolantAllocated(this.system, positive ? COOLANT_INCREMENT : -COOLANT_INCREMENT);
} else {
this.engineeringConsoleManager.incrementSystemEnergyAllocated(this.system, positive ? ENERGY_INCREMENT : -ENERGY_INCREMENT);
}
this.repaint();
}
}
Loading

0 comments on commit 35cd4b4

Please sign in to comment.