Sign in to follow this  
stealthgate

My app processes keyboard input TOO fast...

Recommended Posts

stealthgate    124
My goal is to be able to press a key and have a little sprite appear on the screen. I've been able to get there just fine, however, when I press the key, even for just a second, I can tell the sprite appearing and disappearing (as it should) very very very fast. I'm chocking this up to using immediate data retreival, I'm not sure though. What's another method of getting keyboard input and processing it more slowly without disrupting the framerate (as in, Sleep(), which worked the wrong way :p)? Thanks alot guys.

Share this post


Link to post
Share on other sites
ET3D    810
What effect are you trying to achieve? If I understand correctly, you simply want the sprite to stay longer on the screen. In that case, just start a timer when the key is pressed and keep the sprite on screen until the timer expires.

Share this post


Link to post
Share on other sites
stealthgate    124
Well, basically what happens is that I'm using GetDeviceState() to see what's going on with the keyboard. When a certain key is pressed the sprite appears. When that same key is pressed again, the sprite goes away. However, when I press the key the sprite appears and reappears several times before I lift my finger from the key, rather than me pressing the key, the sprite appearing and staying until I lift my finger and press it again...

Share this post


Link to post
Share on other sites
ET3D    810
Ah, okay. I understand better now.

First of all, you might want to use windows messages instead of DirectInput. Then just use the WM_KEYDOWN/KEYUP messages.

Otherwise implement your own key down/up functionality. That is, only register another key down after the key was up.

Share this post


Link to post
Share on other sites
deadimp    310
Create a buffer for previous variables when you call your input update function.
Then, create keyboard-checking functions with these, well, functions:
Key Press: !prev && current
Key Hold: prev && current
Key Release: prev && !current
And remember to include a function that only checks the current key (and maybe even the previous).

Share this post


