package util.input;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.JComponent;
/**
* KeyboardInput gets input info from keyboard and send appropriate input info to the Input object
* @author Ying Chen, Gavin Ovsak, Aaron Krolik
*/
@SuppressWarnings("unchecked")
public class KeyboardInput extends InputDevice{
public static final String DEVICE = "Keyboard";
private ArrayList<ButtonState> myDownKeys;
private Input myInput;
private long lastClickTime = 0;
private InputDevice inDev = this;
private String lastClickKey = "";
/**
* Constructs the Keyboard Input object with a component to set up listeners
* to and an Input object to send actions to.
* @param component
* @param input
*/
public KeyboardInput(JComponent component, Input input) {
super(DEVICE,input);
myDownKeys = new ArrayList<ButtonState>();
initialize(component);
myInput = input;
}
/**
* A recursive method which goes through all possible combinations of keys pressed down and notified their
* actions. This allows the user to arbitrarily order the combos they desire.
* @param accumulatedKeys
* @param keyArray
* @param maxSize
* @param time
*/
private void recursivePermutation(String accumulatedKeys, ArrayList<ButtonState> keyArray, int maxSize, long time) {
if(maxSize == 0) {
notifyInputAction(DEVICE + "_" + accumulatedKeys + "_Down", new AlertObject(time));
} else {
for(ButtonState key : keyArray) {
ArrayList<ButtonState> modArray = (ArrayList<ButtonState>) keyArray.clone();
modArray.remove(key);
recursivePermutation(key.toString() + accumulatedKeys, modArray, maxSize - 1, time);
}
}
}
/**
* A recursive combination method which goes through subsets of the roughly
* simultaneous key presses in case a subset was being listened for.
* @param keyArray
* @param time
* @param commonKey
*/
private void recursiveCombination(ArrayList<ButtonState> keyArray, long time, ButtonState commonKey) {
//for each thing, take it out and add keyName and permute it
//for each of those things, take each one out and permute it
//smaller sized permuations that all include the latest button
if(keyArray.size() > 1) {
for(int i = 0; i < keyArray.size(); i++) {
ArrayList<ButtonState> modArray = (ArrayList<ButtonState>) keyArray.clone();
modArray.remove(i);
recursiveCombination(modArray, time, commonKey);
modArray.add(commonKey);
recursivePermutation("", modArray, modArray.size(), time);
}
}
}
/**
* Creates the standard keyListener method overrides which process
* the KeyEvents that are passed in from the component.
* @param component
*/
private void initialize(JComponent component) {
component.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
notifyInputAction("Keyboard_Any_Down", new AlertObject(e.getWhen()));
String keyName = KeyboardMappings.getKeyName(e.getKeyCode());
ButtonState downKey = new ButtonState(DEVICE, keyName, e.getWhen(), inDev);
notifyInputAction(downKey.getFullName() + "_KeyDown", new AlertObject(e.getWhen())); //Legacy Support
if (!myDownKeys.contains(downKey)){
if(myDownKeys.size() > 1) {
recursiveCombination(myDownKeys, e.getWhen(), downKey);
}
myDownKeys.add(downKey);
}
else
notifyInputAction(downKey.getFullName() + "_LongPress",new AlertObject(e.getWhen()));
ArrayList<ButtonState> buttonArray = (ArrayList<ButtonState>) myDownKeys.clone();
if(buttonArray.size() > 1)
recursivePermutation("", buttonArray, buttonArray.size(), e.getWhen());
}
@Override
public void keyReleased(KeyEvent e) {
notifyInputAction("Keyboard_Any_Up", new AlertObject(e.getWhen()));
String keyName = KeyboardMappings.getKeyName(e.getKeyCode());
ButtonState temp = new ButtonState(DEVICE, keyName, e.getWhen(), inDev);
int keyIndex;
if( (keyIndex = myDownKeys.indexOf(temp)) != -1 ) {
long timeDifference = temp.getTime() - myDownKeys.remove(keyIndex).getTime();
notifyInputAction(temp.getFullName() + "_Up", new AlertObject(e.getWhen()));
notifyInputAction(temp.getFullName() + "_KeyUp", new AlertObject(e.getWhen())); //Legacy Support
if (timeDifference < Integer.parseInt(myInput.getSetting("ShortClickTimeThreshold")) ) {
notifyInputAction(temp.getFullName() + "_ShortClick",
new AlertObject(e.getWhen()));
}
if (timeDifference >= Integer.parseInt(myInput.getSetting("LongClickTimeThreshold"))) {
notifyInputAction(temp.getFullName() + "_LongClick",
new AlertObject(e.getWhen()));
}
if (lastClickKey.equals(keyName) && e.getWhen() - lastClickTime < Integer.parseInt(myInput.getSetting("DoubleClickTimeThreshold"))) {
notifyInputAction(temp.getFullName() + "_DoubleClick", new AlertObject(e.getWhen()));
}
lastClickTime = e.getWhen();
lastClickKey = keyName;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
});
}
}