1

I am trying to build an application that does not have to be super performant in general, except for the timestamp of a keyboard press (or external controller button press). I would like the timestamp to be as precise as possible, preferably down to +/- 5ms. This is for a scientific application. What is the best programming paradigm to achieve this with minimal latency? Which of the following is preferable?

(a) Create a worker thread that runs in a higher priority and loops to see if a key was pressed. Use Sleep(x) where x is less than 5.

(b) Create an keyboard hook, which has an asynchronous callback.

(c) Another option.

In addition to an answer, any code (or link to sample) would be much appreciated since I am a reasonably new dev.

EDIT: Nomenclature. Should have been more careful. By timestamp, I mean time in general, not necessarily the full Day Month Year Hour Minute Second Millisecond. I was planning on using the StopWatch class from the beginning, because all I need is the time between the start of an event in the program and the time of the button press. Sorry if this was not clear.

Doug
  • 5,116
  • 10
  • 33
  • 42
  • 3
    Are you looking for a genuine timestamp (a point in time), or just the time *between* key presses? – Jon Skeet Jan 19 '15 at 10:40
  • I am looking for the difference between the start of an event and the key press. I planned to use the stopwatch class. Not sure if that is recommended or not. – Doug Jan 19 '15 at 11:01
  • Covered pretty well already in [this question](http://stackoverflow.com/questions/19284345/wpf-keydown-response-time-accuracy). Very doubtful that Stopwatch is going to do anything for you, if it does then you didn't explain your requirements very well. – Hans Passant Jan 19 '15 at 11:21

4 Answers4

2

From comments:

I am looking for the difference between the start of an event and the key press.

It's important to understand that that's very different to trying to get the actual timestamp of a key press.

This situation is exactly what Stopwatch is for. Yes, use that and be grateful you're not really trying to get a timestamp.

Just use Stopwatch.StartNew when the event starts, and Stopwatch.Stop on the key press event. There's the slight latency of the event handler firing, but that will be tiny compared with anything else - I'd be astonished if it caused you any problems here.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • So you think it would be wise to use an event handler, rather than use a synchronous pattern? – Doug Jan 19 '15 at 13:28
  • @Doug: Yes - I haven't used XNA myself, but I'd expect that to be event based as most UIs are. – Jon Skeet Jan 19 '15 at 13:29
  • @Doug Not sure, but I don't think it's right to say "an event handler, rather than a synchronous pattern". Events are synchronous, unless you go out of your way to make them asynchronous. http://stackoverflow.com/questions/7106454/are-c-sharp-events-synchronous – Dave Cousineau Jan 19 '15 at 15:54
1

If you are looking for exact timestamp of keypress, DateTime mightn't be what you want to use:

Get DateTime.Now with milliseconds precision

DateTime has a lot of precision, but is fairly coarse in terms of accuracy. Generally speaking, you can't. Usually the system clock (which is where DateTime.Now gets its data from) has a resolution of around 10-15ms. See Eric Lippert's blog post about precision and accuracy for more details.

If you need more accurate timing than this, you may want to look into using an NTP client.

And the referenced link from that post:

http://blogs.msdn.com/b/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx

Now, the question “how much time has elapsed from start to finish?” is a completely different question than “what time is it right now?” If the question you want to ask is about how long some operation took, and you want a high-precision, high-accuracy answer, then use the StopWatch class. It really does have nanosecond precision and accuracy that is close to its precision.

Remember, you don’t need to know what time it is to know how much time has elapsed. Those can be two different things entirely.

Community
  • 1
  • 1
user1666620
  • 4,800
  • 18
  • 27
  • I had planned to use stopwatch. Which paradigm is best to work with stopwatch? – Doug Jan 19 '15 at 11:03
  • What do you mean by 'paradigm'? This is a decent basic intro to using the `StopWatch` class : http://www.dotnetperls.com/stopwatch – user1666620 Jan 19 '15 at 11:11
  • I guess I mean the synchronous or asynchronous pattern, (a) or (b), or a third option I'm not thinking of. – Doug Jan 19 '15 at 13:27
0

DateAndTime.Timer is the most exact. It returns a double precision float, which represents number of seconds passed from midnight.

Usage (in VB):

x# = DateAndTime.Timer

'... some code...

msgbox((DateAndTime.Timer - x).ToString + " seconds elapsed")
0

In case you end up using a loop, here's one that outperforms all the others that I've tested ->

<DllImport("user32.dll", EntryPoint:="GetInputState")>
Private Shared Function Chk4AnyKey() As Boolean
End Function

Sub HighPerfKybdRead(maxtime#)

  maxtime += DateAndTime.Timer
  Process.GetCurrentProcess.PriorityBoostEnabled = True
  Process.GetCurrentProcess.PriorityClass = 256

  while DateAndTime.Timer < maxtime

    If Chk4AnyKey() Then
    t# = DateAndTime.Timer
    ' Do further processing of the pressed key
    ' You might wanna call the PeekMessage function here
    ' with the option to ignore the repeated keystrokes
    ' and use the "t#" variable accordingly
    End If

  End While

 
 Process.GetCurrentProcess.PriorityBoostEnabled = False
 Process.GetCurrentProcess.PriorityClass = ProcessPriorityClass.Normal

End Sub

But if you're using an external controller instead of keyboard, then I guess you should be calling GetQueueStatus and not GetInputState...