[.net] Keyboard/mouse event handlers - must return quickly?

This topic is 3826 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

A while ago I downloaded a demo that renders some terrain and allows you to move an FPS camera around it using the keyboard. The handler for the KeyDown event looked something like this:
void MyApp_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
camera.Walk(0.5f);
// Handle other keys similarly
}


I compiled and ran the demo but the camera movement was extremely choppy. I then decided to change it to this:

// This is a member of MyApp
bool keys[256];

void MyApp_KeyDown(object sender, KeyEventArgs e)
{
keys[(int)e.KeyCode] = true;
}

void MyApp_KeyUp(object sender, KeyEventArgs e)
{
keys[(int)e.KeyCode] = false;
}

// In the Update/Render function:
if (keys[(int)Keys.W])
camera.Walk(0.5f);
// Handle other keys similarly


After this change the movement was completely smooth. My reasoning for doing this was that the handlers are called each time a key is pressed/released and so they must return very quickly so they can be called for the next key press/release. My question is - am I thinking about this correctly? The reason I ask is: 1) The previous code in the handlers really didn't do much, so I would expect it to be executed fast enough for this not to be a problem. 2) I see many people that use the first method (in tutorials, posts, etc.) and none of them are complaining about choppiness. BTW, the demo used C# and MDX but I guess the question is valid for any Windows Forms application, and also for Win32 applications and the window procedure (maybe especially there because that function is called for many other events as well). Any help is greatly appreciated.

Share on other sites
I would personally do it the second way. It's cleaner IMO; keeps the scene updating code out of the keyboard handler code.

Share on other sites
KeyDown events don't get sent every frame (I'm making assumptions about your environment/libraries). Typically KeyDown get sent only when the key is initially pressed and then once every so often depending on the key repeat rate. So the reason the old one is choppy is that the event is only getting sent once in a while (maybe 10 times a second or something, based on the repeat rate). The way you've changed it keeps track of the key's state so you can advance the camera every frame.

Share on other sites
Quote:
 Original post by wendigo23the reason the old one is choppy is that the event is only getting sent once in a while (maybe 10 times a second or something, based on the repeat rate). The way you've changed it keeps track of the key's state so you can advance the camera every frame.

Thanks, that makes sense, though I'm still wondering why it's not a problem for many other people.

Also, I guess this means that using an event-based approach to input in a game is not a good idea because it will not be updated fast enough (though you must still use such an approach when you need to know the exact order of input events, like when typing a name to be entered into a high-scores list)?

Share on other sites
Quote:
 Also, I guess this means that using an event-based approach to input in a game is not a good idea because it will not be updated fast enough (though you must still use such an approach when you need to know the exact order of input events, like when typing a name to be entered into a high-scores list)?

I use the mousedown event and mouseup to tell my system when the mouse is up or down, then in connection, the mousemove event moves my camera when it knows the mouse is down and does it quite well. Never miss a frame and is never choppy for me.

Your code might be faster if it didn't scan an array ever time it renders the loop. Perhaps cash to a bool value or something? I'm speaking of course of:

// In the Update/Render function:if (keys[(int)Keys.W])    camera.Walk(0.5f);// Handle other keys similarly

At least that would be my guess :)

HTH,

-Devin

Share on other sites
Instead of guessing why it's slowing down, measure it. Using Stopwatch.ElapsedMilliseconds should give you an idea of where the slowdown is occurring if it's within camera.Walk. Otherwise I would measure the frequency of MyApp_KeyDown as wendigo23 suggests, and also check if your render loop is rendering when keys are held down.

Share on other sites
mutex,

I wasn't suggesting that a [begin edit] very small [end edit] slowdown was causing the jitter. That speedup idea was just a sugestion. I wasn't really guessing, scanning an array every frame WILL cause some slow down. Do it once and OK, no big deal, but do that too much and soon it can become a problem, thus the reason for the suggestion. Sorry for the confusion.

-Devin

Share on other sites
I use the event style input (bound to delegates rather than hardcoded, so if anything mine should be worse) and don't have any problem really. Though IIRC the auto-repeat does require that sort of 'on key held down' event to be a WalkStart/WalkStop sort of pair to keep it smooth since the auto-repeat only kicks in after enough time has gone past.

Share on other sites
Quote:
 Original post by devroniousI use the mousedown event and mouseup to tell my system when the mouse is up or down, then in connection, the mousemove event moves my camera when it knows the mouse is down and does it quite well. Never miss a frame and is never choppy for me.

Any idea why that is? From what wendigo23 and Telastyn say I would think you should have the same choppiness problem?

Quote:
 Your code might be faster if it didn't scan an array ever time it renders the loop. Perhaps cash to a bool value or something?

What do you mean by "scan an array"? I simply index the array for the keys I want to handle. I highly doubt that that can cause a slowdown (and note that I said that with this code the movement is completely smooth).

Quote:
 Original post by mutexInstead of guessing why it's slowing down, measure it. Using Stopwatch.ElapsedMilliseconds should give you an idea of where the slowdown is occurring if it's within camera.Walk. Otherwise I would measure the frequency of MyApp_KeyDown as wendigo23 suggests, and also check if your render loop is rendering when keys are held down.

I wouldn't call it slowing down. I didn't have a frame-rate display, but I'm guessing that if I did it would always be high. Rather, it seemed like the camera is only being moved on some frames, which causes the choppiness.

Thanks to everyone for their comments so far. I understand it better now but I still wonder why it works for some of you.

Share on other sites
I just did a little experiment. I added two variables to the demo - keyDown and mouseMoving. At the beginning of the main loop, I set them both to false. In the KeyDown handler, I set keyDown to true (but I do not set it to false in the KeyUp handler), and in the MouseMove handler I set mouseMoving to true. Then I print them both every frame.

When I run the program and move the mouse, it always prints "mouseMoving = true", but if I press a key and keep it pressed, the printed value of keyDown sort of switches between true and false (though it's hard to see at what rate), which indeed confirms that it is not called frequently enough (i.e., every frame) to allow for smooth movement.

But then why does the MouseMove handler gets called frequently enough (this also explains why devronious' code is not choppy)? Is it hardware related, i.e., whatever "detects" mouse movement does it better then whatever "detects" that a key is pressed?

1. 1
2. 2
Rutin
19
3. 3
4. 4
5. 5

• 14
• 13
• 9
• 12
• 9
• Forum Statistics

• Total Topics
631437
• Total Posts
3000063
×