/*
* Copyright 2006, United States Government as represented by the Administrator
* for the National Aeronautics and Space Administration. No copyright is
* claimed in the United States under Title 17, U.S. Code. All Other Rights
* Reserved.
*/
package gov.nasa.ial.mde.ui;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
/**
* The <code>KeyControls</code> class represents a hot-key functionality.
*
* @author Dr. Robert Shelton
* @author Dan Dexter
* @version 1.0
* @since 1.0
*/
public class KeyControls implements KeyListener {
private static final int DO_NOTHING = 0, DECREMENT = 1, INCREMENT = 2;
private int doWhich = DO_NOTHING;
/** Odd numbered function keys. */
private static final int[] DECREMENT_KEYS = { KeyEvent.VK_F3, KeyEvent.VK_F5, KeyEvent.VK_F7, KeyEvent.VK_F9, KeyEvent.VK_F11 };
/** Even numbered function keys. */
private static final int[] INCREMENT_KEYS = { KeyEvent.VK_F4, KeyEvent.VK_F6, KeyEvent.VK_F8, KeyEvent.VK_F10, KeyEvent.VK_F12 };
private static final int MAX_SLIDES = INCREMENT_KEYS.length;
private int numSlides;
private int numHotKeys;
private String[] hotKeys = new String[0];
private int whichSlide = -1;
private int updateRate = 60; // 60 ms
private int initialPause = 800; // 800 ms
private boolean keyIsPressed = false;
private boolean keyHeldDown = false;
private double[] increment;
private double[] slideIncrement;
private double[] incrementAccelerator;
private double[] value;
private Object lock = new Object();
/**
* Constructs a key control for the specified slider control and hot key
* names.
*
* @param ns number of slides.
* @param hk hot-key names.
*/
public KeyControls(int ns, String[] hk) {
if (ns > MAX_SLIDES) {
throw new IllegalArgumentException("Too many slide controls; Max = " + MAX_SLIDES);
}
increment = new double[numSlides = ns];
value = new double[numSlides];
incrementAccelerator = new double[numSlides];
slideIncrement = new double[numSlides];
for (int i = 0; i < numSlides; i++) {
incrementAccelerator[i] = 0.0;
slideIncrement[i] = 0.0;
increment[i] = 0.0;
value[i] = 0.0;
}
if (hk != null) {
hotKeys = hk;
}
numHotKeys = hotKeys.length;
new Thread(new Runnable() {
public void run() {
boolean initialKeyPress = true;
boolean keyHeldDn = false;
long waitTime = 0;
while (true) {
if (keyIsPressed || keyHeldDown) {
if (keyHeldDown) {
// Set local flag, captures the held state when we want it to.
keyHeldDn = true;
}
if (initialKeyPress) {
initialKeyPress = false;
waitTime = initialPause;
} else {
waitTime = updateRate;
}
} else {
initialKeyPress = true;
waitTime = 0; // wait until a nofity() is called
for (int i = 0; i < numSlides; i++) {
slideIncrement[i] = 0;
}
// Make sure we do the last update when the user releases the key
// if it had been held down for a while. Ignore it if they just
// taped the key.
if (keyHeldDn && (whichSlide >= 0) && (whichSlide < numSlides)) {
keyHeldDn = false; // clear local flag.
onSlider(whichSlide);
}
}
synchronized (lock) {
try {
lock.wait(waitTime);
} catch (InterruptedException ie) { } // end try
}
if ((whichSlide < 0) || (whichSlide >= numSlides)) {
continue;
}
switch (doWhich) {
case INCREMENT :
slideIncrement[whichSlide] = Math.min(increment[whichSlide], slideIncrement[whichSlide] + incrementAccelerator[whichSlide]);
value[whichSlide] = Math.min(1.0, value[whichSlide] + slideIncrement[whichSlide]);
onSlider(whichSlide);
break;
case DECREMENT :
slideIncrement[whichSlide] = Math.min(increment[whichSlide], slideIncrement[whichSlide] + incrementAccelerator[whichSlide]);
value[whichSlide] = Math.max(0.0, value[whichSlide] - slideIncrement[whichSlide]);
onSlider(whichSlide);
break;
default :
for (int i = 0; i < numSlides; i++) {
slideIncrement[i] = 0;
}
break;
} // end switch
} // end while
} // end run
} // end Runnable
).start();
} // end KeyControls
/**
* Called by a slider key event to handle the new slider value.
*
* @param w which slider changed.
*/
public void onSlider(int w) {
// do nothing
} // end onSlider
/**
* Called by a hot-key event to handle the new hot key value.
*
* @param w which hot-key what pressed.
*/
public void onHotKey(int w) {
// do nothing
} // end onHotKey
/**
* Returns the slider value for the specified slider index.
*
* @param w which slider.
* @return the slider value.
*/
public double getValue(int w) {
return value[w];
} // end getValue
/**
* Returns the update rate.
*
* @return the update rate.
*/
public int getUpdatetRate() {
return updateRate;
}
/**
* Sets the update rate in milliseconds.
*
* @param ms the update rate in milliseconds.
*/
public void setUpdateRate(int ms) {
// Don't allow values less than 60 ms
this.updateRate = Math.max(60, ms);
}
/**
* Returns the duration of the initial pause.
*
* @return the duration of the initial pause in milliseconds.
*/
public int getInitialPause() {
return this.initialPause;
}
/**
* Sets the initial pause in milliseconds.
*
* @param ms the initial pause in milliseconds.
*/
public void setInitialPause(int ms) {
// Don't allow values less than 60 ms
this.initialPause = Math.max(60, ms);
}
/**
* Returns the state of a key press.
*
* @return true if a key is held down, false otherwise.
*/
public boolean isKeyHeldDown() {
return keyHeldDown;
}
/**
* Process a focus lost event.
*/
public void processFocusLost() {
doWhich = DO_NOTHING;
keyIsPressed = false;
keyHeldDown = false;
}
/**
* Returns the increment value for the specified slider.
*
* @param w which slider.
* @return the increment value.
*/
public double getIncrement(int w) {
return increment[w];
} // end getIncrement
/**
* Sets the increment for the specified slider.
*
* @param dx increment value.
* @param w which slider.
*/
public void setIncrement(double dx, int w) {
increment[w] = dx;
if (incrementAccelerator[w] == 0.0)
incrementAccelerator[w] = dx;
} // end setIncrement
/**
* Sets the value for the specified slider.
*
* @param v the value.
* @param w which slider
*/
public void setValue(double v, int w) {
value[w] = v;
} // end setValue
/**
* Sets the slider increment accelerator value.
*
* @param fraction the slider increment accelerator value.
* @param w which slider.
*/
public void setIncrementAccelerator(double fraction, int w) {
incrementAccelerator[w] = fraction * increment[w];
} // end setIncrementAccelerator
/**
* Handle the key pressed events for the sliders and hot-keys.
*
* @param ke the key event.
* @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
*/
public void keyPressed(KeyEvent ke) {
int i, k = ke.getKeyCode();
if ((i = whichKey(k, INCREMENT_KEYS)) >= 0) {
doWhich = INCREMENT;
whichSlide = i;
if (keyIsPressed) {
keyHeldDown = true;
} else {
keyIsPressed = true;
synchronized (lock) {
lock.notifyAll();
}
}
return;
} // end if
if ((i = whichKey(k, DECREMENT_KEYS)) >= 0) {
doWhich = DECREMENT;
whichSlide = i;
if (keyIsPressed) {
keyHeldDown = true;
} else {
keyIsPressed = true;
synchronized (lock) {
lock.notifyAll();
}
}
return;
} // end if
} // end keyPressed
/**
* Handle the key released events for the sliders and hot-keys.
*
* @param ke the key event.
* @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
*/
public void keyReleased(KeyEvent ke) {
doWhich = DO_NOTHING;
keyIsPressed = false;
keyHeldDown = false;
synchronized (lock) {
lock.notifyAll();
}
} // end keyReleased
/**
* Handle the key typed events for the sliders and hot-keys.
*
* @param ke the key event.
* @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
*/
public void keyTyped(KeyEvent ke) {
int k = whichHK(ke.getKeyChar());
if (k >= 0) {
onHotKey(k);
}
} // end keyTyped
private int whichKey(int keyCode, int[] keyCodes) {
int i, n = keyCodes.length;
for (i = 0; i < n; i++) {
// System.out.print (" " + keyCodes[i]);
if (keyCode == keyCodes[i])
return i;
} // end for i
return -1;
} // end whichKey
private int whichHK(char c) {
for (int i = 0; i < numHotKeys; i++) {
if (hotKeys[i].indexOf(c) >= 0) {
return i;
}
}
return -1;
} // end whichHK
} // end class KeyControls