Keyboard Input Problem

Hello,

I'm currently updating a java applet I wrote to work with swing. One problem I've encountered is the ususual key down multiple repetition problem. I wrote this nifty class to fix the problem:

//////////////////////////////////////////////////////////////////////

// Gerbils Revenge Version 1.2

// Copyright 2001 - 2003 David Lloyd

// This code is purely for educational purposes.

// No element of Gerbils Revenge is to be redistributed in any form without prior permission from the author.

// This is a KeyAdapter that solves the problem of keyboards giving multiple key down events. This class will only fire a key event once when a key is pressed. For every key down there will always be a key released too.

import java.awt.event.*;

import java.util.*;

public class UnrepeatedKeyListener extends KeyAdapter

{

ArrayList keyDownList;

KeyListener master;

int i;

// The master is a class that implements KeyListener. When a key event occurs keyPressed() or keyReleased() is called in the master class. This allows the UnrepeatedKeyListener to listen to one class but pass the key events to another.

public UnrepeatedKeyListener(KeyListener newMaster)

{

keyDownList = new ArrayList();

master = newMaster;

}

public synchronized void keyPressed(KeyEvent e)

{

for (i = 0; i < keyDownList.size(); i++)

{

if (((KeyEvent)keyDownList.get(i)).getKeyCode() == e.getKeyCode())

return;

}

keyDownList.add(e);

master.keyPressed(e);

}

public synchronized void keyReleased(KeyEvent e)

{

for (i = 0; i < keyDownList.size(); i++)

{

if (((KeyEvent)keyDownList.get(i)).getKeyCode() == e.getKeyCode())

{

keyDownList.remove(i);

master.keyReleased(e);

return;

}

}

}

}

/////////////////////////////////////////////////////////////////////

The problem is that it can only handle about four keys being pressed at once. If four keys are being held down it will not register a fifth one being pressed. This is a bit of a problem as my game allows for four people to play using the same keyboard. Does anyone know if there's a way to fix this ? Is it a platform specific problem, I'm running under WinXP with java 1.4_1 ?

[2384 byte] By [WaterWolfa] at [2007-9-28 9:03:07]
# 1

what is wrong with the below code, and then simply scan the keys[] each game loop?

Its not like any1 actually does any game logic changes

in a keyPressed/Released event :P (or if you do, your already in trouble :|)

public class KeyStates implements KeyListener

{

final boolean [] keys = new boolean[256];

//(ignoring the obvious fact that more than 256 keys exist)

public void keyPressed(KeyEvent keyevent)

{

keys[keyevent.getKeyCode()] = true;

}

public void keyReleased(KeyEvent keyevent)

{

keys[keyevent.getKeyCode()] = false;

}

public void keyTyped(KeyEvent keyevent) {}

}

p.s. the issue with 4+ keys pressed at once is not an issue with Java or Windows, it is a hardware issue (i.e. a **** keyboard :P)

Abusea at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 2

I've got a question about checking for key input the way abuse posted. It's the way I've been implementing it, but something about it worries me. What's the timing resolution on the key pressed/key released event? Isn't it possible to miss events if you have your game thread checking for events and then sleeping? This is what I've been doing in my first few games, and I've yet to see a problem with it, but maybe that's because my game loop is sleeping for a very short time. Is the solution to have the keypressed event wake up the game loop? There's probably just something I'm missing, or doing stupidly. ;p

-Eric

ericmuntza at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 3

Abuse's code would work if you were polling, but it doesn't call a key listener (interrupt-driven) as is usually done in Java. Not a good or a bad thing, just a fact. If your game is in a polling event loop anyway, then Abuse's method will probably work great, and might simplify your keyboard handling.

It's probably not *technically* threadsafe though... per-thread caching and all that. Technically you're not guaranteed to see new values unless it's a volatile field or you are synchronized. But I don't think synchronizing the array would help, because it's the element you'd need to be volatile and you can't make array elements volatile. And synchonizing would be a little more overhead, but maybe not too much.

cdbennetta at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 4

a valid point.

just as a quick test, I wrote this...

import javax.swing.JFrame;

import java.awt.event.*;

public class TestFrame extends JFrame implements KeyListener

{

HiResTimer hri = new HiResTimer(); //native timer, with resolution of <1ms

public TestFrame()

{

super();

setBounds(0,0,400,300);

addKeyListener(this);

setDefaultCloseOperation(DISPOSE_ON_CLOSE);

show();

}

double start;

public void keyPressed(KeyEvent e)

{

start = hri.getTime();

}

public void keyReleased(KeyEvent e)

{

double end = hri.getTime();

System.out.println(end-start);

}

public void keyTyped(KeyEvent e) {}

public static void main(String [] args)

{

new TestFrame();

}

}

I couldn't press and release the same key in less than 25ms (and that was my absolute best :P)

Abusea at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 5
as to the Thread safe issue....does it realy matter?its a game afterall, and the golden rule for games - 1 Thread only.(unless its a network game, then you may need a few more - depending on how you do your networking...)
Abusea at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 6
oops - ignore that last post.I forgot the KeyEvent is delivered by the Event delivery Thread :D
Abusea at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 7
It is possible to miss keys -- the question is whether or not it matters to your game logic. If you're doing something that requires text entry, you need some kind of event-driven keyboard logic, even if it isn't done AWT-style.
markuskidda at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 8

Thanks for the sample timer. Luckily I have a HiRes timer with the native methods too. :) I suppose the CPU speed (or other hardware piece?) would also have a say in how long the delay between keyPressed/keyReleased events is. I am running on Win2K on a P3 933Mhz and the best I got was 38ms. :p

Now I have this question: if the keyEvent is crucial to my game logic, what's the best way to structure my code so I don't miss an event?

Right now I do something like this:

//

// in logic thread

//

Thread.sleep(sleepTime);

// check key flags, update enviro and render

//

// in keypressed

//

_keyState[code] = true;

//

// in keyReleased

//

_keyState[code] = false;

so I could change Thread.sleep(SLEEP_TIME) to be mutex.wait(SLEEP_TIME) where mutex is just my Object to sleep on. Then have the keypressed call mutex.notify() to wake it up. Of course, I'd have to synchronize on mutex. Is this going to be too expensive?

Also, the way I'm currently handling the sleepTime value is to do something like "sleepTime = DRAW_INTERVAL - actualRenderTime", and I'm not sure how I could keep my frame rate from going haywire if the keyPressed event always caused a new render. I really don't want to have keyPressed directly update the logic and render the frame. I guess I could update the logic from keyPressed, but not render until the next render is supposed to happen?

Ok, I just asked a lot of questions. I'm obviously confused. :p

I hope I'm not asking stupid questions.

-Eric

ericmuntza at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...
# 9
if you absolutely cant afford to miss a key event, the only solution is to queue them (then each game loop, empty the queue, processing each event as you empty it)
Abusea at 2007-7-11 21:53:57 > top of Java-index,Other Topics,Java Game Development...