I need to be able to determine how long a key has been held down with high accuracy. For example if they key tapped really fast it could report a time that is less than the time for each update frame.
-
\$\begingroup\$ Based on your other comments, I have to ask, is getting ~16ms accuracy actually detrimental to your game? Pretty much every game I've ever done has not bothered with input on the sub-frame scale. Maybe there are some other things causing the game to feel bad (which I'm assuming it does, otherwise why are you asking?) \$\endgroup\$– TetradCommented Apr 14, 2011 at 22:50
-
1\$\begingroup\$ You know, Mario games didn't need sub-frame accuracy to pull off the "quick tab for low jump, full press for high jump" thing. Better add an acceleration vector for the first 2-3 frames of the jump. \$\endgroup\$– MauricioCommented Apr 15, 2011 at 3:39
-
2\$\begingroup\$ I've answered a similar question on Stack Overflow \$\endgroup\$– Andrew RussellCommented Apr 17, 2011 at 14:18
-
\$\begingroup\$ @Andrew Russel: that should be the answer. \$\endgroup\$– Michael ColemanCommented Apr 19, 2011 at 18:03
5 Answers
You could capture the input by using the System.Windows.Forms.NativeWindow class. You'll get a notification when an input event occurs. That way you'll be notified as fast as possible right when it occurs, letting you record the time to a higher precision. It gets kind of messy (native/unsafe code), but it works.
I think this only works on windows, but I think that's the platform your targeting (no need for this on Xbox and WP7).
Here is a good example (from nuclex framework): WindowInputCapturer (note: this code might have been updated recently and I didn't code it)
Edit: This also allows you to get at the character code of the key press. This could be useful for taking text input (especially things like latin characters) I'm not sure why you would need to get input at such a high precision, but this would be a good way to do it in my opinion.
XNA is a looped based framework, not an event based framework. If you need the exact time an event occurred, consider a winforms project (an event based project) and connect XNA to a control if necessary for rendering.
Store key state into a variable and compare on the next loop to current key states. Create a DateTime
object to hold the start and you can compare with DateTime.Now
when the previous key state doesn't match.
Very simple example of what I mean:
if(currentKeyboardState.IsKeyDown(Keys.Space)
&& !previousKeyboardState.IsKeyDown(Key.Space))
{ DateTime startTime = DateTime.Now; }
...
if(!currentKeyboardState.IsKeyDown(Keys.Space)
&& previousKeyboardState.IsKeyDown(Key.Space))
{ TimeSpan elapsedTime = DateTime.Now - startTime; }
-
\$\begingroup\$ I specifically asked for something that can give me a time that is less than the time for each update. Your answer will only give me time in increments of 16ms. \$\endgroup\$ Commented Apr 14, 2011 at 22:06
-
1\$\begingroup\$ So run that in it's own thread. XNA doesn't have event handler for keyboard changes. \$\endgroup\$– riv_recCommented Apr 15, 2011 at 3:10
-
\$\begingroup\$ DateTime.Now has worse resolution than the update, though. Try Stopwatch. \$\endgroup\$– MauricioCommented Apr 15, 2011 at 3:36
I'm not aware of any official way of doing this, you could run a second thread in a very tight loop just to check the input and send this of to a circular buffer sufficiently large to require very little synchronization between threads.
(Store some kind of increasing number in each slot of the buffer and update that AFTER the thread wrote all the data, then continue reading slots with data from the buffer until the number decreases (don't forget to check for overflowing numbers!))
If you update thirty times per second, a human will not be able to press keys faster than you can sample the keyboard state. If you update more slowly than a human can type, then you may need one thread for rendering graphics, and another thread for reading and responding to the keyboard / mouse.
But, if you update more slowly than a human can type, then you can't provide visual feedback for each key press either. This doesn't matter if the idea is to display aggregate feedback, such as average time between key presses.
-
\$\begingroup\$ I never said anything about typing. I want to know the time a key has been pressed down, the exact milliseconds. \$\endgroup\$ Commented Apr 14, 2011 at 20:35
-
\$\begingroup\$ And actually a human can type at a rate of more than 30 keys per second but only in a burst of a few keys, not a sustained rate. \$\endgroup\$ Commented Apr 14, 2011 at 20:37
-
\$\begingroup\$ If you update sixty times per second, you get accuracy to 16ms. What accuracy do you require, and why? \$\endgroup\$– bmcnettCommented Apr 14, 2011 at 20:37
-
\$\begingroup\$ For player movement, I want the user to be able to tap once quickly and have the player move less than 1 full press. \$\endgroup\$ Commented Apr 14, 2011 at 20:40
-
\$\begingroup\$ @AttackingHobo Could you not make use of equations of motion for this? While it's held down apply an acceleration vector to a velocity vector? The longer it's held down, the higher the velocity? \$\endgroup\$– Ray DeyCommented Apr 14, 2011 at 21:21