Link to post
Share on other sites
EmperiorRune    138
I'm not sure what your using. I'm sorta new to DirectX9, but here is a few tips;
-DirectX 9 uses DirectInput 8, takes a itty bit to get it to work. (There are two different ways that I'm aware of; defining directx8, or the coinitialize way.)

-There is 2 modes for 3 different areas;
foreground: You require focus to the directx app in order to get input.
background: You can get input even when the application is not selected.

exclusive: other handlers cannot take control of the device. (?)
non-exclusive: other handlers can take control of the device.

immeadiate: Events are not logged, creates screenshots of the pressed keys/mouse. Can lose states if not updated fast enough.
buffered mode: Events are logged, ie; key is pressed, key is released, etc. Can overflow if too many keys are pressed between your key update.

-Both versions seem to be updated 12 times a second.. which means you should run the update immeadiate/buffered every ~8.333 milliseconds.

For foreground, non-exclusive
-When you lose control of a device. (Which can happen when someone escapes - you can write reacquire code in the update event. - Additionally you'll want to clear the buffer/key program when you lose access.)

For immeadiate/buffered
-Logging events like a key being pressed can be instantaneous, but.. a release is somewhat more complicated. You can write a boolean that logs a release event, and when that a check is done against that release event, it resets the boolean to false. This is somewhat better than both modes.

Another effect is when you want to act on a change... if you move an object to the right every frame, and your code runs at 100 frames/second.. it will move very very fast. In this case, you can try to query it slower, but most likely.. the idea of caching results, and then querying against it at a time-based "tick" is more effective.

In my version of a DirectX/C++ engine I wrote a scheduler class that uses a global clock, and queues multiple events by id. Basically like at a theatre they have actors looking at a central clock to know when to get on stage.

Similarly.. in my Scheduler class, I write a dynamic array that sets three variables with every event. The delay of a event.. say.. every 10 milliseconds I update the movement of game objects. Then a repeat variable, which for game updates would happen repeatedly. Then finally.. a decrement value.. that is used to safely reach the end of a clock. (it decrements to 0 to determine when a event is "expired")

I hope this gives you some ideas.

Share this post


Link to post
Share on other sites
Shinkage    595
To determine key press/release events you should be using buffered mode rather than immediate polling. When you call GetDeviceState it will ALWAYS return a "key down" state as long as the key is actively being held down. With buffered input mode you get a discrete "key was pressed" message and another "key was released" message. There are some pretty simple tutorials in the DirectX SDK docs for using buffered mode.

Share this post


Link to post
Share on other sites
stealthgate    124
thanks guys...i definitely see the advantages of using buffered input. i'm currently working on being able to press the same button to display and vanish a sprite (like I was saying before).

My idea is that I see if the key '`' was pressed: if it was then I check to see if it was released (data[0].dwOfs != 0), if it is, then the sprite is displayed. however, my trouble is using '`' again, after it is displayed, to make it vanish. Any further suggestions?

Share this post


Link to post
Share on other sites
deadimp    310
If you mean toggling the sprite's visibility when you press that button...
if key pressed '`' //NOT Held down
visible = !visible //Toggle it

Hope that helps.

Share this post


Link to post
Share on other sites
stealthgate    124
thanks alot deadimp - i see what you're saying, but I'm still having trouble. here's what I have going on:


static bool bConsoleOn = false;

if ( KeyboardDataBuffer[0].dwOfs == DIK_GRAVE )
{
if ( KeyboardDataBuffer[0].dwData == 0 ) // key released
{
bConsoleOn = !bConsoleOn;
}
}

if ( bConsoleOn )
// Set flag to on to show sprite
else
// Set flag to off to vanish sprite



what do you think? this doesn't work, the sprite appears and disappears really fast making it appear as a window blind.

thanks guys

Share this post


Link to post
Share on other sites
ChurchSkiz    1101
This is a rude hack that I use in my games, it will suffice until you can find the proper result through buffered input (which i can hopefully figure out soon).

bool RightArrowPressed=false;


mainloop()
{
if( keyup(rightarrow) )
rightarrowpressed=false;

if(keydown(rightarrow) && rightarrowpressed=false)
{
//do something

rightarrowpressed=true;
}

}

repeat with as many variables and statements as necessary. It will not run the if loop again until the game loop has gone one loop with the key up. Like i said this is a hack but it will work until you can figure out a better method.

Share this post


Link to post
Share on other sites
stealthgate    124
thanks alot ChurchSkiz for the method, it works fine for displaying the sprite once, but not for over and over again.

what i'm going for (and what I should have mentioned a loooong time ago) is something that emulates a quake like console in the effect where i press the tilde key the console (sprite) appears and once I press it again it vanishes.

Also, the prog is 100% 2d - sorry for not mentioning that earlier [dead]

thanks again guys for the patience and help!

Share this post


Link to post
Share on other sites
ThrakhathZero    122
I don't really like my solution, but it works.

What I needed for mine was to have a key rotate an tetris block, but as you noted, DiX reads it too many times per frame to be usful. The block in my case would spin super fast and you'd be unable to position it correctly.

What I ended up doing was attaching a 'delay' or 'timer' to each key. The key'd delay variable was decreased every frame till it hit 0. The game would only react to a key if it's delay was at 0 and then after doing it's thing, would reset the delay to whatever amount of time I had picked, thus not reacting to it again for a while.


#define DELAY 100

GameLoop() {

keyXdelay -= timeElapsed //controlled so it never goes below 0

if (KEYDOWN(DIK_X) && keyXdelay == 0){
// do whatever
keyXdelay = DELAY;
}

}



I don't like it because it requires an extra variable for every single key I want to use, and in addition, I've found that for certain keys I want more or less delay on how often it's allowed (for instance, I want 'down' to have less of a delay than the rotation), so it makes tuning much less intuitive. So I'm looking for a better way to do it, might have to try this buffered input thing, but I wonder if it won't (in theory) cause lag on keys during busy times.

Share this post


Link to post
Share on other sites
stealthgate    124
thank you all for your advice and patience, I finally got to where I wanted to - thanks all to you guys.

here's what i worked out:


// Show the Console
if ( KeyboardDataBuffer[0].dwOfs == DIK_GRAVE )
{
if ( KeyboardDataBuffer[0].dwData == 0 && !Console->bConsoleKeyPressed )
{
Console->bDisplayConsole = true;
Console->bConsoleKeyPressed = true;

return;
}

if ( KeyboardDataBuffer[0].dwData == 0 && Console->bConsoleKeyPressed )
{
Console->bDisplayConsole = false;
Console->bConsoleKeyPressed = false;

Console->ClearLine();

return;
}
}



I have a console class object that has two main boolean flags: one that marks whether or not the console is displayed and one which marks whether or not the key has been pressed (they both should always have the same value).

When the key is pressed, two control statements are looked at: the first sees if the key has been released and the console does not report the key having been pressed. In this situation the key was pressed from it NOT being pressed before (something I was missing, thanks again guys!) so then the console should be displayed and the key known as pressed. This function then returns and the master loop that renders the console will see this update. Another big part I was missing is returning...that way the second if will not be tried causing the console to appear and disappear really fast.

The second control statement sees if the key is released and the console IS active (which after the first if it will be). If this is so, the key pressed is false, and the console should no longer be displayed.

by the way both flags are init'ed to false.

Again, thanks guys for all the help -- I'm working on a considerably large project right now and would love to mention you guys for your help.

- stealthgate

Share this post


Link to post
Share on other sites
mc30900    100
guys i didnt read the whole subject but as i can understand, the guy is having probloms with "too much" input.
i made applications before that had the same problom.
first of all i suggest doing veriable for the input
like
keys[256]
when a key is pressed his number turns to true.
when u write what the key does you just add another BOOL
that turns to true.

now make an if so the thing you want to happen will be only if
( (keys[20]) && (!x))

(thats a way of doing this)
the problom is if you are writing a game and then, its really code to do a timer.
i hope i helped you :D

Share this post


Link to post
Share on other sites
Proudest    100
I had the same problem a while back and just use an arraylist which keeps track of which keys have been held down. I have the original GetKey function and the additional GetKeyOnce function.


//[C# + MDX 2.0]
class Keyboard
{
Device deviceKeyboard;
KeyboardState keyState;
ArrayList handled;

public void Update()
{
keyState = deviceKeyboard.CurrentKeyboardState;
}

public bool GetKey(Key key)
{
return keyState[key];
}

public bool GetKeyOnce(Key key)
{
if (keyState[key]) // if key was pressed
{
if (handled.Contains(key)) // if key was handled
{
return false;
}
else // if key wasnt handled
{
handled.Add(key); // handle key
return true;
}
}
else // if key wasn't pressed
{
handled.Remove(key); // unhandle key
return false;
}
}
}



You probably already solved your problem, but I thought it would be useful to someone. I havent tried buffered input yet, that might be a better option.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this