What operating system are you using? On linux / possibly mac, holding a key down performs several cycles which involve calling both the press and release methods constantly (You know how if you hold a key down in a text box, one character appears, then there's a delay, then several more appear rapidly? In linux, the operating system executes press, then release, really really fast.) In windows, however, the release method is never called until the key is actually released. (basically, it just keeps calling the press method really fast.)
A very ugly and hacky answer, but I hope it helps:
It is helpful to know the timing of these cycles. Typically, it goes something like this:
- User presses and holds a button (say, the 'a' key). The 'a' key's press function is immediately called.
- There is about a quarter to half second delay (often adjustable in system settings).
- 'a' key's release function is called
- Few millisecond delay (between 2 and 10 ms by my testing)
- Press function is called again
- Slightly longer delay (Between 20 and 30 ms by my testing).
- Repeat starting on third bullet point.
With this cycle in mind, it is theoretically possible (actually, completely possible. I've tested it.) to use timing to detect whether or not the user has actually released the key. Basically, if the key is released for more than 10 milliseconds (I'd go 15, just to be safe), then you know that the user has released the key.
This solution involves creating a boolean for each relevant key. Your KeyListeners, in turn, will do nothing more than set these booleans to true / false (maybe when they are pressed, they are set to true, and when they are released, they are set to false.)
Then, you create one more boolean for every key which will represent whether or not the keys are really being pressed. Create a thread which watches the first booleans (the ones controlled by the KeyListeners). Every time the first booleans are set to true, set the corresponding second boolean to true.
However, whenever the first booleans are set to false, wait 15 milliseconds, and check again. If they are still set to false, then set the corresponding second boolean to false. Why? If it's been 15 milliseconds and they are still false, then you know that the user has actually released the key.
KeyListener:
@Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode == 65){
aPressed = true;
}
}
@Override
public void keyReleased(KeyEvent e){
if(e.getKeyCode == 65){
aPressed = false;
}
}
Separate Thread (calling it trueKeyListener
)
boolean waiting = false;
long tWaitStart;
Runnable trueKeyListener = new Runnable(){
@Override
public void run(){
while(true){//Instead of true, use some variable, like running
if(aPressed){
aTruePressed = true;
}else if(!waiting){//not yet waiting for the 15 ms
waiting = true;
tWaitStart = System.nanoTime();
}else if(System.nanoTime() - tWaitStart >= 15000000){//waiting is over
waiting = false;
if(!aPressed){//a still isn't pressed
aTruePressed = false;
}
}
}
}
};
As far as I know, timing the booleans is the only way to make it work on any operating system. As I said, this shouldn't be (or at least wasn't when I last coded something like this) an issue on a Windows OS.
Edit: Finally, as I forgot to mention, you can create one more thread which watches the truePressed
booleans and handles movement accordingly.
Secondly, just some advice, if there are several relevant keys in your application, I recommend using arrays of pressed booleans, truePressed booleans, waiting booleans, and tWaitStart longs for handling multiple keys in one for loop.
Second Edit: I have found this question which seems very similar to yours. I hope it helps.